stdio and Streamable HTTP
A transport is a binding: how messages are framed, how metadata travels, how cancellation is signalled. The messages themselves are identical on both.
By the end of this lesson you can
- list the stdio rules: framing, the streams, cancellation, shutdown, credentials;
- list the Streamable HTTP rules: one endpoint, POST only, JSON or SSE replies, cancellation, 405;
- name the four
Mcp-*headers and what each mirrors; - explain why a header that disagrees with the body is rejected with
-32020, and why servers checkOrigin.
Two bindings, one protocol
Framing, replies, cancellation
- stdio: the client launches the server as a subprocess and writes one JSON-RPC message per line on its stdin. No embedded newlines.
- Responses come back one per line on stdout, which carries only protocol.
- Logs go to stderr, never stdout.
- To cancel a request on stdio, the client sends a
notifications/cancellednotification. - Streamable HTTP: one endpoint, POST only. Each message is its own request, with headers that mirror the body.
- The reply is one JSON object, or an SSE stream scoped to that one request (for progress, then the result).
- To cancel on HTTP, the client closes the response stream.
- GET and DELETE are answered
405 Method Not Allowed. There is no session to open a stream for or to delete; session ids are ignored.
stdio
- The client launches the server as a subprocess.
- One JSON-RPC message per line, no embedded newlines.
- stdout carries only protocol; stderr is for logs.
- Cancel with
notifications/cancelled. - Shutdown: close stdin, wait, then SIGTERM and SIGKILL.
- No OAuth: credentials come from the environment.
- If it crashes, restart the process and retry: nothing was kept.
Streamable HTTP
- One endpoint, POST only. Each message is its own request.
- The reply is one JSON object or an SSE stream scoped to that request.
- Cancel by closing the response stream.
- Headers mirror the body so gateways can route without parsing it.
- Validate
Originagainst DNS rebinding; bind to localhost when local. - GET and DELETE answer
405; session ids are ignored.
Headers that mirror the body
A gateway or load balancer wants to route, rate-limit and log by method and tool without parsing JSON. So the 2026-07-28 revision copies those values into headers.
| Header | Mirrors | Required on |
|---|---|---|
MCP-Protocol-Version | _meta protocol version | Every POST |
Mcp-Method | method | Every request |
Mcp-Name | params.name or params.uri | tools/call, resources/read, prompts/get |
Mcp-Param-{Name} | A tool argument marked x-mcp-header | When the tool declares it |
Spec rule
If a header disagrees with the body, the server answers 400 with error -32020, HeaderMismatch. The rule exists because a load balancer might route on the header while the server acts on the body: a request whose header says read_docs but whose body says delete_repo would slip past a gateway policy.
Key idea
A local HTTP server is reachable from any web page you visit, through DNS rebinding. That is why servers must validate Origin and should bind to 127.0.0.1 when they only serve the local machine.
Send a request to a modern server
The body is fixed: tools/call for the tool named in the box, with _meta version 2026-07-28. Change the method and headers and see what the server says.
Request line and headers
Body
Server answers
Press Send.
Quick check
How does a client cancel an in-flight request on Streamable HTTP?
notifications/cancelled is the stdio way; DELETE gets 405.The body says "name": "delete_repo" but the Mcp-Name header says read_docs. What happens?
Why do servers validate the Origin header?
Recap
- stdio: subprocess, one message per line, stdout only protocol,
notifications/cancelled, close stdin to stop, environment credentials. - Streamable HTTP: one endpoint, POST only, JSON or a request-scoped SSE stream, close the stream to cancel, GET and DELETE get 405.
MCP-Protocol-Version,Mcp-Method,Mcp-Name,Mcp-Param-*mirror the body; a mismatch is-32020.- Validate
Origin; bind local servers to 127.0.0.1.