MCP Transport Layer
stdio for local servers, SSE for legacy remote, Streamable HTTP for modern stateless remote — when to use each and how they differ.
An MCP server is a process that speaks JSON-RPC 2.0. The transport is the mechanism that carries those messages between the client and server.
MCP supports three transports:
| Transport | When to use |
|---|---|
| stdio | Local servers — runs as a subprocess of the client |
| SSE (Server-Sent Events) | Legacy remote servers — deprecated in newer spec |
| Streamable HTTP | Modern remote servers — single endpoint, stateless |
ExpandMCP Transport Comparison
stdio — The Local Default
stdio is the simplest transport, and it's what I use for everything local. The MCP client spawns your server as a child process and communicates via stdin/stdout. JSON-RPC messages flow in on stdin, responses come back on stdout.
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const transport = new StdioServerTransport();
await server.connect(transport);This is what claude_desktop_config.json uses. Claude Desktop reads the command and args fields, spawns the process, and talks to it over stdio.
Advantages: Zero network overhead, simple setup, works without any server infrastructure. Limitation: Only works when client and server run on the same machine. A remotely hosted MCP server can't use stdio.
SSE — Server-Sent Events (Legacy)
SSE was the original remote transport for MCP. It uses:
- One SSE endpoint (
GET /sse) for server → client messages (the streaming channel) - One POST endpoint for client → server messages
This bidirectional setup over HTTP works but is stateful — each session requires a persistent SSE connection. That means your server needs session affinity (sticky routing), which complicates load balancing and scaling.
SSE is supported in the MCP SDK but deprecated in newer versions of the spec. I'd avoid it for new servers. Existing servers using SSE still work, but migrate to Streamable HTTP when you get the chance.
Streamable HTTP — The Modern Standard
Streamable HTTP is the current recommended transport for remote MCP servers. It uses a single endpoint (POST /mcp) for everything.
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";
const app = express();
app.use(express.json());
app.post("/mcp", async (req, res) => {
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
app.listen(3000);Why it's better than SSE:
- Stateless — no persistent connection required
- Single endpoint — simpler routing and load balancing
- Works behind standard HTTP infrastructure (CDNs, proxies, serverless)
How streaming works: For responses that stream (like sampling), the server uses HTTP chunked transfer encoding. The client reads chunks as they arrive. The endpoint is the same — just the response type differs.
Picking the Right Transport
Is the server running on the same machine as the client?
Yes → stdio
No → Streamable HTTP
Do you have legacy code using SSE?
Yes → Plan a migration to Streamable HTTP
No → Skip SSE entirelyFor learning and local development, stdio is always the right choice. For a server you want to deploy and share — a weather API, a team's shared issue tracker, a company's internal tools — Streamable HTTP is the path.
Remote Server Considerations
When you move from stdio to a remote transport, new concerns appear that I think are worth taking seriously from the start:
- Authentication: How does the server know who's calling? API keys, OAuth, JWTs.
- Authorization: Which user can call which tools? Not all callers should have the same access.
- Rate limiting: Remote servers can be called by multiple clients concurrently.
- HTTPS: Always use TLS for remote servers — MCP messages can contain sensitive data.
The MCP spec leaves auth to the implementer. For simple cases, an API key in an HTTP header works. For team or production deployments, use a proper auth flow.
Further Reading
Enjoyed this? Get more like it.
Deep dives on system design, React, web development, and personal finance — straight to your inbox. Free, always.