initial runner for checking server conformance (#3)
* create some checks * basic initialize working * rename
This commit is contained in:
parent
90ab89ffe1
commit
3b9da98c6a
4 changed files with 267 additions and 23 deletions
84
src/checks/checks.test.ts
Normal file
84
src/checks/checks.test.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import { createClientInitializationCheck } from './client';
|
||||
|
||||
describe('createClientInitializationCheck', () => {
|
||||
it('should return SUCCESS for a valid initialize request', () => {
|
||||
const validRequest = {
|
||||
protocolVersion: '2025-06-18',
|
||||
clientInfo: {
|
||||
name: 'TestClient',
|
||||
version: '1.0.0'
|
||||
}
|
||||
};
|
||||
|
||||
const check = createClientInitializationCheck(validRequest);
|
||||
expect(check.status).toBe('SUCCESS');
|
||||
expect(check.errorMessage).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return FAILURE when protocol version is missing', () => {
|
||||
const invalidRequest = {
|
||||
clientInfo: {
|
||||
name: 'TestClient',
|
||||
version: '1.0.0'
|
||||
}
|
||||
};
|
||||
|
||||
const check = createClientInitializationCheck(invalidRequest);
|
||||
expect(check.status).toBe('FAILURE');
|
||||
expect(check.errorMessage).toContain('Protocol version not provided');
|
||||
});
|
||||
|
||||
it('should return FAILURE when protocol version does not match', () => {
|
||||
const invalidRequest = {
|
||||
protocolVersion: '2024-11-05',
|
||||
clientInfo: {
|
||||
name: 'TestClient',
|
||||
version: '1.0.0'
|
||||
}
|
||||
};
|
||||
|
||||
const check = createClientInitializationCheck(invalidRequest);
|
||||
expect(check.status).toBe('FAILURE');
|
||||
expect(check.errorMessage).toContain('Version mismatch');
|
||||
});
|
||||
|
||||
it('should return FAILURE when client name is missing', () => {
|
||||
const invalidRequest = {
|
||||
protocolVersion: '2025-06-18',
|
||||
clientInfo: {
|
||||
version: '1.0.0'
|
||||
}
|
||||
};
|
||||
|
||||
const check = createClientInitializationCheck(invalidRequest);
|
||||
expect(check.status).toBe('FAILURE');
|
||||
expect(check.errorMessage).toContain('Client name missing');
|
||||
});
|
||||
|
||||
it('should return FAILURE when client version is missing', () => {
|
||||
const invalidRequest = {
|
||||
protocolVersion: '2025-06-18',
|
||||
clientInfo: {
|
||||
name: 'TestClient'
|
||||
}
|
||||
};
|
||||
|
||||
const check = createClientInitializationCheck(invalidRequest);
|
||||
expect(check.status).toBe('FAILURE');
|
||||
expect(check.errorMessage).toContain('Client version missing');
|
||||
});
|
||||
|
||||
it('should support custom expected spec version', () => {
|
||||
const request = {
|
||||
protocolVersion: '2024-11-05',
|
||||
clientInfo: {
|
||||
name: 'TestClient',
|
||||
version: '1.0.0'
|
||||
}
|
||||
};
|
||||
|
||||
const check = createClientInitializationCheck(request, '2024-11-05');
|
||||
expect(check.status).toBe('SUCCESS');
|
||||
expect(check.errorMessage).toBeUndefined();
|
||||
});
|
||||
});
|
||||
47
src/checks/client.ts
Normal file
47
src/checks/client.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { ConformanceCheck, CheckStatus } from '../types.js';
|
||||
|
||||
export function createServerInfoCheck(serverInfo: { name: string; version: string }): ConformanceCheck {
|
||||
return {
|
||||
id: 'server-info',
|
||||
name: 'ServerInfo',
|
||||
description: 'Test server info returned to client',
|
||||
status: 'INFO',
|
||||
timestamp: new Date().toISOString(),
|
||||
specReferences: [{ id: 'MCP-Lifecycle', url: 'https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle' }],
|
||||
details: {
|
||||
serverName: serverInfo.name,
|
||||
serverVersion: serverInfo.version
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function createClientInitializationCheck(initializeRequest: any, expectedSpecVersion: string = '2025-06-18'): ConformanceCheck {
|
||||
const protocolVersionSent = initializeRequest?.protocolVersion;
|
||||
const versionMatch = protocolVersionSent === expectedSpecVersion;
|
||||
|
||||
const errors: string[] = [];
|
||||
if (!protocolVersionSent) errors.push('Protocol version not provided');
|
||||
if (!versionMatch) errors.push(`Version mismatch: expected ${expectedSpecVersion}, got ${protocolVersionSent}`);
|
||||
if (!initializeRequest?.clientInfo?.name) errors.push('Client name missing');
|
||||
if (!initializeRequest?.clientInfo?.version) errors.push('Client version missing');
|
||||
|
||||
const status: CheckStatus = errors.length === 0 ? 'SUCCESS' : 'FAILURE';
|
||||
|
||||
return {
|
||||
id: 'mcp-client-initialization',
|
||||
name: 'MCPClientInitialization',
|
||||
description: 'Validates that MCP client properly initializes with server',
|
||||
status,
|
||||
timestamp: new Date().toISOString(),
|
||||
specReferences: [{ id: 'MCP-Lifecycle', url: 'https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle' }],
|
||||
details: {
|
||||
protocolVersionSent,
|
||||
expectedSpecVersion,
|
||||
versionMatch,
|
||||
clientName: initializeRequest?.clientInfo?.name,
|
||||
clientVersion: initializeRequest?.clientInfo?.version
|
||||
},
|
||||
errorMessage: errors.length > 0 ? errors.join('; ') : undefined,
|
||||
logs: errors.length > 0 ? errors : undefined
|
||||
};
|
||||
}
|
||||
7
src/checks/index.ts
Normal file
7
src/checks/index.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
// Namespaced exports for client and server checks
|
||||
import * as client from './client.js';
|
||||
import * as server from './server.js';
|
||||
|
||||
|
||||
export const clientChecks = client;
|
||||
export const serverChecks = server;
|
||||
36
src/checks/server.ts
Normal file
36
src/checks/server.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { ConformanceCheck, CheckStatus } from '../types.js';
|
||||
|
||||
export function createServerInitializationCheck(initializeResponse: any, expectedSpecVersion: string = '2025-06-18'): ConformanceCheck {
|
||||
const result = initializeResponse?.result;
|
||||
const protocolVersion = result?.protocolVersion;
|
||||
const serverInfo = result?.serverInfo;
|
||||
const capabilities = result?.capabilities;
|
||||
|
||||
const errors: string[] = [];
|
||||
if (!initializeResponse?.jsonrpc) errors.push('Missing jsonrpc field');
|
||||
if (!initializeResponse?.id) errors.push('Missing id field');
|
||||
if (!result) errors.push('Missing result field');
|
||||
if (!protocolVersion) errors.push('Missing protocolVersion in result');
|
||||
if (protocolVersion !== expectedSpecVersion) errors.push(`Protocol version mismatch: expected ${expectedSpecVersion}, got ${protocolVersion}`);
|
||||
if (!serverInfo) errors.push('Missing serverInfo in result');
|
||||
if (!serverInfo?.name) errors.push('Missing server name in serverInfo');
|
||||
if (!serverInfo?.version) errors.push('Missing server version in serverInfo');
|
||||
if (capabilities === undefined) errors.push('Missing capabilities in result');
|
||||
|
||||
const status: CheckStatus = errors.length === 0 ? 'SUCCESS' : 'FAILURE';
|
||||
|
||||
return {
|
||||
id: 'mcp-server-initialization',
|
||||
name: 'MCPServerInitialization',
|
||||
description: 'Validates that MCP server properly responds to initialize request',
|
||||
status,
|
||||
timestamp: new Date().toISOString(),
|
||||
specReferences: [{ id: 'MCP-Lifecycle', url: 'https://modelcontextprotocol.io/specification/2025-06-18/basic/lifecycle' }],
|
||||
details: {
|
||||
expectedSpecVersion,
|
||||
response: initializeResponse
|
||||
},
|
||||
errorMessage: errors.length > 0 ? errors.join('; ') : undefined,
|
||||
logs: errors.length > 0 ? errors : undefined
|
||||
};
|
||||
}
|
||||
Loading…
Reference in a new issue