/**
* MCP Protocol with Custom Port E2E Test
*
* Tests MCP protocol functionality using a custom port to avoid conflicts.
*/
import { join } from 'path';
import { MCPTestClient, createMCPTestClient } from '../support/mcp-test-client';
import {
validateToolsListResponse,
validatePromptsListResponse,
createHumanDecisionPromptArgs,
MCPErrorCode
} from '../support/protocol-helpers';
describe('MCP Protocol with Custom Port', () => {
let client: MCPTestClient;
const serverPath = join(__dirname, '../../../dist/askme-server/main.js');
const TEST_PORT = 9876; // Use a high port to avoid conflicts
const TEST_TIMEOUT = 20000; // 20 seconds
beforeAll(async () => {
try {
// Create and connect MCP client with custom port
client = await createMCPTestClient(serverPath, TEST_PORT);
console.log(`MCP client connected to server on port ${TEST_PORT}`);
} catch (error) {
console.error('Setup failed:', error);
throw error;
}
}, 30000);
afterAll(async () => {
if (client) {
await client.disconnect();
}
}, 10000);
test('should initialize and connect successfully', async () => {
const processInfo = client.getProcessInfo();
expect(processInfo.connected).toBe(true);
expect(processInfo.pid).toBeDefined();
});
test('should list available tools', async () => {
const response = await client.listTools();
validateToolsListResponse(response);
// Verify expected tools are present
const toolNames = response.tools.map((t: any) => t.name);
expect(toolNames).toContain('ask-one-question');
expect(toolNames).toContain('ask-multiple-choice');
expect(toolNames).toContain('challenge-hypothesis');
expect(toolNames).toContain('choose-next');
});
test('should list available prompts', async () => {
const response = await client.listPrompts();
validatePromptsListResponse(response);
// Verify expected prompts are present
const promptNames = response.prompts.map((p: any) => p.name);
expect(promptNames).toContain('human-decision');
expect(promptNames).toContain('expert-consultation');
expect(promptNames).toContain('creative-brainstorm');
expect(promptNames).toContain('suggest-follow-up-questions');
});
test('should handle invalid JSON-RPC requests', async () => {
try {
await client.request('invalid-method');
fail('Should have thrown an error');
} catch (error: any) {
expect(error.code).toBe(MCPErrorCode.MethodNotFound);
}
});
test('should generate prompts successfully', async () => {
const args = createHumanDecisionPromptArgs(
'Should we deploy to production?',
'1. Deploy now 2. Wait for testing'
);
const response = await client.getPrompt('human-decision', args);
expect(response).toHaveProperty('messages');
expect(Array.isArray(response.messages)).toBe(true);
expect(response.messages.length).toBeGreaterThan(0);
});
test('should handle concurrent requests', async () => {
const promises = [
client.listTools(),
client.listPrompts(),
client.getPrompt('human-decision', createHumanDecisionPromptArgs('Test question'))
];
const responses = await Promise.all(promises);
expect(responses).toHaveLength(3);
expect(responses[0]).toHaveProperty('tools');
expect(responses[1]).toHaveProperty('prompts');
expect(responses[2]).toHaveProperty('messages');
});
test('should validate tool schemas', async () => {
const response = await client.listTools();
response.tools.forEach((tool: any) => {
expect(tool.inputSchema).toHaveProperty('type');
expect(tool.inputSchema).toHaveProperty('properties');
if (tool.name === 'ask-one-question') {
expect(tool.inputSchema.properties).toHaveProperty('question');
expect(tool.inputSchema.required).toContain('question');
}
});
});
});