MCP Transports: stdio for Local Servers, Streamable HTTP for Remote Ones
MCP defines exactly two transports as of the 2025-11-25 specification — stdio and Streamable HTTP — and picking between them is a deployment-time decision, not a runtime one: a server is built and launched against one transport, and tool logic doesn't change when you switch (modelcontextprotocol.io/specification/2025-11-25/basic/transports). Getting this choice right on the first attempt is one of the concrete things this wiki's objective asks for when building a remote server. See MCP Architecture: Host, Client, Server, and the JSON-RPC 2.0 Wire Format for how the transport layer relates to the JSON-RPC data layer it carries.
stdio: local, same-machine integrations
The client launches the MCP server as a subprocess; the server reads JSON-RPC 2.0 messages from stdin and writes them to stdout, with each message delimited by a newline (modelcontextprotocol.io/specification/2025-11-25/basic/transports). The server MAY write UTF-8 logging output to stderr but MUST NOT write anything else to stdout — stdout is reserved exclusively for valid MCP messages (modelcontextprotocol.io/specification/2025-11-25/basic/transports). The spec explicitly recommends it: "Clients SHOULD support stdio whenever possible" (modelcontextprotocol.io/specification/2025-11-25/basic/transports).
Performance
stdio achieves sub-millisecond latency (roughly 0–1ms) and 10,000+ operations/second throughput, because communication is direct CPU-to-CPU over file descriptors with no network stack involved (truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise — vendor benchmark, single source).
When it fits
local development and single-developer scenarios where process isolation is a feature, not a bug — the rule of thumb given is "if the person using the AI client also controls the machine the server runs on, use stdio" (truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise).
Streamable HTTP: remote, multi-client servers
Streamable HTTP is the current standardized remote transport, replacing the earlier HTTP+SSE transport from protocol version 2024-11-05 (modelcontextprotocol.io/specification/2025-11-25/basic/transports). The server runs as an independent process and exposes a single HTTP endpoint that supports both POST and GET (modelcontextprotocol.io/specification/2025-11-25/basic/transports) — a deliberate simplification over the two-endpoint design it replaced (see "What does NOT work" below).
Sending messages
the client sends JSON-RPC messages via HTTP POST, with an Accept header listing both application/json and text/event-stream (modelcontextprotocol.io/specification/2025-11-25/basic/transports).
Streaming responses
the server MAY respond over Server-Sent Events (SSE) to stream multiple messages for a single client request (modelcontextprotocol.io/specification/2025-11-25/basic/transports). If it opens an SSE stream, it SHOULD immediately send an event with an empty data field to prime the client for reconnection (modelcontextprotocol.io/specification/2025-11-25/basic/transports). The server MAY also close an SSE connection without ending the logical stream, letting the client reconnect and resume with the Last-Event-ID header (modelcontextprotocol.io/specification/2025-11-25/basic/transports).
Server-initiated messages
clients MAY issue a plain GET to open an SSE stream and receive server-initiated messages without first POSTing anything, and MAY hold multiple SSE streams open at once for concurrent operations (modelcontextprotocol.io/specification/2025-11-25/basic/transports).
Auth surface
because it's plain HTTP, Streamable HTTP layers onto standard HTTP security patterns — bearer tokens, API keys, custom headers, OAuth, mTLS — whatever the surrounding infrastructure already uses (truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise). See Authorization in MCP: OAuth 2.1, Token Scoping, and the Confused-Deputy Problem — securing a remote server on the first attempt for how MCP's own authorization model builds on this.
Latency
stdio's sub-millisecond figure is a same-machine number; Streamable HTTP measures at roughly 10ms per call even under load (truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise — vendor benchmark, single source). The gap is the price of remote accessibility, not a defect: stdio is bound to a single machine, HTTP is not.
Statefulness
under the 2024-11-05 and 2025-06-18 specs, Streamable HTTP could pin a client to one server instance via a cryptographically-secure MCP-Session-Id header (UUID, JWT, or hash) (modelcontextprotocol.io/specification/2025-06-18/basic/transports). That stateful model forced sticky-session routing at the load balancer — every request from a client had to land on the same server instance (techcommunity.microsoft.com/blog/mcp-just-went-stateless). This constraint is being removed in 2026 (see below).
Scalability
stdio is a process-per-connection model that does not scale to multi-user production use — the cited example is 50 developers across 8 servers producing roughly 400 concurrent processes spread across 50 laptops (truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise). Streamable HTTP, by contrast, is built for horizontal scaling behind a load balancer, letting many clients share a pool of server instances (modelcontextprotocol.io/specification/2025-11-25/basic/transports).
Firewall/network
stdio needs zero network configuration — it's file descriptors on one machine (modelcontextprotocol.io/specification/2025-11-25/basic/transports). Streamable HTTP servers carry two hard security requirements instead: they MUST validate the Origin header on incoming connections to prevent DNS rebinding attacks, and SHOULD bind to 127.0.0.1 rather than 0.0.0.0 when running locally, to avoid unintended network exposure (modelcontextprotocol.io/specification/2025-11-25/basic/transports).
Audit trail
stdio authenticates only via environment variables and has no centralized interception point, so audit and identity have to be reconstructed out-of-band; Streamable HTTP's single HTTP endpoint is a natural point to apply centralized auth and logging (truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise).
What does NOT work: the original HTTP+SSE transport
The transport that shipped with protocol version 2024-11-05 required two separate endpoints — an SSE endpoint (/sse) for receiving responses and a POST endpoint (/sse/messages) for sending requests — with the server sending an endpoint event to tell the client where to POST (modelcontextprotocol.io/specification/2024-11-05/basic/transports). It was deprecated in the 2025-03-26 specification, roughly four months after its November 2024 introduction, for three concrete failure modes documented independently of the official spec (blog.fka.dev/2025-06-06-why-mcp-deprecated-sse):
- Fragile sessions: the SSE connection was stateful and long-lived; if it dropped, the client lost its only channel for responses and had to re-establish the whole session from scratch (blog.fka.dev/2025-06-06-why-mcp-deprecated-sse). This also forced sticky-session routing, since the persistent connection was pinned to one server instance (blog.fka.dev/2025-06-06-why-mcp-deprecated-sse). - Security blind spot: credentials were checked once, at connection time, then the connection stayed open — "the door propped open" — with no re-verification for the life of the stream (auth0.com/blog/mcp-streamable-http). - Token leakage: developers were often forced to pass sensitive access tokens directly in the URL query string, since there was no better place to put them in the two-endpoint design (blog.fka.dev/2025-06-06-why-mcp-deprecated-sse).
Streamable HTTP fixes all three by collapsing the design to a single endpoint with per-request POST semantics and optional, resumable SSE only when actually needed (modelcontextprotocol.io/specification/2025-11-25/basic/transports). The MCP TypeScript SDK kept backward compatibility with the old SSE transport for the migration period (blog.fka.dev/2025-06-06-why-mcp-deprecated-sse). Lesson for server builders: don't hand-roll a two-endpoint SSE design even for compatibility reasons — it reproduces exactly the session-fragility and token-in-URL problems the spec moved away from.
The move toward a stateless core (2026)
The 2026-07-28 release candidate removes the initialize/initialized handshake and the MCP-Session-Id header entirely — the headline claim is "a stateless protocol core" (blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate). Protocol version, client info, and capabilities now travel inline in a _meta field on every request instead of being negotiated once at session start (blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate) — this changes how MCP Session Lifecycle: the Handshake a Client Must Get Right — and the One Being Removed in 2026-07-28 works going forward. Because no server instance is pinned to a client anymore, any instance can serve any request, and remote servers can sit behind a plain round-robin load balancer with no sticky sessions and no shared session store (blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate; techcommunity.microsoft.com/blog/mcp-just-went-stateless). New MCP-Method and MCP-Name HTTP headers let load balancers, gateways, and rate limiters route on the operation without buffering and parsing the JSON-RPC body first (blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate). List operations gained ttlMs and cacheScope parameters so clients can cache tool/resource lists per server-specified freshness windows (blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate), and W3C Trace Context propagation is now formally specified for distributed tracing (blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate). The final spec is dated to ship July 28, 2026, after a ten-week validation window for SDK maintainers and client implementers, and going forward the spec commits to twelve-month deprecation windows before removing any feature (blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate).
Why it matters for building a server
the scalability gap in stdio was architectural (process-per-connection); the scalability friction in Streamable HTTP up to 2025-06-18 was the sticky-session requirement. The 2026 stateless core removes the second one, leaving raw process-vs-network overhead as the only remaining structural trade-off between the two transports.
Choosing a transport
Decision rule: use stdio if the person using the AI client also controls the machine the server runs on; use Streamable HTTP for new remote deployments, serverless environments, high-scale production, or any deployment where operational simplicity and centralized monitoring matter (truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise). Streamable HTTP is the right call specifically for shared-team scenarios needing remote reachability, centralized monitoring, or rate limiting (truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise). Migrating from stdio to Streamable HTTP later is a wiring change, not a rewrite, because MCP's data layer is transport-agnostic and tool logic is unaffected (truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise; modelcontextprotocol.io/specification/2025-11-25/basic/transports) — see Building an MCP Server: SDKs, Tool Schemas, Testing, and Deployment — the practical path from a 15-minute local prototype to a hosted remote server for the deployment patterns this enables in practice.
This is the transport decision the wiki's objective names directly: getting it right — and knowing why HTTP+SSE is the wrong answer even though it still shows up in older tutorials — is a precondition for "build a working, secure remote MCP server on the first attempt."
Related
- MCP Architecture: Host, Client, Server, and the JSON-RPC 2.0 Wire Format — the transport layer sits under the JSON-RPC data layer described there; this page is the deployment-time half of that split.
- MCP Session Lifecycle: the Handshake a Client Must Get Right — and the One Being Removed in 2026-07-28 — the initialize/initialized handshake this page describes is being removed in the 2026 stateless core; that page needs to track the new _meta-based negotiation.
- Authorization in MCP: OAuth 2.1, Token Scoping, and the Confused-Deputy Problem — securing a remote server on the first attempt — Streamable HTTP's open HTTP surface is what makes OAuth, bearer tokens, and mTLS possible in the first place; stdio has no equivalent auth layer.
- Building an MCP Server: SDKs, Tool Schemas, Testing, and Deployment — the practical path from a 15-minute local prototype to a hosted remote server — deployment patterns (local stdio process vs. hosted remote server) that follow directly from the transport choice made here.
- MCP Adoption and the July 2026 Spec — what changed under you while you weren't looking — the July 2026 release candidate summarized in this page's stateless-core section is one of that page's key data points.
Verified against
- modelcontextprotocol.io/specification/2025-11-25/basic/transpor…
- modelcontextprotocol.io/specification/2025-06-18/basic/transpor…
- modelcontextprotocol.io/specification/2024-11-05/basic/transpor…
- blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate
- truefoundry.com/blog/mcp-stdio-vs-streamable-http-enterprise
- techcommunity.microsoft.com/blog/appsonazureblog/mcp-just-went-…
- auth0.com/blog/mcp-streamable-http
- blog.fka.dev/blog/2025-06-06-why-mcp-deprecated-sse-and-go-with…
What links here
Source: Sinapsi — verified compositional memory, queryable by LLMs. Query this wiki live from your assistant over MCP, or build your own verified wiki (public, or private for your team). CC BY 4.0 — reuse with attribution to Sinapsi.