MCP uses JSON-RPC to encode messages. JSON-RPC messages MUST be UTF-8 encoded. The protocol currently defines two standard transport mechanisms for client-server communication:Documentation Index
Fetch the complete documentation index at: https://modelcontextprotocol.io/llms.txt
Use this file to discover all available pages before exploring further.
- stdio, communication over standard in and standard out
- Streamable HTTP
stdio
In the stdio transport, the client launches the MCP server as a subprocess. The two ends communicate over the subprocess’s standard streams:- The server reads JSON-RPC messages from
stdinand writes JSON-RPC messages tostdout. - Messages are individual JSON-RPC requests, notifications, or responses.
- Messages are delimited by newlines, and MUST NOT contain embedded newlines.
- The server MAY write UTF-8 strings to
stderrfor any logging purposes including informational, debug, and error messages. - The client MAY capture, forward, or ignore the server’s
stderroutput and SHOULD NOT assumestderroutput indicates error conditions. - The server MUST NOT write anything to its
stdoutthat is not a valid MCP message. - The client MUST NOT write anything to the server’s
stdinthat is not a valid MCP message.
Sending Messages
The client sends messages by writing JSON-RPC requests, notifications, or responses to the server’sstdin, one message per line.
Receiving Messages
All server-to-client messages — responses to client requests, in-flight notifications (notifications/progress, notifications/message), and
deliveries on a subscriptions/listen
stream — arrive on stdout, one message per line, multiplexed onto a single
shared channel.
To distinguish notifications belonging to different concurrent subscriptions,
clients MUST correlate notifications using the
io.modelcontextprotocol/subscriptionId field carried in _meta. See the
schema for SubscriptionsListenRequest
for details.
Request Metadata
All request metadata for the stdio transport is carried inline in the JSON-RPC message body. The protocol version, client identity, and per-request capabilities live in_meta.io.modelcontextprotocol/*;
the method name and arguments live where JSON-RPC puts them. There is no
header layer.
Cancellation
To cancel an in-flight request, the client MUST send anotifications/cancelled notification referencing the request’s ID. Because
stdio is a single shared bidirectional channel, there is no per-request stream
to close. Servers SHOULD stop work on a cancelled request as soon as
practical and MUST NOT send any further messages for it. See
Cancellation for the full rules.
Shutdown
The client SHOULD initiate shutdown by:- Closing the input stream to the child process (the server).
- Waiting for the server to exit.
- If the server does not exit within a reasonable time, forcibly terminating the process using the mechanism appropriate for the operating system.
SIGTERM
to SIGKILL. On Windows, where POSIX signals are not available, clients can
use TerminateProcess
or Job Objects.
Servers SHOULD exit promptly when their standard input is closed or reads
return end-of-file. This is the primary graceful-shutdown signal and the only
portable one, so honoring it reduces the need for forced termination.
The server MAY initiate shutdown by closing its output stream to the
client and exiting.
Unexpected Termination
If the server process exits unexpectedly, the client SHOULD restart it. Because the protocol is stateless, any in-flight requests are simply lost and the client can retry them against the fresh process. Activesubscriptions/listen streams must also be
re-established after restart.
Backward Compatibility
A client that supports both modern (per-request-metadata) MCP versions and a legacy version that requires aninitialize handshake SHOULD probe with
server/discover before sending
any other request. If the server returns Method not found (-32601), the
client falls back to the legacy initialize handshake. If the server returns
UnsupportedProtocolVersionError, it speaks a version of MCP without
initialize — the client SHOULD retry using one of the advertised
supportedVersions rather than falling back to initialize. See
Lifecycle: Backward Compatibility
for details.
A client that only supports modern versions does not need to probe.
Streamable HTTP
This replaces the HTTP+SSE transport from
protocol version 2024-11-05. See Backward Compatibility
below.
https://example.com/mcp.
Security & Endpoint
When implementing Streamable HTTP transport:- Servers MUST validate the
Originheader on all incoming connections to prevent DNS rebinding attacks.- If the
Originheader is present and invalid, servers MUST respond with HTTP 403 Forbidden. The HTTP response body MAY comprise a JSON-RPC error response that has noid.
- If the
- When running locally, servers SHOULD bind only to localhost (127.0.0.1) rather than all network interfaces (0.0.0.0).
- Servers SHOULD implement proper authentication for all connections.
Sending Messages
Every JSON-RPC message sent from the client MUST be a new HTTP POST request to the MCP endpoint.- The client MUST use HTTP POST to send JSON-RPC messages.
- The client MUST include an
Acceptheader listing bothapplication/jsonandtext/event-streamas supported content types. - The client MUST include the request metadata headers on each POST request.
- The body of the HTTP POST MUST be a single JSON-RPC request, notification, or response to a server-initiated input request (see Receiving Messages).
- If the body is a JSON-RPC notification or a response to a
server-initiated input request:
- If the server accepts it, the server MUST return HTTP status code
202 Acceptedwith no body. - If the server cannot accept it, it MUST return an HTTP error status
code (e.g.,
400 Bad Request). The HTTP response body MAY comprise a JSON-RPC error response that has noid.
- If the server accepts it, the server MUST return HTTP status code
- If the body is a JSON-RPC request, the server MUST return either
Content-Type: application/json(a single JSON object) orContent-Type: text/event-stream(an SSE response stream). The client MUST support both.
Receiving Messages
When the server returns an SSE response stream (Content-Type: text/event-stream):
- The server MAY send JSON-RPC notifications — for example,
notifications/progressornotifications/message— before the final response. These notifications MUST relate to the originating client request. - The server MUST NOT send independent JSON-RPC requests on this stream.
Server-to-client interactions (sampling, elicitation, list-roots) are
embedded as input requests inside an
IncompleteResultper SEP-2322 (MRTR), not delivered as separate requests on this or any other stream. - The final JSON-RPC response SHOULD terminate the stream.
subscriptions/listen
request. The server’s response is itself an SSE stream that stays open and
delivers notifications/tools/list_changed,
notifications/resources/updated, notifications/message, etc. for the
notification types the client opted in to.
When initiating an SSE stream, servers SHOULD include the
X-Accel-Buffering: no header in the HTTP response. This instructs reverse
proxies (such as nginx) to disable response buffering, ensuring that SSE
events are delivered to clients immediately rather than being held in a
buffer. Without this header, proxies may accumulate messages before sending
them to the client, introducing unwanted latency and potentially breaking the
real-time nature of SSE communication.
For workloads that need durability across connection drops, use the
tasks primitive; resumable SSE
streams via Last-Event-ID are not supported.
Cancellation
Closing the SSE response stream MUST be treated by the server as cancellation of that request. Because each request has its own response stream, the transport-level disconnect is unambiguous. The server SHOULD stop work on the cancelled request as soon as practical and MUST NOT send any further messages for it. See Cancellation for the full rules.Request Metadata
The Streamable HTTP transport mirrors selected JSON-RPC body fields into HTTP headers so that intermediaries (load balancers, gateways, observability tooling) can route and inspect requests without parsing the body.Protocol Version Header
Every POST request to the MCP endpoint MUST include anMCP-Protocol-Version header.
For example: MCP-Protocol-Version: DRAFT-2026-v1
The header value MUST match the
io.modelcontextprotocol/protocolVersion field carried in the request body’s
_meta. If the values do not match, the server MUST reject the request
with 400 Bad Request and a HeaderMismatch JSON-RPC error
(see Server Validation).
If the server does not implement the requested protocol version (whether the
version is unknown to the server, or is a known version the server has chosen
not to support), it MUST respond with 400 Bad Request and an
UnsupportedProtocolVersionError
listing its supported versions. See
Lifecycle: Protocol Version Negotiation
for the negotiation flow.
If the server does not implement the requested RPC method, it MUST respond
with 404 Not Found and a JSON-RPC error with code -32601
(Method not found).
For backward compatibility, if the server does not receive an
MCP-Protocol-Version header and has no other way to identify the version,
the server SHOULD assume protocol version 2025-03-26.
Standard Request Headers
| Header Name | Source Field | Required For |
|---|---|---|
Mcp-Method | method | All requests and notifications |
Mcp-Name | params.name or params.uri | tools/call, resources/read, prompts/get requests |
tools/call request:
resources/read request:
Custom Headers from Tool Parameters
MCP servers MAY designate specific tool parameters to be mirrored into HTTP headers using anx-mcp-header extension property in the parameter’s
schema within the tool’s inputSchema. See
Tool Definitions for
details on how to annotate tool parameters.
While the use of x-mcp-header is optional for servers, clients MUST
support this feature. When a server’s tool definition includes
x-mcp-header annotations, conforming clients MUST mirror the
designated parameter values into HTTP headers.
Schema Extension
Thex-mcp-header property specifies the name portion used to construct
the header name Mcp-Param-{name}.
Constraints on x-mcp-header values:
- MUST NOT be empty
- MUST contain only ASCII characters (excluding space and
:) - MUST be case-insensitively unique among all
x-mcp-headervalues in theinputSchema - MUST only be applied to parameters with primitive types (number, string, boolean)
x-mcp-header value
violates these constraints. Rejection means the client MUST exclude the
invalid tool from the result of tools/list. Clients SHOULD log a
warning when rejecting a tool definition, including the tool name and the
reason for rejection.
Example tool definition:
Value Encoding
Clients MUST encode parameter values before including them in HTTP headers to ensure safe transmission and prevent injection attacks. Type conversion: Convert the parameter value to its string representation:string: Use the value as-isnumber: Convert to decimal string representation (e.g.,42,3.14)boolean: Convert to lowercase"true"or"false"
=?base64? and suffix ?= indicate that the value is
Base64-encoded. Servers and intermediaries that need to inspect these
values MUST decode them accordingly.
Encoding examples:
| Original Value | Reason | Encoded Header Value |
|---|---|---|
"us-west1" | Plain ASCII | Mcp-Param-Region: us-west1 |
"Hello, 世界" | Contains non-ASCII | Mcp-Param-Greeting: =?base64?SGVsbG8sIOS4lueVjA==?= |
" padded " | Leading/trailing spaces | Mcp-Param-Text: =?base64?IHBhZGRlZCA=?= |
"line1\nline2" | Contains newline | Mcp-Param-Text: =?base64?bGluZTEKbGluZTI=?= |
Client Behavior
When constructing atools/call request via HTTP transport, the client
MUST:
- Extract the values for any standard headers from the request body (e.g.,
method,params.name,params.uri). - Append the
Mcp-Methodheader and, if applicable,Mcp-Nameheader to the request. - Inspect the tool’s
inputSchemafor properties marked withx-mcp-headerand extract the value for each parameter. - Encode the values according to the Value Encoding rules.
- Append a
Mcp-Param-{Name}: {Value}header to the request.
Server Behavior for Custom Headers
Intermediate servers that do not recognize anMcp-Param-{Name} header
MUST forward it and otherwise ignore it, as required by the
HTTP Semantics RFC.
Servers MUST reject requests with a recognized Mcp-Param-{Name} header
that contains invalid characters (see Value Encoding).
Any server that processes the message body MUST validate that encoded
header values, after decoding if Base64-encoded, match the corresponding
values in the request body. Servers MUST reject requests with a
400 Bad Request HTTP status and JSON-RPC error code -32001
(HeaderMismatch) if any validation fails.
| Scenario | Client Behavior | Server Behavior |
|---|---|---|
| Parameter value provided | Client MUST include the header | Server MUST validate header matches body |
Parameter value is null | Client MUST omit the header | Server MUST NOT expect the header |
| Parameter not in arguments | Client MUST omit the header | Server MUST NOT expect the header |
| Client omits header but value is in body | Non-conforming client | Server MUST reject the request |
Case Sensitivity
Header names (called “field names” in RFC 9110) are case-insensitive. Clients and servers MUST use case-insensitive comparisons for header names. Header values (such as method names) are case-sensitive.Server Validation
Servers that process the request body MUST reject requests where the values specified in the headers do not match the corresponding values in the request body. This prevents potential security vulnerabilities when different components in the network rely on different sources of truth (e.g., a load balancer routing on the header value while the MCP server executes based on the body value). When rejecting a request due to header validation failure, servers MUST return HTTP status400 Bad Request and SHOULD include a JSON-RPC error
response using the following error code:
| Code | Name | Description |
|---|---|---|
-32001 | HeaderMismatch | The HTTP headers do not match the corresponding values in the request body, or required headers are missing/malformed. |
-32000 to -32099).
Example error response:
- A required standard header (
MCP-Protocol-Version,Mcp-Method,Mcp-Name) is missing. - A header value does not match the corresponding request body value.
- A header value contains invalid characters.
Intermediaries MUST return an appropriate HTTP error status (e.g.,
400 Bad Request) for validation failures but are not required to return
a JSON-RPC error response.Backward Compatibility
A client that supports both modern (per-request-metadata) MCP versions and a legacy version that requires aninitialize handshake MAY detect which
era the server implements by attempting a modern request first. If the
server returns 400 Bad Request (or any other version error indicating the
server does not implement the modern protocol), the client falls back to
initialize and continues with the legacy version for subsequent requests.
See Lifecycle: Backward Compatibility
for details.
Separately, clients and servers can maintain backward compatibility with the
deprecated HTTP+SSE transport (from
protocol version 2024-11-05) as follows:
Servers wanting to support older clients should:
- Continue to host both the SSE and POST endpoints of the old transport,
alongside the new “MCP endpoint” defined for the Streamable HTTP transport.
- It is also possible to combine the old POST endpoint and the new MCP endpoint, but this may introduce unneeded complexity.
- Accept an MCP server URL from the user, which may point to either a server using the old transport or the new transport.
- Attempt to POST a request to the server URL, with an
Acceptheader as defined above:- If it succeeds, the client can assume this is a server supporting the new Streamable HTTP transport.
- If it fails with HTTP status codes “400 Bad Request”, “404 Not Found”,
or “405 Method Not Allowed”:
- Issue a GET request to the server URL, expecting that this will open
an SSE stream and return an
endpointevent as the first event. - When the
endpointevent arrives, the client can assume this is a server running the old HTTP+SSE transport, and should use that transport for all subsequent communication.
- Issue a GET request to the server URL, expecting that this will open
an SSE stream and return an