A null id
Legal JSON-RPC 2.0 and forbidden by MCP, so a generic validator passes it
{"jsonrpc": "2.0", "id": null, "error": {"code": -32700, "message": "Parse error"}} Paste one MCP JSON-RPC message and get told what it is, whether it is well-formed, and which of the MCP-specific rules it breaks. A null id and a batch array are both valid JSON-RPC and both rejected here, because MCP rejects them.
Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.
The answer appears here
Paste on the left and press Validate. Nothing leaves this tab.
Nothing else to flag.
No formatting problems, and nothing the rules object to. Worth remembering what that covers: this reads the file you pasted, not the account or cluster it will be applied to.
No finding matches that filter.
Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.
Legal JSON-RPC 2.0 and forbidden by MCP, so a generic validator passes it
{"jsonrpc": "2.0", "id": null, "error": {"code": -32700, "message": "Parse error"}}The tool runs with no arguments at all and reports a missing required field, which reads as a schema problem
{"jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": {"name": "read_file", "args": {"path": "/tmp/a"}}}Valid under revision 2025-03-26 and removed in 2025-06-18, so it now fails as a parse error rather than a version error
[{"jsonrpc": "2.0", "id": 1, "method": "ping"},
{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}]These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.
Base JSON-RPC 2.0 permits it when a request could not be parsed. MCP removes that allowance, so a message a JSON-RPC library happily produces is rejected.
Instead:Use a string or an integer. A genuinely unparseable request is a transport problem, not a message to send.
The id is what makes a message a request. `notifications/initialized` with an id turns into a request for a method defined never to answer, so the sender waits forever.
Instead:Omit the field entirely. Setting it to null does not help, because null is separately forbidden.
A protocol error is handled by the client and never reaches the model, so the model cannot react to it. Reporting "file not found" as `-32603` hides the failure from the only participant that could recover.
Instead:Return a normal result with `isError: true` and the reason in `content`. Reserve JSON-RPC errors for protocol problems.
A message can be valid JSON-RPC and still be rejected by an MCP peer. Three of the rules below exist only in MCP, so a generic JSON-RPC validator passes messages that will fail.
Base JSON-RPC 2.0 allows a null id on an error response when the request could not be parsed. MCP removes that allowance outright: on a request or a response the id is a string or a number, never null. This is the rule most often broken by code written against a JSON-RPC library rather than against MCP.
A message with a method and an id is a request and gets exactly one response. The same message without an id is a notification and gets none, ever. Send notifications/initialized with an id and you wait forever for a reply the protocol says will not come; send tools/list without one and the server may well do the work and drop the answer.
A JSON-RPC batch, an array of messages in one frame, was valid under 2025-03-26. Revision 2025-06-18 removed it. Current peers reject the array, and because the failure happens before any message inside it is read, the error looks like a parse problem rather than a version one.
tools/List is not tools/list. The peer answers -32601 Method not found, which reads as a feature the server does not implement rather than as a typo. This is worth knowing because it is the one class of bug where the error message actively misleads.
These are different channels and conflating them loses information. A JSON-RPC error means the protocol went wrong: unknown method, malformed arguments, handler threw. It is handled by the client and the model never sees it. A tool whose work failed returns a normal successful result with isError set to true and the reason in content, which does reach the model, so it can try something else. Returning -32603 for "file not found" hides the problem from the only participant that could recover from it.
Whether the arguments in a tools/call match the tool's own schema, because that schema is not in the message. Whether the id is unique across the session, because one message is not a session. Whether the peer would accept it, since implementations vary in how strict they are and a lax one accepts things listed here as errors. For per-session rules such as id reuse and handshake ordering, use the stdio session debugger on a whole log instead.