129 lines
3.6 KiB
JavaScript
129 lines
3.6 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('node:assert/strict');
|
|
const test = require('node:test');
|
|
const {
|
|
MCP_PROTOCOL_VERSION,
|
|
McpServer,
|
|
SUPPORTED_PROTOCOL_VERSIONS,
|
|
} = require('../lib/server');
|
|
|
|
function createServer(toolRegistry = {}) {
|
|
return new McpServer({
|
|
config: { host: '127.0.0.1', port: 8765 },
|
|
toolRegistry: {
|
|
listTools: () => [],
|
|
callTool: async () => 'ok',
|
|
...toolRegistry,
|
|
},
|
|
resourceProvider: {
|
|
listResources: () => [],
|
|
listResourceTemplates: () => [],
|
|
readResource: async () => ({ contents: [] }),
|
|
},
|
|
promptProvider: {
|
|
listPrompts: () => [],
|
|
getPrompt: () => ({ messages: [] }),
|
|
},
|
|
interactionLog: { add() {} },
|
|
serverName: 'test-server',
|
|
serverVersion: '0.0.0-test',
|
|
});
|
|
}
|
|
|
|
test('initialize negotiates the current MCP protocol version by default', async () => {
|
|
const server = createServer();
|
|
const response = await server.handleRpcRequest({
|
|
jsonrpc: '2.0',
|
|
id: 1,
|
|
method: 'initialize',
|
|
params: {},
|
|
});
|
|
|
|
assert.equal(response.result.protocolVersion, MCP_PROTOCOL_VERSION);
|
|
assert.equal(response.result.serverInfo.name, 'test-server');
|
|
});
|
|
|
|
test('initialize can negotiate an older supported MCP protocol version', async () => {
|
|
const server = createServer();
|
|
const olderVersion = SUPPORTED_PROTOCOL_VERSIONS[SUPPORTED_PROTOCOL_VERSIONS.length - 1];
|
|
const response = await server.handleRpcRequest({
|
|
jsonrpc: '2.0',
|
|
id: 1,
|
|
method: 'initialize',
|
|
params: { protocolVersion: olderVersion },
|
|
});
|
|
|
|
assert.equal(response.result.protocolVersion, olderVersion);
|
|
});
|
|
|
|
test('tool execution failures are returned as MCP tool errors', async () => {
|
|
const server = createServer({
|
|
callTool: async () => {
|
|
throw new Error('bad arguments');
|
|
},
|
|
});
|
|
|
|
const response = await server.handleRpcRequest({
|
|
jsonrpc: '2.0',
|
|
id: 2,
|
|
method: 'tools/call',
|
|
params: { name: 'example', arguments: {} },
|
|
});
|
|
|
|
assert.equal(response.error, undefined);
|
|
assert.equal(response.result.isError, true);
|
|
assert.deepEqual(response.result.content, [{ type: 'text', text: 'bad arguments' }]);
|
|
});
|
|
|
|
test('tool object results include structuredContent', async () => {
|
|
const value = { ok: true, count: 2 };
|
|
const server = createServer({
|
|
callToolDetailed: async () => ({
|
|
value,
|
|
text: JSON.stringify(value, null, 2),
|
|
}),
|
|
});
|
|
|
|
const response = await server.handleRpcRequest({
|
|
jsonrpc: '2.0',
|
|
id: 4,
|
|
method: 'tools/call',
|
|
params: { name: 'example', arguments: {} },
|
|
});
|
|
|
|
assert.deepEqual(response.result.structuredContent, value);
|
|
assert.equal(response.result.content[0].type, 'text');
|
|
});
|
|
|
|
test('structuredContent sanitizes circular values', async () => {
|
|
const value = { ok: true };
|
|
value.self = value;
|
|
const server = createServer({
|
|
callToolDetailed: async () => ({
|
|
value,
|
|
text: '{ "ok": true, "self": "[Circular]" }',
|
|
}),
|
|
});
|
|
|
|
const response = await server.handleRpcRequest({
|
|
jsonrpc: '2.0',
|
|
id: 5,
|
|
method: 'tools/call',
|
|
params: { name: 'example', arguments: {} },
|
|
});
|
|
|
|
assert.deepEqual(response.result.structuredContent, { ok: true, self: '[Circular]' });
|
|
});
|
|
|
|
test('unsupported protocol version headers are rejected when present after initialize', () => {
|
|
const server = createServer();
|
|
const response = server.validateProtocolVersionHeader(
|
|
{ headers: { 'mcp-protocol-version': '1999-01-01' } },
|
|
{ jsonrpc: '2.0', id: 3, method: 'tools/list' }
|
|
);
|
|
|
|
assert.equal(response.error.code, -32600);
|
|
assert.match(response.error.message, /Unsupported MCP protocol version/);
|
|
});
|