"Transport" just means how the client and server talk to each other. Are they on the same computer passing messages through a pipe, or on different machines passing messages over the internet? MCP supports three ways to connect, and the right choice depends entirely on where your server runs and who's using it. This page walks through all three.
If MCP had only one transport, it would be limited to one kind of server. In practice, MCP servers come in very different shapes:
Each situation has different needs. A laptop-local server doesn't need HTTPS or authentication; talking over a simple pipe is fastest. A shared team server needs to handle many clients at once, which means real network infrastructure. The three transports, stdio, SSE, and HTTP, map to those three worlds.
"stdio" stands for standard input/output. It's the oldest and most boring way to make two programs talk: one launches the other as a child process and sends messages through a pipe. No network, no ports, no HTTPS. Just two programs on the same computer passing newline-delimited JSON back and forth.
How it feels: you add a server to your client's config with a command (like npx @notionhq/notion-mcp), and the client spawns that command whenever you start up. The server process dies when the client does.
Use stdio when: the server needs access to your local file system, your local git repo, or any resource on your machine. Also: if you're doing private work and don't want data leaving the device.
What you trade off: it only works when the client and server are on the same machine. No sharing with teammates, no remote deployment. If your laptop is the server, your laptop has to be running. But within that constraint, it's the fastest transport and has the least operational overhead. This is what Claude Code uses by default for most MCPs.
SSE is a well-established web standard where the server keeps a long-lived HTTP connection open and streams events back to the client. It's been around since before AI. MCP uses it for remote servers that want streaming behavior, for example, a server that returns partial results as they come in.
How it feels: the server is a URL somewhere on the internet. The client connects once, authenticates (usually OAuth), and keeps the connection open for the duration of the session. Messages stream both ways.
Use SSE when: multiple people need to share one server (a team knowledge base, a company's internal tools MCP), or when the server does work that's nice to stream back incrementally (long-running searches, data generation, reports).
What you trade off: operational cost. You need a real server somewhere, TLS certificates, auth handling, and a process that stays alive. Not hard, but not nothing. Also, long-lived connections don't play well with serverless platforms like AWS Lambda, which was designed for short request-response cycles.
Plain stateless HTTP. Client sends a JSON-RPC request, server sends a JSON-RPC response. That's the whole story. No streaming, no long-lived connection, each call is independent.
How it feels: the server is an endpoint. The client calls it over HTTPS the same way your browser calls any API. Each tool call is one request. Done.
Use HTTP when: you're hosting on something serverless (AWS Lambda, Cloudflare Workers, Vercel Functions), when your server is simple enough to not need streaming, or when you just want the dumbest-possible deployment story. This is also the right choice for public APIs that many unrelated users will hit; stateless HTTP scales infinitely, while SSE doesn't.
What you trade off: responsiveness on long operations. If a tool takes 30 seconds to produce a result, HTTP makes the client wait for the whole thing with no feedback. SSE would stream partial progress. For most tools this doesn't matter; for a few (long reports, bulk imports) it does.
A single client can talk to many servers at once, each over a different transport. A realistic Claude Code setup might have:
The client manages all four transparently. Your agent can call tools from any of them in the same conversation. The transport is completely invisible to the model, which is as it should be. Pick the right one per server, and the rest takes care of itself.
Andrej Karpathy - Intro to Large Language Models (1 hour)