
This page is part of our MCP specification reference, a plain-English guide to the Model Context Protocol spec (version 2026-07-28), within The MCP Guide. Building a server? See MCP development.
Status in the 2026-07-28 spec: core
Every MCP message is a JSON-RPC 2.0 message. JSON-RPC is a small, decades-old convention for one program to call a function in another by sending a JSON object. MCP uses three kinds: requests, responses (a result or an error) and notifications.
MCP adds a few rules on top of plain JSON-RPC. IDs can never be null. Every result now carries a resultType. And since the 2026-07-28 spec, only the client starts requests.
This page explains each message type in plain English, with examples from the MCP base protocol page, current as of October 2026.
Key Takeaways
- MCP messages "MUST follow the JSON-RPC 2.0 specification," with a few MCP-specific additions.
- Requests carry a string or integer ID that is never null and never reused while a request is still open.
- Every successful result must include
resultType:completeorinput_required. - Notifications are one-way messages with no ID, and the receiver must not reply.
- In 2026-07-28, servers must not start requests; they ask for input through multi round-trip requests instead.
- MCP reserves error codes
-32020to-32099for codes defined by the spec.
What JSON-RPC is, and why MCP uses it
JSON-RPC 2.0 defines a request object with a method name and params, and a response object with either a result or an error. It does not care how bytes travel, so the same messages work over a local pipe or over HTTP.
That is why MCP picked it. The MCP overview says the protocol "uses JSON-RPC 2.0 messages" between hosts, clients and servers. The transport (stdio or Streamable HTTP) only decides how those messages are delivered.
Requests
A request asks the other side to do something. In 2026-07-28, "Requests are sent from the client to the server, to initiate an operation." The rules are:
- A request MUST include a string or integer
id. - "Unlike base JSON-RPC, the ID MUST NOT be
null." - The ID MUST NOT match any other request the sender has sent and not yet had answered.
Every request also carries metadata in params._meta. The protocol version and client capabilities are required on every request; client name and version are recommended. Here is a tool call adapted from the extensions overview:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": { "location": "New York" },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientCapabilities": {},
"io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" }
}
}
}
A request missing a required _meta field is malformed. The spec says the server MUST reject it with error -32602 (Invalid params), and with 400 Bad Request on HTTP.
Responses: results
A result response answers a request that worked. It MUST carry the same id as the request and a result object. New in 2026-07-28, the result MUST include a resultType:
"complete": the request finished and the result holds the final content."input_required": the server needs more information first. This drives multi round-trip requests.
For older servers that do not send it, "clients MUST treat an absent resultType as complete." Any value the client does not recognize "MUST be considered invalid." Extensions may add their own values once both sides advertise them.
Here is an illustrative tool result (our example, following the shapes in the spec):
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"content": [{ "type": "text", "text": "Sunny, 72°F" }]
}
}
Responses: errors
An error response carries an error object with an integer code and a message, plus optional data. It uses the request's ID, unless the ID could not be read because the request was malformed.
MCP uses the standard JSON-RPC codes (-32700 and -32600 to -32603) for general failures. It also splits the JSON-RPC server-error range:
| Range or code | Meaning in 2026-07-28 |
|---|---|
-32000 to -32019 | Legacy range. No new codes may be allocated here. |
-32020 to -32099 | Reserved for codes defined by the MCP spec |
-32020 | HeaderMismatch |
-32021 | MissingRequiredClientCapability |
-32022 | UnsupportedProtocolVersion |
-32002 | Old "resource not found" code; now replaced by -32602 |
Your own application errors should sit outside the JSON-RPC reserved range of -32768 to -32000. Note that a tool failing at its job (for example, "city not found") is usually reported inside a normal tool result, not as a protocol error. Our guide to MCP tool errors covers that difference.
Notifications
A notification is a one-way message. It "MUST NOT include an ID," and "the receiver MUST NOT send a response." This example, from the cancellation page, is a client telling a stdio server to stop work on request 123:
{
"jsonrpc": "2.0",
"method": "notifications/cancelled",
"params": {
"requestId": "123",
"reason": "User requested cancellation"
}
}
In 2026-07-28, servers send notifications in two places only. Some are tied to a request in flight, such as progress updates. Others flow on a subscriptions/listen stream the client opened, such as "the tool list changed." The message patterns page is explicit: "Servers MUST NOT initiate JSON-RPC requests, and clients do not send JSON-RPC responses."
What changed across spec versions
- 2025-03-26 added support for JSON-RPC batching, per its changelog.
- 2025-06-18 removed batching again, according to the 2025-06-18 changelog. Send one message at a time.
- 2025-11-25 and earlier let requests flow "from the client to the server or vice versa," per the 2025-11-25 base protocol page. Servers could send
sampling/createMessageorelicitation/createrequests to clients. - 2026-07-28 made the client the only side that starts requests, added the required
resultTypefield and set the error-code allocation policy. The 2026-07-28 changelog also moved three codes: HeaderMismatch from-32001to-32020, MissingRequiredClientCapability from-32003to-32021and UnsupportedProtocolVersion from-32004to-32022.
For the full picture of the 2026 release, see what changed in the July 2026 MCP specification.
Common mistakes
- Reusing an ID on a retry. In a multi round-trip request, "the JSON-RPC
idMUST be different between the initial request and the retry." - Sending
nullIDs. Plain JSON-RPC allows it; MCP does not. - Leaving out
resultType. New servers must send it on every result. - Replying to a notification. Notifications never get a response.
- Inventing codes in the MCP range. Implementations "MUST NOT emit any code" from
-32020to-32099that the spec does not define. - Still emitting
-32002for missing resources. Use-32602, but keep accepting-32002from older servers. - Treating
clientInfoas identity. It is self-reported and not verified, so never use it for security decisions.
Next step
JSON-RPC tells you the shape of each message. The next question is who sends them. Read MCP hosts, clients and servers, or return to the MCP specification hub.
Frequently asked questions
Does MCP use JSON-RPC 2.0?
Yes. All messages between MCP clients and servers must follow JSON-RPC 2.0. MCP adds its own rules, such as non-null IDs, the _meta field and the required resultType on results.
Can an MCP server send requests to the client?
Not in the 2026-07-28 spec. Servers must not initiate JSON-RPC requests. When a server needs something from the client, it returns an input_required result and the client retries the original request with the answers.
Does MCP support JSON-RPC batching?
No. Batching was added in 2025-03-26 and removed in 2025-06-18. Each message is sent on its own.
What is resultType in MCP?
It is a required field on every result in 2026-07-28. complete means the result is final. input_required means the server needs more input before it can finish.
What error code means "unsupported protocol version"?
In 2026-07-28 it is -32022. The error's data lists the versions the server supports, so the client can retry with one of them.











