MCP uses JSON-RPC (JSON Remote Procedure Call) 2.0, a request-and-response message standard, encoded as Unicode text. There are three message shapes.
A request carries jsonrpc: "2.0", a unique id (string or number, never null), a method, and optional params. A response echoes the id and contains exactly one of result or error, where error has a numeric code, a message, and optional data.
A notification has a method and params but no id, and must never be answered.
{ "jsonrpc": "2.0", "id": 1, "method": "resources/read",
"params": { "uri": "file:///notes.md" } }
{ "jsonrpc": "2.0", "id": 1, "result": {
"contents": [{ "uri": "file:///notes.md", "mimeType": "text/markdown", "text": "..." }] } }
MCP layers its own method namespace on top: initialize, tools/list, tools/call, resources/read, prompts/get, sampling/createMessage, notifications/..., and so on. Both sides can send requests, which is unusual and important: servers can call back into clients (sampling, roots, elicitation). The protocol is therefore bidirectional and sessions are stateful.
Requests may be answered out of order; the id does the correlation.
This answer doesn't lend itself to a diagram - it reads best . No credits were charged.
Why there's no diagram: “”
The interactive diagram is below the answer - jump to diagram ↓ · Below it, the related concept . Jump to it ↓
The diagram below the answer is the concept . Jump to it ↓