* Create a fresh McpServer for each request and process a single JSON-RPC message. * * For non-initialize requests we fast-forward the server through the MCP * initialization handshake (using an internal fake initialize) before dispatching * the real message. This keeps the handler stateless whi
( context: Parameters<typeof createMcpServer>[0], message: JSONRPCMessage, isInitialize = false, )
| 126 | * internal state machine. |
| 127 | */ |
| 128 | async function processRequest( |
| 129 | context: Parameters<typeof createMcpServer>[0], |
| 130 | message: JSONRPCMessage, |
| 131 | isInitialize = false, |
| 132 | ): Promise<JSONRPCMessage> { |
| 133 | if ('method' in message && message.method === 'tools/call' && 'params' in message) { |
| 134 | const { name, arguments: args } = (message.params ?? {}) as { name?: string; arguments?: unknown }; |
| 135 | logger.info( |
| 136 | { |
| 137 | tool: name, |
| 138 | params: args, |
| 139 | organizationId: context.organizationId, |
| 140 | projectId: context.projectId, |
| 141 | clientType: context.clientType, |
| 142 | }, |
| 143 | 'MCP tool call', |
| 144 | ); |
| 145 | } |
| 146 | const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); |
| 147 | const server = createMcpServer(context); |
| 148 | await server.connect(serverTransport); |
| 149 | |
| 150 | if (!isInitialize) { |
| 151 | // Fast-forward: send a fake initialize so the server enters its ready state |
| 152 | await new Promise<void>((resolve, reject) => { |
| 153 | clientTransport.onmessage = () => resolve(); |
| 154 | clientTransport |
| 155 | .send({ |
| 156 | jsonrpc: '2.0', |
| 157 | id: '__mcp_init__', |
| 158 | method: 'initialize', |
| 159 | params: { |
| 160 | protocolVersion: MCP_PROTOCOL_VERSION, |
| 161 | capabilities: {}, |
| 162 | clientInfo: { name: 'mcp-proxy', version: '0' }, |
| 163 | }, |
| 164 | }) |
| 165 | .catch(reject); |
| 166 | }); |
| 167 | // Notify the server that initialization is complete (no response expected) |
| 168 | await clientTransport.send({ |
| 169 | jsonrpc: '2.0', |
| 170 | method: 'notifications/initialized', |
| 171 | }); |
| 172 | } |
| 173 | |
| 174 | const start = Date.now(); |
| 175 | const response = await new Promise<JSONRPCMessage>((resolve, reject) => { |
| 176 | clientTransport.onmessage = resolve; |
| 177 | clientTransport.send(message).catch(reject); |
| 178 | }); |
| 179 | |
| 180 | if ('method' in message && message.method === 'tools/call') { |
| 181 | const { name } = (('params' in message && message.params) ?? {}) as { name?: string }; |
| 182 | const isError = 'result' in response && (response.result as { isError?: boolean })?.isError; |
| 183 | logger.info( |
| 184 | { |
| 185 | tool: name, |
no test coverage detected