How does MCP relate to JSON-RPC 2.0?
Quick Answer
MCP uses JSON-RPC 2.0 as its wire format for every message between client and server. All three JSON-RPC message shapes are used: requests (have an id, expect a matching response — e.g. tools/call), responses (either a result or an error matching a request's id), and notifications (no id, no response expected — e.g. notifications/tools/list_changed). MCP itself defines the method names (initialize, tools/list, resources/read, ...) and the shape of their params/results on top of plain JSON-RPC, plus its own lifecycle and capability model. JSON-RPC just gives MCP a battle-tested, transport-agnostic message envelope, so it doesn't need to invent framing, IDs, or error semantics from scratch.
Detailed Answer
MCP doesn't invent its own message format. It's layered directly on JSON-RPC 2.0, a lightweight, transport-agnostic RPC spec that predates MCP by over a decade.
The three message shapes
// Request — has an id, expects a response
{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "search", "arguments": {"q": "mcp"}}}
// Response — matches the request's id, has either "result" or "error", never both
{"jsonrpc": "2.0", "id": 1, "result": {"content": [{"type": "text", "text": "3 results found"}]}}
// Notification — no id, fire-and-forget, no response expected
{"jsonrpc": "2.0", "method": "notifications/tools/list_changed"}
What JSON-RPC gives MCP for free
- A defined error object shape (
code,message, optionaldata) and a standard set of error codes (parse error, invalid request, method not found, invalid params, internal error). - Correlation of responses to requests via
id. This matters once you have several in-flight requests over one connection — an HTTP transport handling concurrent tool calls, for example. - A format that's transport-independent. The exact same JSON-RPC messages work whether they're framed as newline-delimited JSON over stdio, or as HTTP POST bodies/SSE events over Streamable HTTP.
What MCP adds on top
JSON-RPC only defines the envelope. On top of it, MCP layers everything that actually makes it MCP:
- A fixed catalog of method names (
initialize,tools/list,tools/call,resources/read,prompts/get,sampling/createMessage, and more). - The exact shape of each method's params and result.
- A lifecycle (initialize/initialized) that must run before most other methods are valid.
- A capabilities object that lets each side declare which optional features it supports.