MCP JSON-RPC Message Validator

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.

Paste below, or drop a file anywhere on this panel

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.

Wanted a different tool?

  • MCP Structured Output Validator when the envelope is valid and the payload inside it is the question, since a schema the server declared is one only the server has to keep.

Examples

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.

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"}}

args instead of arguments

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"}}}

A batch array

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"}]

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Sending `"id": null` on an error response

    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.

  2. Giving a notification an id

    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.

  3. Returning a JSON-RPC error when a tool fails

    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.

Where MCP is stricter than JSON-RPC 2.0

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.

id must not be null

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.

The id is what makes a request a request

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.

Batching was removed in 2025-06-18

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.

Method names are exact and case-sensitive

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.

A tool that failed is not a protocol error

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.

What this cannot see

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.