JSON-RPC 2.0
JSON-RPC 2.0 is the message format every Model Context Protocol exchange uses. Each message is a JSON object carrying a jsonrpc version string, a method name, and either an id for requests or no id for notifications. MCP defines the method names; JSON-RPC defines the envelope they travel in.
Updated
What is JSON-RPC 2.0?
JSON-RPC 2.0 is a small, long-standing specification for calling a method on a remote system using JSON. It predates MCP by well over a decade and MCP adopts it wholesale rather than inventing a message format: every message between an MCP client and server must follow it [1].
A request names a method, carries optional params, and carries an id. The response carries the same id and either a result or an error.
What are the three message types?
Requests, responses, and notifications. A request has an id and expects an answer. A response echoes that id. A notification has a method but no id, and the receiver must not answer it [1].
MCP uses all three. initialize and tools/list are requests. notifications/initialized, which a client sends once the handshake is agreed, is a notification, and a server that waits for a response to it will hang.
What do the messages look like?
A request, here asking for the server's tools:
{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}
A result response, carrying the same id:
{"jsonrpc": "2.0", "id": 2, "result": {"tools": [{"name": "search", "inputSchema": {"type": "object"}}]}}
On the 2026-07-28 revision every result also carries a resultType, normally "complete"; a client treats a missing one as "complete", so results from older servers still parse [1].
A notification, with no id, telling the client the tool list changed:
{"jsonrpc": "2.0", "method": "notifications/tools/list_changed"}
An error response. The error object needs an integer code and a message, and may carry data [1]. This is the shape of the answer one server gave our initialize call:
{"jsonrpc": "2.0", "id": 1, "error": {"code": -32601, "message": "Unknown method: initialize"}}
If a server answers with a bare array, or with {"tools": [...]} and no envelope, it is not speaking JSON-RPC and a conforming client is right to reject it.
What are the JSON-RPC error codes in MCP?
MCP uses the five standard JSON-RPC codes for general protocol failures [1][4]:
| Code | Name | What it means |
|---|---|---|
| -32700 | Parse error | The body was not valid JSON |
| -32600 | Invalid Request | Valid JSON, but not a valid JSON-RPC request |
| -32601 | Method not found | The server has no method by that name |
| -32602 | Invalid params | The method exists, the arguments are wrong |
| -32603 | Internal error | The server failed while handling the request |
JSON-RPC leaves -32000 to -32099 for implementations, and the 2026-07-28 revision splits that range [1]. -32000 to -32019 is legacy: codes servers invented before the split, which a client must not read meaning into (apart from -32002, the old "resource not found", now replaced by -32602). -32020 to -32099 belongs to the MCP specification, which so far defines three: -32020 HeaderMismatch, -32021 MissingRequiredClientCapability and -32022 UnsupportedProtocolVersion.
On 20 August 2026 we called 1,100 remote MCP servers once each for our registry census. 6 rejected our initialize with a JSON-RPC error code. 3 sent -32001, and all three were refusing us for lack of a key ("invalid api key", "Authentication failed", "Unauthorized"), which the authorization spec expects as an HTTP 401 instead. One each sent -32601 (the server did not have initialize), -32602 ("Unsupported MCP protocol version") and -32603. MCP server errors covers what to do about each.
What can an id be?
A string or an integer. Plain JSON-RPC allows a null id; MCP does not [1][2].
What an id must not repeat changed with the 2026-07-28 revision. Up to 2025-11-25, a sender could not reuse an id anywhere in the same session [2]. The 2026-07-28 revision removed sessions, so the rule is now narrower: an id must not match another request the sender has sent and not yet had an answer to [1].
Batching, sending several messages as one JSON array, arrived in the 2025-03-26 revision and was removed in 2025-06-18 [3][5]. Neither later revision brings it back, so send one message per request.
Where does this go wrong in practice?
Most often at the envelope, not the content. A server that returns valid JSON which is not a valid JSON-RPC response fails before anything MCP-specific is even considered.
Across 82 connection attempts between 20 July and 5 August 2026 we recorded 4 protocol errors, meaning the address answered and spoke something, but not this. A separate 3 answered with a web page rather than JSON at all, which is what a documentation URL does when it is mistaken for an endpoint.