Every agent of section 16 needs tools, and every application used to wire up its tools in its own way. The Model Context Protocol (MCP), introduced by Anthropic in November 2024 as an open standard, defines one way for LLM (large language model) applications to talk to the programs that provide tools and data, in the same spirit as the Language Server Protocol did for programming languages in editors: one standard, instead of one connection per pair of applications.
This page builds MCP from the bottom: JSON-RPC 2.0 messages, the framing of the stdio transport, the per-request metadata of the current revision, and a minimal tool server. Each part has a small example of the messages involved.
The specification is versioned by date. This page follows the latest revision, 2026-07-28, and points out what changed from earlier ones.
Hosts, clients and servers
- A host is the LLM application: a chat app, an IDE (integrated development environment), an agent.
- A client is the connector inside the host that talks to one server.
- A server is a program that offers capabilities: tools (functions the model can call), resources (data for the user or the model) and prompts (templated messages and workflows).
One host can connect to many servers, each through its own client, so a weather server, a database server and a file-system server can all serve the same chat.
JSON-RPC 2.0
All MCP messages follow JSON-RPC 2.0: a stateless, light-weight remote procedure call (RPC) protocol, that is, a standard way to ask another program to run a function and send back the result, with messages written in JSON (JavaScript Object Notation, a text format for structured data). There are three kinds:
- A request has
"jsonrpc": "2.0", anid, amethodand optionalparams. MCP requires the id to be a string or an integer, nevernull. - A response has the same
idand either aresultor anerror(an object with an integercodeand amessage). - A notification is a request without an
id. The receiver must not answer it.
Example. A request, its response, a notification and an error response:
A request: {"jsonrpc": "2.0", "id": 1, "method": "tools/list"} Its response: {"jsonrpc": "2.0", "id": 1, "result": {...}} A notification (no id): {"jsonrpc": "2.0", "method": "notifications/progress"} An error response: {"jsonrpc": "2.0", "id": 1, "error": { "code": -32601, "message": "Method not found"}}The
idis how a client matches a response to its request. The notification has noid: nobody answers it. A message with both aresultand anerror, or with"id": true, is invalid.
JSON-RPC reserves standard error codes: -32700 parse error, -32600 invalid request, -32601 method not found, -32602 invalid params, -32603 internal error. MCP adds its own in the range -32020 to -32099, such as -32022 for an unsupported protocol version. JSON-RPC batches (arrays of requests) were removed from MCP in revision 2025-06-18.
Transport: stdio
In the simplest transport the host launches the server as a subprocess and they exchange messages over its standard streams: the client writes to the server's stdin, the server writes to its stdout. Each message is one JSON object on one line: messages are delimited by newlines and must not contain embedded newlines, and nothing else may be written to stdout (logs go to stderr). Remote servers use the Streamable HTTP (Hypertext Transfer Protocol) transport instead, with the same messages.
Reading therefore means buffering bytes until a newline arrives, since one read may deliver half a message or several.
Example. Writing a message whose text contains a line break: JSON writes the break as the two characters
\n, so the line itself never contains a real newline:{"a":"line1\nline2","id":1}followed by the line terminator.Reading: the first read delivers
{"id":1}+ newline +{"id"(a message and half of the next). The reader returns the first message and keeps{"id"in its buffer. The second read delivers:2}+ newline +{"id":3}+ newline: the buffer plus the new text now holds two complete lines, and the reader returns both messages. A line that is not valid JSON is reported as a parse error instead of crashing the reader.
A stateless protocol
Up to revision 2025-11-25, a connection began with an initialize handshake: the client sent its protocol version and capabilities, the server answered with its own, and the client confirmed with a notifications/initialized notification. Revision 2026-07-28 removed the handshake and made MCP stateless: every request carries what the server needs in its params._meta field, under keys that all start with io.modelcontextprotocol/:
protocolVersion(required), for example"2026-07-28";clientCapabilities(required);clientInfo(recommended): the client's name and version.
A request missing a required field is malformed and gets error -32602. A request asking for a version the server does not support gets error -32022, whose data lists the supported versions and the requested one, so the client can retry with a common version. Servers must implement server/discover, which returns their supported versions, capabilities and identity in one call. Every result carries a resultType, "complete" for an ordinary result.
Example. A client asks for the tools of a server that supports only
2026-07-28. In the_metaof its request it puts the three keys (with the prefixio.modelcontextprotocol/):
- A request with
protocolVersion"2026-07-28"andclientCapabilities{}: the request may proceed.- A request with only
protocolVersion, withoutclientCapabilities: error-32602, with the message "Missing required _meta field" followed by the full name of the missing key.- A request with
protocolVersion"2025-01-01": error-32022, "Unsupported protocol version", whosedatalists the supported versions ("2026-07-28") and the requested one ("2025-01-01").Every request is checked on its own: the server does not remember anything about the client between requests.
Tools
A server that offers tools declares a tools capability and answers two methods:
tools/listreturns the tools, each with aname, adescriptionand aninputSchema: a JSON Schema (2020-12 by default) of its arguments (a description of the fields the arguments must have, and their types). The result also carries caching hints,ttlMsandcacheScope.tools/calltakesparams.nameandparams.argumentsand returnscontent, a list of items such as{"type": "text", "text": "..."}, andisError.
The specification separates two kinds of failure. Protocol errors (an unknown tool, a malformed request) are JSON-RPC errors, for example -32602. Tool execution errors (invalid input values, a failing API (application programming interface)) are ordinary results with isError: true and a text explaining what went wrong, because that text is what lets the model correct itself and try again.
Example. A server with a tool
add(two required numbersaandb) and a toolboomthat always fails.
tools/list: the toolsaddandboom, each with name, description and schema, plusttlMs300000 andcacheScope"public".tools/calladdwitha=2,b=3:contentwith the text5,isErrorfalse.tools/callboom:contentwith the text of the exception,city not found, andisErrortrue. The tool failed; the request did not.tools/callnope: error-32602, "Unknown tool: nope". A protocol error.- A notification: no answer.
resources/list(not implemented): error-32601, "Method not found".The input of a tool is checked against its schema. With a schema that requires a text
location, allows an integerdays, aunitsof"c"or"f", and forbids other fields, the arguments{"days": 2.5, "units": "k", "x": 1}give four problems, in this order: the missinglocation,daysnot an integer,unitsnot one of the allowed values, and the unexpectedx. Returned as a tool execution error, they tell the model exactly what to fix.
Security
Tools are arbitrary code execution. The specification asks hosts to obtain the user's explicit consent before invoking a tool or exposing user data to a server, and to treat tool descriptions as untrusted unless the server is trusted: a malicious server can write a description that is really a prompt injection (section 18).
References
- Model Context Protocol, Specification, revision 2026-07-28: base protocol, versioning, stdio transport, discovery, tools and changelog.
- Model Context Protocol, changelog of revision 2025-06-18: removal of JSON-RPC batching.
- JSON-RPC Working Group, JSON-RPC 2.0 Specification.
- Anthropic, Introducing the Model Context Protocol, November 25, 2024.
- Microsoft, Language Server Protocol.