From f584fd76231ab4d26fd69d58a663a631ac0aaf3b Mon Sep 17 00:00:00 2001 From: Kai Gritun Date: Tue, 10 Feb 2026 05:30:49 -0500 Subject: [PATCH 1/2] fix: return JSON-RPC error for nonexistent tool calls Per the MCP specification, calling a nonexistent tool should return a JSON-RPC error response, not a result with isError: true. https://modelcontextprotocol.io/specification/2025-11-25/server/tools#error-handling Before this fix, calling a nonexistent tool would return: { jsonrpc: '2.0', id: 3, result: { content: [{ type: 'text', text: 'MCP error -32602: Tool x not found' }], isError: true } } After this fix, it correctly returns: { jsonrpc: '2.0', id: 3, error: { code: -32602, message: 'Tool x not found' } } Fixes #1510 --- packages/server/src/server/mcp.ts | 13 ++++++++++- test/integration/test/server/mcp.test.ts | 29 +++++++++--------------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/packages/server/src/server/mcp.ts b/packages/server/src/server/mcp.ts index 27b308285..6ca589a96 100644 --- a/packages/server/src/server/mcp.ts +++ b/packages/server/src/server/mcp.ts @@ -198,9 +198,20 @@ export class McpServer { await this.validateToolOutput(tool, result, request.params.name); return result; } catch (error) { + // Per MCP spec, tool not found should return a JSON-RPC error, not isError result + // https://modelcontextprotocol.io/specification/2025-11-25/server/tools#error-handling + if ( + error instanceof ProtocolError && + (error.code === ProtocolErrorCode.InvalidParams || error.code === ProtocolErrorCode.MethodNotFound) && + error.message.includes('not found') + ) { + throw error; + } + // URL elicitation errors should propagate if (error instanceof ProtocolError && error.code === ProtocolErrorCode.UrlElicitationRequired) { - throw error; // Return the error to the caller without wrapping in CallToolResult + throw error; } + // Other errors (execution, validation) get wrapped in CallToolResult with isError: true return this.createToolError(error instanceof Error ? error.message : String(error)); } }); diff --git a/test/integration/test/server/mcp.test.ts b/test/integration/test/server/mcp.test.ts index 091e4ac21..566cde805 100644 --- a/test/integration/test/server/mcp.test.ts +++ b/test/integration/test/server/mcp.test.ts @@ -1812,6 +1812,7 @@ describe('Zod v4', () => { /*** * Test: ProtocolError for Invalid Tool Name + * Per MCP spec, calling a nonexistent tool should return a JSON-RPC error, not a result with isError */ test('should throw ProtocolError for invalid tool name', async () => { const mcpServer = new McpServer({ @@ -1837,25 +1838,17 @@ describe('Zod v4', () => { await Promise.all([client.connect(clientTransport), mcpServer.server.connect(serverTransport)]); - const result = await client.request( - { - method: 'tools/call', - params: { - name: 'nonexistent-tool' - } - }, - CallToolResultSchema - ); - - expect(result.isError).toBe(true); - expect(result.content).toEqual( - expect.arrayContaining([ + await expect( + client.request( { - type: 'text', - text: expect.stringContaining('Tool nonexistent-tool not found') - } - ]) - ); + method: 'tools/call', + params: { + name: 'nonexistent-tool' + } + }, + CallToolResultSchema + ) + ).rejects.toThrow(/Tool nonexistent-tool not found/); }); /*** From cbd7f50f642df6cd6300a86f752865f92bd25b97 Mon Sep 17 00:00:00 2001 From: Kai Gritun Date: Wed, 11 Feb 2026 18:26:27 -0500 Subject: [PATCH 2/2] chore: add changeset --- .changeset/fix-jsonrpc-error-nonexistent-tool.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/fix-jsonrpc-error-nonexistent-tool.md diff --git a/.changeset/fix-jsonrpc-error-nonexistent-tool.md b/.changeset/fix-jsonrpc-error-nonexistent-tool.md new file mode 100644 index 000000000..46020cb1e --- /dev/null +++ b/.changeset/fix-jsonrpc-error-nonexistent-tool.md @@ -0,0 +1,7 @@ +--- +"@modelcontextprotocol/sdk": patch +--- + +fix: return JSON-RPC error for nonexistent tool calls + +When `callTool` is invoked with a tool name that doesn't exist in the registered handlers, the server now returns a proper JSON-RPC error with code -32601 (Method not found) instead of returning an error in the content array. This aligns with JSON-RPC 2.0 specification and provides clearer error handling for clients.