mcp-server-tester-sse-http-stdio
Version:
MCP Server Tester with SSE support - Test MCP servers using HTTP, SSE, and STDIO transports
268 lines (267 loc) • 12.8 kB
JavaScript
/**
* SDK-Based JSON-RPC Compliance Tests
* Leverages MCP SDK error detection instead of manual validation
*/
import { DiagnosticTest } from '../DiagnosticTest.js';
import { SdkErrorDetector } from '../SdkErrorDetector.js';
import { TEST_SEVERITY, ISSUE_TYPE, } from '../types.js';
import { ErrorCode } from '@modelcontextprotocol/sdk/types.js';
class SdkJsonRpcComplianceTest extends DiagnosticTest {
name = 'SDK: JSON-RPC Protocol Compliance';
description = 'Uses SDK error detection to validate JSON-RPC compliance';
category = 'base-protocol';
feature = 'json-rpc';
severity = TEST_SEVERITY.CRITICAL;
mcpSpecSection = 'Base Protocol - JSON-RPC 2.0';
async execute(client, config) {
const sdkTests = [
{
name: 'JSON-RPC Message Format',
description: 'Validate basic message format through SDK',
category: 'base-protocol',
feature: 'json-rpc',
severity: TEST_SEVERITY.CRITICAL,
operation: async (client) => await client.sdk.listTools(),
expectsError: false,
},
{
name: 'JSON-RPC Request Processing',
description: 'Test request processing through SDK',
category: 'base-protocol',
feature: 'json-rpc',
severity: TEST_SEVERITY.CRITICAL,
operation: async (client) => {
// Test multiple operations to ensure consistent processing
const [tools, resources, prompts] = await Promise.all([
client.sdk.listTools(),
client.sdk.listResources(),
client.sdk.listPrompts(),
]);
return { tools, resources, prompts };
},
expectsError: false,
},
];
try {
const sdkResults = await SdkErrorDetector.executeTests(client, config, sdkTests);
const diagnosticResults = SdkErrorDetector.convertTodiagnosticResults(sdkResults);
const failedTests = diagnosticResults.filter(r => r.status === 'failed');
const passedTests = diagnosticResults.filter(r => r.status === 'passed');
if (failedTests.length === 0) {
return this.createResult(true, `SDK JSON-RPC compliance validated (${passedTests.length} checks passed)`, {
passedTests: passedTests.length,
details: diagnosticResults,
});
}
else {
return this.createEnhancedResult({
success: false,
message: `SDK detected ${failedTests.length} JSON-RPC compliance issues`,
details: {
failedTests: failedTests.length,
passedTests: passedTests.length,
results: diagnosticResults,
},
issueType: failedTests[0].issueType || ISSUE_TYPE.CRITICAL_FAILURE,
expected: 'Full JSON-RPC 2.0 compliance through SDK validation',
actual: `${failedTests.length} compliance issues detected by SDK`,
fixInstructions: failedTests.flatMap(t => t.recommendations || []),
specLinks: [
'https://spec.modelcontextprotocol.io/specification/basic/json-rpc/',
'https://www.jsonrpc.org/specification',
],
});
}
}
catch (error) {
return this.createResult(false, 'SDK JSON-RPC compliance test failed', { error: error instanceof Error ? error.message : String(error) }, [
'Check SDK integration and client setup',
'Verify server is properly responding to SDK requests',
'Review connection and transport configuration',
]);
}
}
}
class SdkErrorResponseTest extends DiagnosticTest {
name = 'SDK: Error Response Validation';
description = 'Uses SDK to validate JSON-RPC error response handling';
category = 'base-protocol';
feature = 'json-rpc';
severity = TEST_SEVERITY.WARNING;
mcpSpecSection = 'Base Protocol - Error Handling';
async execute(client, config) {
const errorTests = [
{
name: 'Method Not Found Error (-32601)',
description: 'Test SDK handling of method not found errors',
category: 'base-protocol',
feature: 'json-rpc',
severity: TEST_SEVERITY.WARNING,
operation: async (client) => {
await client.sdk.callTool({
name: 'non_existent_method_12345',
arguments: {},
});
},
expectsError: true,
expectedErrorCode: ErrorCode.MethodNotFound,
},
{
name: 'Invalid Parameters Error (-32602)',
description: 'Test SDK handling of invalid parameter errors',
category: 'base-protocol',
feature: 'json-rpc',
severity: TEST_SEVERITY.WARNING,
operation: async (client) => {
// First get a valid tool to test invalid parameters
const tools = await client.sdk.listTools();
if (tools.tools && tools.tools.length > 0) {
const toolName = tools.tools[0].name;
await client.sdk.callTool({
name: toolName,
arguments: {
__definitely_invalid_param: 'test',
__another_bad_param: null,
},
});
}
else {
// If no tools, just test the non-existent tool case
await client.sdk.callTool({
name: 'invalid_tool',
arguments: { bad: 'params' },
});
}
},
expectsError: true,
expectedErrorCode: ErrorCode.InvalidParams,
},
];
try {
const sdkResults = await SdkErrorDetector.executeTests(client, config, errorTests);
const diagnosticResults = SdkErrorDetector.convertTodiagnosticResults(sdkResults);
const failedTests = diagnosticResults.filter(r => r.status === 'failed');
const passedTests = diagnosticResults.filter(r => r.status === 'passed');
if (failedTests.length === 0) {
return this.createResult(true, `SDK error response validation passed (${passedTests.length} error types tested)`, {
passedTests: passedTests.length,
details: diagnosticResults,
});
}
else {
return this.createEnhancedResult({
success: false,
message: `SDK detected ${failedTests.length} error response issues`,
details: {
failedTests: failedTests.length,
passedTests: passedTests.length,
results: diagnosticResults,
},
issueType: failedTests[0].issueType || ISSUE_TYPE.SPEC_WARNING,
expected: 'Proper JSON-RPC error codes and format through SDK',
actual: `${failedTests.length} error handling issues detected by SDK`,
fixInstructions: failedTests.flatMap(t => t.recommendations || []),
specLinks: [
'https://spec.modelcontextprotocol.io/specification/basic/json-rpc/',
'https://www.jsonrpc.org/specification#error_object',
],
});
}
}
catch (error) {
return this.createResult(false, 'SDK error response test failed', { error: error instanceof Error ? error.message : String(error) }, [
'Check that server properly handles error conditions',
'Verify error response formatting',
'Review SDK error handling implementation',
]);
}
}
}
class SdkConnectionReliabilityTest extends DiagnosticTest {
name = 'SDK: Connection Reliability';
description = 'Uses SDK to test connection management and reliability';
category = 'lifecycle';
feature = 'connection';
severity = TEST_SEVERITY.CRITICAL;
mcpSpecSection = 'Lifecycle - Connection Management';
async execute(client, config) {
const connectionTests = [
{
name: 'Basic Connectivity',
description: 'Test basic SDK connectivity',
category: 'lifecycle',
feature: 'connection',
severity: TEST_SEVERITY.CRITICAL,
operation: async (client) => {
// Test that basic operations work through SDK
const result = await client.sdk.listTools();
return { connected: true, toolCount: result.tools?.length || 0 };
},
expectsError: false,
},
{
name: 'Concurrent Requests',
description: 'Test SDK handling of concurrent requests',
category: 'lifecycle',
feature: 'connection',
severity: TEST_SEVERITY.WARNING,
operation: async (client) => {
// Test concurrent operations through SDK
const startTime = Date.now();
const results = await Promise.allSettled([
client.sdk.listTools(),
client.sdk.listResources(),
client.sdk.listPrompts(),
client.sdk.listTools(), // Duplicate to test concurrency
]);
const duration = Date.now() - startTime;
const successful = results.filter(r => r.status === 'fulfilled').length;
return {
duration,
successful,
total: results.length,
concurrentOpsSupported: successful >= 2,
};
},
expectsError: false,
},
];
try {
const sdkResults = await SdkErrorDetector.executeTests(client, config, connectionTests);
const diagnosticResults = SdkErrorDetector.convertTodiagnosticResults(sdkResults);
const failedTests = diagnosticResults.filter(r => r.status === 'failed');
const passedTests = diagnosticResults.filter(r => r.status === 'passed');
if (failedTests.length === 0) {
return this.createResult(true, `SDK connection reliability validated (${passedTests.length} checks passed)`, {
passedTests: passedTests.length,
details: diagnosticResults,
});
}
else {
return this.createEnhancedResult({
success: false,
message: `SDK detected ${failedTests.length} connection reliability issues`,
details: {
failedTests: failedTests.length,
passedTests: passedTests.length,
results: diagnosticResults,
},
issueType: failedTests[0].issueType || ISSUE_TYPE.CRITICAL_FAILURE,
expected: 'Reliable connection management through SDK',
actual: `${failedTests.length} connection issues detected by SDK`,
fixInstructions: failedTests.flatMap(t => t.recommendations || []),
specLinks: ['https://spec.modelcontextprotocol.io/specification/basic/transports/'],
});
}
}
catch (error) {
return this.createResult(false, 'SDK connection reliability test failed', { error: error instanceof Error ? error.message : String(error) }, [
'Check server connection handling',
'Verify transport configuration',
'Review SDK connection management',
]);
}
}
}
// Export test classes for registration
export { SdkJsonRpcComplianceTest, SdkErrorResponseTest, SdkConnectionReliabilityTest };