Transport choice determines how MCP messages move between client and server. It does not change the logical protocol, but it changes deployment shape, authentication options, failure modes, and operating cost.
In the current stable MCP specification revision, `2025-11-25`, the standard transports remain stdio and Streamable HTTP. Streamable HTTP replaced the older HTTP+SSE transport from the `2024-11-05` revision, which is now a backwards-compatibility concern rather than the preferred design.
| Transport | Best Fit | Strengths | Operational Caveats |
|---|---|---|---|
| stdio | Local spawned servers | Simple, low-latency, no HTTP stack | Process lifecycle and stdout hygiene matter |
| Streamable HTTP | Hosted network services | Remote auth, session support, multi-client deployment | Needs HTTP security, session handling, and observability |
| HTTP+SSE (legacy) | Older client compatibility only | Supports old deployments during migration | Deprecated for new implementations |
stdio is the default local transport for many desktop and developer workflows. The host launches the server process and exchanges JSON-RPC messages over stdin and stdout.
This is simple, but it comes with discipline requirements. Protocol traffic must stay on stdout. Diagnostic logs should go to stderr. If your server writes arbitrary text to stdout, you corrupt the transport.
Streamable HTTP is the modern remote transport. Clients send JSON-RPC requests over HTTP POST and can receive responses either as JSON or via an SSE stream, depending on the flow and server behavior.
The current spec also allows a client to open an SSE stream with HTTP GET for server-to-client communication. That makes Streamable HTTP more flexible than the old split-endpoint HTTP+SSE model while staying aligned with normal network deployment practices.
Transport is not just connectivity. It changes your threat model. A local stdio server inherits the host environment and must guard against path confusion, environment assumptions, and accidental data exposure. A remote HTTP server must handle origin validation, authentication, network hardening, and session management.
The current transport spec explicitly warns about DNS rebinding risks for local HTTP deployments. If you expose Streamable HTTP on localhost, validate Origin headers and prefer binding only to localhost instead of all interfaces.
Some hosts and servers still support the deprecated HTTP+SSE transport from the November 5, 2024 MCP revision. That is a compatibility problem to manage, not a reason to design new systems around the older model.
If you have to support both generations, isolate the compatibility layer so your main capability code does not become transport-specific spaghetti.
Transport is not just plumbing. It decides who starts the server, where credentials live, how failures are observed, how sessions scale, and how data crosses machine boundaries. Stdio is usually best when the host launches a local process and the data should stay near the user workspace. Streamable HTTP is usually best when the server is a managed remote service with independent deployment, shared access, and enterprise authorization.
A local stdio server can feel simpler because there is no network endpoint to operate, but it still needs careful packaging, path handling, environment variables, logging, and update strategy. A remote HTTP server can centralize operations and authorization, but it introduces network reliability, token handling, tenant isolation, rate limiting, and service ownership.
Choose the transport that matches the real trust boundary. If a tool reads a user local repository, spawning a local server may be safer and more intuitive. If a tool reads company tickets with centralized permissions, a remote service may be easier to secure and audit.
Modern Streamable HTTP deployments may be stateless or stateful depending on the server design. Stateless servers are easier to scale horizontally because any replica can handle a request. Stateful servers can support richer session behavior, but they need shared persistence, sticky routing, or explicit session recovery. Decide intentionally before production load decides for you.
Streaming should improve responsiveness, not hide slow architecture. If a tool takes a long time because it is waiting on a backend job, consider task-style deferred work where supported rather than keeping users staring at an open request. If output is large, stream bounded chunks with clear completion and error behavior.
Choose an MCP transport by working from ownership outward. First ask where the server should live. If it must run beside a user workspace, read local files, or use local developer tools, stdio is usually the clearest starting point because the host launches and supervises a local process. If the server is shared, centrally deployed, audited, and accessed by many users or tenants, Streamable HTTP is usually the better fit.
Second, ask who owns authentication and operations. A local stdio server still needs packaging, environment configuration, process supervision, and safe logging. A remote HTTP server needs HTTPS, authorization metadata, token handling, rate limits, monitoring, and scaling. Neither transport removes engineering work; they simply move the work to different owners.
Third, ask how long runs behave. Short, local tools may complete within one request. Remote systems may need resumability, cancellation, or task-style deferred work. If your transport choice makes cancellation, status, or recovery impossible to explain, the architecture is not ready for production.
Test transport behavior the way it will fail in production. For stdio, test missing executable paths, missing environment variables, startup crashes, stdout pollution before initialize, stderr logging, and graceful process shutdown. These are the failures users actually see when a local server is packaged incorrectly.
For Streamable HTTP, test authentication failure, expired tokens, network timeout, client disconnect, server restart, large responses, and concurrent requests from different tenants. Also decide whether the server is stateless or sessionful, because that choice affects load balancing, recovery, and horizontal scaling.
A transport review should end with a runbook. The runbook should explain how to confirm the server is reachable, how to inspect initialization, where logs live, how to rotate credentials, how to disable the server, and how to distinguish transport failure from capability-handler failure.
After HTTP initialization, the client sends the negotiated revision in the `MCP-Protocol-Version` header on subsequent requests. This lets the server interpret messages under the same contract that initialization selected.
Reject unsupported versions explicitly and record the negotiated value in traces. A load balancer, gateway, or client library must not strip or rewrite the header, because a successful HTTP exchange can still be a protocol mismatch.
With stdio, the client launches the server process, writes newline-delimited JSON-RPC messages to standard input, and reads them from standard output. Messages are UTF-8 and cannot contain embedded newlines. Standard output is protocol-only; diagnostics belong on standard error. One startup banner printed to stdout is enough to corrupt initialization.
Streamable HTTP exposes one MCP endpoint supporting POST and GET, with optional Server-Sent Events for multiple messages. Validate the Origin header to prevent DNS rebinding, bind local-only services to loopback, authenticate remote access, and keep tenant state isolated. If the server issues an MCP session identifier, clients must return it according to the transport rules and handle expiry without silently reusing another session.
The older HTTP-plus-SSE transport belongs to compatibility with the `2024-11-05` revision, not new deployment design. Migration should test resumability, disconnects, duplicate delivery, request correlation, protocol-version headers, and whether load balancing preserves the chosen session model.
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new McpServer({ name: 'local-files', version: '1.0.0' });
// Register tools, resources, and prompts here.
const transport = new StdioServerTransport();
await server.connect(transport);
{
"mcpServers": {
"docs": {
"command": "node",
"args": [
"C:/absolute/path/to/docs-server/dist/index.js"
],
"env": {
"DOCS_INDEX_PATH": "C:/absolute/path/to/index"
}
}
}
}
No. It is better for hosted services, but stdio is often the cleanest option for local process-spawned workflows.
No. Transport-level auth and per-capability authorization are complementary, not substitutes.
Explore 500+ free tutorials across 20+ languages and frameworks.