Skip to content

fix: reject messages that are not JSON-RPC 2.0 with -32600 - #350

Open
mcollina wants to merge 1 commit into
mainfrom
fix/344-require-jsonrpc-2
Open

mcollina wants to merge 1 commit into
mainfrom
fix/344-require-jsonrpc-2

Conversation

@mcollina

Copy link
Copy Markdown
Member

Problem

The legacy POST path dispatched messages that are not JSON-RPC 2.0:

  • {"jsonrpc":"1.0","id":1,"method":"tools/list"}, and the same body without jsonrpc, returned 200 with a tool list;
  • {"jsonrpc":"2.0","id":1,"method":5} returned -32601 "Method 5 not found";
  • the notification {"jsonrpc":"2.0","method":5} returned 202.

JSON-RPC 2.0 requires "jsonrpc": "2.0" and a string method; anything else is an Invalid Request.

Fix

New checkJSONRPCVersion(message) in src/handlers.ts returns a -32600 error with id: null when jsonrpc !== "2.0", or when a method is present and is not a string. It is used:

  • in processMessage, before dispatch (after the existing batch refusal);
  • in the POST /mcp route next to checkRequestId, so the answer is HTTP 400 and no session is opened for the message (for example an initialize without jsonrpc).

Client responses (no method, with result/error) are still accepted, but they must carry "jsonrpc": "2.0" too. The stdio transport sends every message through the same route via inject, so it returns the same error; there is a stdio test for that.

Tests

  • test/legacy-post-bodies.test.ts: the invalid-body table now includes jsonrpc "1.0", missing, or numeric; numeric or null method on requests and notifications; an initialize without jsonrpc; client responses without jsonrpc or with "1.0". All are checked with and without SSE, for 400, -32600, id: null and no Mcp-Session-Id.
  • test/stdio.test.ts: the same cases over stdio, plus a valid request afterwards.

Overlap with open PRs

#323 (fix/318, checkRequestId in src/handlers.ts) and #324 (fix/319, batch handling in processMessage) change the same area. This PR does not depend on either. The diff is a new function next to checkRequestId, two lines in processMessage and one check in the route, so any conflict should be easy to resolve whichever PR merges first.

Fixes #344

🤖 Generated with Claude Code

https://claude.ai/code/session_01LmhsFjk8W96X2PvmShmDm9

The POST handler dispatched messages without "jsonrpc": "2.0" (missing or
"1.0") and requests or notifications whose method was not a string. Add
checkJSONRPCVersion and apply it in processMessage and in the POST route,
before a session is created, answering -32600 with id null and HTTP 400.
Client responses must carry "jsonrpc": "2.0" as well. The stdio transport
goes through the same route and gets the same answer.

Fixes #344

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LmhsFjk8W96X2PvmShmDm9

This branch has not been deployed

No deployments
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.

Legacy POST accepts messages that are not JSON-RPC 2.0

1 participant