/**
* MCP Server Integration Tests
* Complete end-to-end testing of MCP server functionality
*/
import 'reflect-metadata';
import { Container } from 'inversify';
import { MCPServer, MCPServerConfig, MCPRequest } from '@/server/mcp-server';
import { createConfiguredContainer } from '@/core/container';
import { TYPES } from '@/core/types';
import { Logger } from '@/core/logger';
describe('MCP Server Integration Tests', () => {
let container: Container;
let server: MCPServer;
let config: MCPServerConfig;
beforeAll(async () => {
// Create a test configuration
config = {
name: 'test-mcp-server',
version: '1.0.0-test',
capabilities: {
tools: true,
resources: true,
prompts: false,
logging: true
},
server: {
protocol: 'stdio'
},
providers: {
enabled: ['deepseek', 'openai'],
default: 'deepseek'
},
features: {
collaboration: true,
caching: true,
metrics: true,
search: true,
synthesis: true
}
};
// Set up dependency injection container
container = createConfiguredContainer({
logLevel: 'info',
cacheType: 'memory',
metricsEnabled: true
});
// Bind configuration
container.bind<MCPServerConfig>('MCPServerConfig').toConstantValue(config);
// Create server instance
server = container.get<MCPServer>(MCPServer);
});
afterAll(async () => {
if (server) {
await server.stop();
}
});
describe('Server Lifecycle', () => {
it('should start and stop server successfully', async () => {
// Start server
await expect(server.start()).resolves.not.toThrow();
// Verify server is running
const serverInfo = server.getServerInfo();
expect(serverInfo.name).toBe(config.name);
expect(serverInfo.version).toBe(config.version);
// Stop server
await expect(server.stop()).resolves.not.toThrow();
});
it('should handle multiple start/stop cycles', async () => {
await server.start();
await server.stop();
await server.start();
await server.stop();
});
});
describe('JSON-RPC Protocol', () => {
beforeEach(async () => {
await server.start();
});
afterEach(async () => {
await server.stop();
});
it('should handle initialize request', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 1,
method: 'initialize',
params: {
protocolVersion: '2024-11-05',
capabilities: {
tools: { listChanged: true }
},
clientInfo: {
name: 'test-client',
version: '1.0.0'
}
}
};
const response = await server.handleRequest(request);
expect(response.jsonrpc).toBe('2.0');
expect(response.id).toBe(1);
expect(response.result).toEqual(
expect.objectContaining({
protocolVersion: '2024-11-05',
capabilities: expect.any(Object),
serverInfo: expect.objectContaining({
name: config.name,
version: config.version
})
})
);
});
it('should handle tools/list request', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 2,
method: 'tools/list'
};
const response = await server.handleRequest(request);
expect(response.result).toEqual({
tools: expect.arrayContaining([
expect.objectContaining({
name: expect.stringMatching(/^(collaborate|review|compare|refine)$/),
description: expect.any(String),
inputSchema: expect.objectContaining({
type: 'object',
properties: expect.any(Object)
})
})
])
});
});
it('should handle resources/list request', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 3,
method: 'resources/list'
};
const response = await server.handleRequest(request);
expect(response.result).toEqual({
resources: expect.arrayContaining([
expect.objectContaining({
uri: expect.stringMatching(/^(collaboration|metrics|search):\/\//),
name: expect.any(String)
})
])
});
});
it('should handle ping request', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 4,
method: 'ping'
};
const response = await server.handleRequest(request);
expect(response.result).toEqual({
status: 'ok',
timestamp: expect.any(Number)
});
});
});
describe('Tool Execution', () => {
beforeEach(async () => {
await server.start();
});
afterEach(async () => {
await server.stop();
});
it('should execute collaborate tool', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 5,
method: 'tools/call',
params: {
name: 'collaborate',
arguments: {
request: {
prompt: 'Write a simple hello world function',
model: 'default',
temperature: 0.7
},
strategy: 'parallel',
providers: ['deepseek'],
strategy_config: {
timeout: 10000
}
}
}
};
const response = await server.handleRequest(request);
expect(response.result).toEqual({
result: expect.objectContaining({
success: expect.any(Boolean),
collaboration_id: expect.any(String),
strategy_used: 'parallel',
providers_used: expect.arrayContaining(['deepseek'])
})
});
});
it('should execute review tool', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 6,
method: 'tools/call',
params: {
name: 'review',
arguments: {
content: 'def hello(): print("Hello, World!")',
review_type: 'code_review',
criteria: ['correctness', 'style', 'performance'],
provider: 'deepseek'
}
}
};
const response = await server.handleRequest(request);
expect(response.result).toEqual({
result: expect.objectContaining({
success: expect.any(Boolean),
review_id: expect.any(String),
review_type: 'code_review'
})
);
});
it('should handle tool execution errors gracefully', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 7,
method: 'tools/call',
params: {
name: 'invalid-tool',
arguments: {}
}
};
const response = await server.handleRequest(request);
expect(response.error).toEqual({
code: -32603,
message: expect.stringContaining('Unknown tool')
});
});
});
describe('Resource Access', () => {
beforeEach(async () => {
await server.start();
});
afterEach(async () => {
await server.stop();
});
it('should read collaboration history resource', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 8,
method: 'resources/read',
params: {
uri: 'collaboration://history'
}
};
const response = await server.handleRequest(request);
expect(response.result).toEqual({
content: expect.objectContaining({
results: expect.any(Array),
total: expect.any(Number)
})
});
});
it('should read metrics resource', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 9,
method: 'resources/read',
params: {
uri: 'metrics://performance'
}
};
const response = await server.handleRequest(request);
expect(response.result).toEqual({
content: expect.any(Object)
});
});
it('should read search index resource', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 10,
method: 'resources/read',
params: {
uri: 'search://index'
}
};
const response = await server.handleRequest(request);
expect(response.result).toEqual({
content: expect.objectContaining({
total_documents: expect.any(Number),
index_size: expect.any(Number),
last_updated: expect.any(String)
})
});
});
});
describe('Custom Handlers', () => {
beforeEach(async () => {
await server.start();
});
afterEach(async () => {
await server.stop();
});
it('should handle collaboration/execute request', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 11,
method: 'collaboration/execute',
params: {
strategy: 'parallel',
providers: ['deepseek'],
request: {
prompt: 'Test collaboration request',
model: 'default'
}
}
};
const response = await server.handleRequest(request);
expect(response.result).toEqual(
expect.objectContaining({
strategy: 'parallel',
success: expect.any(Boolean)
})
);
});
it('should handle synthesis/create request', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 12,
method: 'synthesis/create',
params: {
responses: [
{
content: 'Response 1',
provider: 'deepseek',
model: 'deepseek-chat',
usage: { prompt_tokens: 10, completion_tokens: 20, total_tokens: 30 },
timestamp: new Date(),
metadata: {}
},
{
content: 'Response 2',
provider: 'openai',
model: 'gpt-4',
usage: { prompt_tokens: 12, completion_tokens: 22, total_tokens: 34 },
timestamp: new Date(),
metadata: {}
}
],
synthesis_method: 'consensus'
}
};
const response = await server.handleRequest(request);
expect(response.result).toEqual(
expect.objectContaining({
success: expect.any(Boolean),
synthesis_id: expect.any(String)
})
);
});
it('should handle search/query request', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 13,
method: 'search/query',
params: {
query: 'test search query',
filters: {
provider: 'deepseek'
},
limit: 10
}
};
const response = await server.handleRequest(request);
expect(response.result).toEqual(
expect.objectContaining({
results: expect.any(Array),
total: expect.any(Number)
})
);
});
it('should handle metrics/get request', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 14,
method: 'metrics/get'
};
const response = await server.handleRequest(request);
expect(response.result).toEqual(expect.any(Object));
});
});
describe('Error Handling', () => {
beforeEach(async () => {
await server.start();
});
afterEach(async () => {
await server.stop();
});
it('should handle malformed JSON-RPC requests', async () => {
const invalidRequest = {
id: 15,
method: 'test'
// Missing jsonrpc field
} as MCPRequest;
const response = await server.handleRequest(invalidRequest);
expect(response.error).toEqual({
code: -32603,
message: 'Invalid JSON-RPC version'
});
});
it('should handle unknown methods', async () => {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 16,
method: 'unknown/method',
params: {}
};
const response = await server.handleRequest(request);
expect(response.error).toEqual({
code: -32603,
message: 'Unknown method: unknown/method'
});
});
it('should handle requests without method', async () => {
const invalidRequest = {
jsonrpc: '2.0',
id: 17
} as MCPRequest;
const response = await server.handleRequest(invalidRequest);
expect(response.error).toEqual({
code: -32603,
message: 'Missing method'
});
});
});
describe('Performance and Scalability', () => {
beforeEach(async () => {
await server.start();
});
afterEach(async () => {
await server.stop();
});
it('should handle concurrent requests', async () => {
const requests: Promise<any>[] = [];
for (let i = 0; i < 10; i++) {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 100 + i,
method: 'ping'
};
requests.push(server.handleRequest(request));
}
const responses = await Promise.all(requests);
expect(responses).toHaveLength(10);
responses.forEach((response, index) => {
expect(response.id).toBe(100 + index);
expect(response.result).toEqual({
status: 'ok',
timestamp: expect.any(Number)
});
});
});
it('should handle rapid sequential requests', async () => {
const responses = [];
for (let i = 0; i < 20; i++) {
const request: MCPRequest = {
jsonrpc: '2.0',
id: 200 + i,
method: 'ping'
};
const response = await server.handleRequest(request);
responses.push(response);
}
expect(responses).toHaveLength(20);
responses.forEach((response, index) => {
expect(response.id).toBe(200 + index);
expect(response.result.status).toBe('ok');
});
});
});
describe('Metrics Collection', () => {
beforeEach(async () => {
await server.start();
});
afterEach(async () => {
await server.stop();
});
it('should collect request metrics', async () => {
// Make several requests
for (let i = 0; i < 5; i++) {
await server.handleRequest({
jsonrpc: '2.0',
id: i,
method: 'ping'
});
}
// Get metrics
const metricsRequest: MCPRequest = {
jsonrpc: '2.0',
id: 999,
method: 'metrics/get'
};
const response = await server.handleRequest(metricsRequest);
// Verify metrics were collected (implementation dependent)
expect(response.result).toBeDefined();
});
});
describe('Logging Integration', () => {
it('should integrate with logging system', async () => {
const logger = container.get<Logger>(TYPES.Logger);
const logSpy = jest.spyOn(logger, 'info');
await server.start();
expect(logSpy).toHaveBeenCalledWith(
'MCP Server started successfully',
expect.any(Object)
);
await server.stop();
logSpy.mockRestore();
});
});
});