Skip to content

Correlate invalid JSON-RPC envelope errors with the original request id#2857

Open
GauthamPrabhuM wants to merge 1 commit into
modelcontextprotocol:mainfrom
GauthamPrabhuM:feature/gauthamprabhu/correlate-invalid-envelope-request-id
Open

Correlate invalid JSON-RPC envelope errors with the original request id#2857
GauthamPrabhuM wants to merge 1 commit into
modelcontextprotocol:mainfrom
GauthamPrabhuM:feature/gauthamprabhu/correlate-invalid-envelope-request-id

Conversation

@GauthamPrabhuM

Copy link
Copy Markdown

Summary

Fixes #2848.

A JSON-RPC message that is valid JSON but not a valid request object (wrong jsonrpc version, missing jsonrpc, non-string method, etc.) was not answered with an error that a client could correlate back to its request. Per JSON-RPC 2.0, the server should reply with an Invalid Request (-32600) error that echoes the original request id when it is detectable (and null otherwise).

Previously the behavior was inconsistent and uncorrelatable:

  • Streamable HTTP replied 400 with id: null and code -32602 (Invalid params). A client that pipelines requests 1, 2, 3 and trips this on #2 saw a response with a non-matching id and no way to know which request failed.
  • stdio sent no response at all — the validation exception was forwarded into the read stream and silently dropped by the dispatcher, so the original request hung from the client's perspective.

Changes

  • Added mcp.types.jsonrpc.extract_request_id() — best-effort extraction of the id from a raw payload that failed envelope validation, returning None when no valid id is present (bool and fractional values are rejected, since they are not valid RequestId types).
  • Streamable HTTP (server/streamable_http.py): invalid envelopes now reply -32600 with the correlated id instead of -32602/null. _create_error_response gained an optional request_id parameter.
  • stdio (server/stdio.py): an id-bearing line that fails validation now emits a correlated -32600 error response on the write stream. Lines without a detectable id (parse errors, malformed notifications, invalid id types) keep the previous behavior of forwarding the exception without a response.

Testing

  • New parametrized tests on both transports covering all three cases from the issue plus string ids, undetectable ids, and invalid id types (bool, fractional).
  • Updated test_hosting_http.py to assert the new -32600 code for the batched-request case.
  • End-to-end verified against a live stdio subprocess and a live streamable-HTTP server following a full init flow: invalid envelopes return correlated -32600 errors and a follow-up ping still succeeds.
  • Full suite green: ./scripts/test (1788 passed), 100% coverage, ruff, pyright all clean.

Migration / breaking change

The error code returned for an invalid JSON-RPC envelope over both transports changes from -32602 (Invalid params) to -32600 (Invalid Request), and the response id is now populated when detectable. This is a behavioral change to error responses; documented here for reviewers since it may affect clients that string-matched on the prior code.

🤖 Generated with Claude Code

Per JSON-RPC 2.0, a message that is valid JSON but not a valid request
object must be answered with an Invalid Request (-32600) error that
echoes the original request id when it is detectable, so clients can
correlate the failure. Previously:

- Streamable HTTP replied 400 with id null and code -32602
  (Invalid params), breaking client-side request/response correlation.
- stdio sent no response at all; the validation exception was forwarded
  into the read stream and silently dropped by the dispatcher.

Both transports now extract the id from the raw payload (via the new
mcp.types.jsonrpc.extract_request_id helper) and reply with a
correlated -32600 error. On stdio, lines without a detectable id
(parse errors, malformed notifications, ids of an invalid type) keep
the previous behavior of forwarding the exception without a response.

Fixes modelcontextprotocol#2848

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@GauthamPrabhuM GauthamPrabhuM force-pushed the feature/gauthamprabhu/correlate-invalid-envelope-request-id branch from d98117c to e3f1cfd Compare June 13, 2026 03:24
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.

Invalid JSON-RPC envelope errors are not correlated with the original request id

1 participant