Skip to content

fix(server): return JSON-RPC errors for missing tools#1674

Open
fahe1em1 wants to merge 2 commits intomodelcontextprotocol:mainfrom
fahe1em1:codex/typescript-sdk-1510-missing-tool-jsonrpc-error
Open

fix(server): return JSON-RPC errors for missing tools#1674
fahe1em1 wants to merge 2 commits intomodelcontextprotocol:mainfrom
fahe1em1:codex/typescript-sdk-1510-missing-tool-jsonrpc-error

Conversation

@fahe1em1
Copy link

Summary

  • keep protocol-level ProtocolErrors as JSON-RPC errors instead of wrapping them into CallToolResult.isError
  • add a focused streamable HTTP test covering an unknown tool call
  • preserve CallToolResult.isError wrapping for ordinary tool execution failures

Root Cause

McpServer already throws a ProtocolError when a tool does not exist, but the catch block in the tools/call handler was catching that protocol error and converting it into a normal tool result with isError: true.

Why This Is Small And Safe

This only changes how existing ProtocolErrors are surfaced. Tool execution errors still follow the existing CallToolResult.isError path, while protocol validation and missing-tool failures now stay aligned with JSON-RPC semantics.

Testing

  • pnpm --filter @modelcontextprotocol/server test -- streamableHttp.test.ts
  • pnpm --filter @modelcontextprotocol/server lint

Closes #1510.

@fahe1em1 fahe1em1 requested a review from a team as a code owner March 12, 2026 21:40
@changeset-bot
Copy link

changeset-bot bot commented Mar 12, 2026

⚠️ No Changeset found

Latest commit: d8f0744

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 12, 2026

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@1674

@modelcontextprotocol/server

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@1674

@modelcontextprotocol/express

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/express@1674

@modelcontextprotocol/hono

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/hono@1674

@modelcontextprotocol/node

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/node@1674

commit: b616fbf

} catch (error) {
if (error instanceof ProtocolError && error.code === ProtocolErrorCode.UrlElicitationRequired) {
throw error; // Return the error to the caller without wrapping in CallToolResult
if (error instanceof ProtocolError) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This broadens the catch from only UrlElicitationRequired to all ProtocolError instances. Before this change, a ProtocolError with any other code (e.g. MethodNotFound thrown by user code inside a tool handler) would have been caught by the outer branch and returned as a CallToolResult with isError: true. Now it becomes a JSON-RPC error response instead.

Is this intentional for all protocol error codes? For example, if a tool implementation internally calls another protocol method that throws a ProtocolError, that would now surface as a JSON-RPC error rather than a tool-level error — which changes what the client sees. The test only covers the tool not found case (-32602), but this catch clause now affects every ProtocolError subtype.

Worth documenting which ProtocolError codes are expected to reach this path, or alternatively using an allowlist (e.g. UrlElicitationRequired, InvalidParams) rather than a blanket catch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Calling a nonexistent tool should trigger a JSON-RPC Error

2 participants