|
4 | 4 | InMemoryTransport, |
5 | 5 | isJSONRPCResultResponse, |
6 | 6 | LATEST_PROTOCOL_VERSION, |
| 7 | + ProtocolErrorCode, |
7 | 8 | SUPPORTED_PROTOCOL_VERSIONS |
8 | 9 | } from '@modelcontextprotocol/core'; |
9 | 10 | import { Server } from '../../src/server/server.js'; |
@@ -84,6 +85,73 @@ describe('Server', () => { |
84 | 85 |
|
85 | 86 | await server.close(); |
86 | 87 | }); |
| 88 | + |
| 89 | + it('rejects requests before initialize', async () => { |
| 90 | + const server = new Server({ name: 'test', version: '1.0.0' }, { capabilities: { tools: {} } }); |
| 91 | + |
| 92 | + server.setRequestHandler('tools/list', async () => ({ tools: [] })); |
| 93 | + |
| 94 | + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); |
| 95 | + await server.connect(serverTransport); |
| 96 | + |
| 97 | + const responses: JSONRPCMessage[] = []; |
| 98 | + clientTransport.onmessage = message => responses.push(message); |
| 99 | + await clientTransport.start(); |
| 100 | + |
| 101 | + await clientTransport.send({ |
| 102 | + jsonrpc: '2.0', |
| 103 | + method: 'notifications/initialized' |
| 104 | + } as JSONRPCMessage); |
| 105 | + |
| 106 | + await clientTransport.send({ |
| 107 | + jsonrpc: '2.0', |
| 108 | + id: 1, |
| 109 | + method: 'tools/list', |
| 110 | + params: {} |
| 111 | + } as JSONRPCMessage); |
| 112 | + |
| 113 | + await vi.waitFor(() => expect(responses.some(message => 'id' in message && message.id === 1)).toBe(true)); |
| 114 | + |
| 115 | + const rejected = responses.find(message => 'id' in message && message.id === 1); |
| 116 | + expect(rejected).toMatchObject({ |
| 117 | + error: { |
| 118 | + code: ProtocolErrorCode.InvalidRequest, |
| 119 | + message: 'Server not initialized' |
| 120 | + } |
| 121 | + }); |
| 122 | + |
| 123 | + await clientTransport.send({ |
| 124 | + jsonrpc: '2.0', |
| 125 | + id: 2, |
| 126 | + method: 'initialize', |
| 127 | + params: { |
| 128 | + protocolVersion: LATEST_PROTOCOL_VERSION, |
| 129 | + capabilities: {}, |
| 130 | + clientInfo: { name: 'test-client', version: '1.0.0' } |
| 131 | + } |
| 132 | + } as JSONRPCMessage); |
| 133 | + await vi.waitFor(() => expect(responses.some(message => 'id' in message && message.id === 2)).toBe(true)); |
| 134 | + |
| 135 | + await clientTransport.send({ |
| 136 | + jsonrpc: '2.0', |
| 137 | + method: 'notifications/initialized' |
| 138 | + } as JSONRPCMessage); |
| 139 | + |
| 140 | + await clientTransport.send({ |
| 141 | + jsonrpc: '2.0', |
| 142 | + id: 3, |
| 143 | + method: 'tools/list', |
| 144 | + params: {} |
| 145 | + } as JSONRPCMessage); |
| 146 | + |
| 147 | + await vi.waitFor(() => expect(responses.some(message => 'id' in message && message.id === 3)).toBe(true)); |
| 148 | + |
| 149 | + expect(responses.find(message => 'id' in message && message.id === 3)).toMatchObject({ |
| 150 | + result: { tools: [] } |
| 151 | + }); |
| 152 | + |
| 153 | + await server.close(); |
| 154 | + }); |
87 | 155 | }); |
88 | 156 |
|
89 | 157 | describe('getNegotiatedProtocolVersion', () => { |
|
0 commit comments