Explainer

MCP transport: stdio vs Streamable HTTP (and when to use each)

MCP has two transports. Use stdio when the server runs as a local subprocess of one client, and Streamable HTTP when the server is a remote service many clients reach over the network. Here is the decision, with config for both.

Mark

Head of Marketing, MCPOrbit

Published
Updated
· Updated
Read time
· 7 min read
A decision diagram comparing MCP stdio transport, a local subprocess speaking JSON-RPC over stdin and stdout, against Streamable HTTP transport, a remote stateless endpoint reached by many clients over the network.

The Model Context Protocol (MCP) has two transports, and the choice is about where the server runs. Use stdio when the server is a local program that one client launches as a subprocess and talks to over stdin and stdout. Use Streamable HTTP when the server is a network service that many clients reach at a URL. Everything else, the tools and resources and prompts your server exposes, is identical across both.

What are the MCP transports?

A transport is the channel that carries JSON-RPC messages between an MCP client and an MCP server. The protocol defines two. stdio runs the server as a local subprocess: the client starts your program, writes requests to its standard input, and reads responses from its standard output. Streamable HTTP runs the server as a web service: the client sends each request as an HTTP POST to a single endpoint and reads the response, optionally as a stream of server-sent events on that same response. A third transport, the older HTTP plus SSE design that used a separate long-lived event channel, is deprecated as of the 2026-07-28 spec.

stdio vs Streamable HTTP: which should I use?

Choose by where the server has to live and who has to reach it. If the server runs on the same machine as the client and serves only that client, use stdio. If the server runs somewhere else and serves many clients over a network, use Streamable HTTP. The table below lines the two up on the decisions that actually differ.

                     stdio                    Streamable HTTP
-----------------------------------------------------------------------
Where it runs        local subprocess         remote HTTP service
Who reaches it       one client (the host)    many clients over network
How it starts        client spawns it         you deploy and host it
Message channel      stdin / stdout           HTTP POST (+ SSE stream)
State                per-process              stateless (2026-07-28)
Auth                 OS process trust         OAuth 2.1, audience-bound
Scaling              one process per client   horizontal, any instance
Typical use          local dev tools, CLIs    hosted, shared servers

When should I use stdio?

Reach for stdio when the server is a local tool that a single client owns. Because the client launches the process, there is no port to open, no URL to publish, and no auth handshake: the operating system already decided who is allowed to run the program. This is the default for MCP servers that ship as a command a developer installs, such as a filesystem server, a git server, or a wrapper around a local database.

  • The server accesses local resources: files, a local database, a dev toolchain, the machine's own credentials.
  • Exactly one client uses the server, and that client can launch it as a subprocess.
  • You want zero network and auth setup, because the process boundary is the trust boundary.
  • You are distributing the server as an installable command rather than a hosted service.

When should I use Streamable HTTP?

Reach for Streamable HTTP when the server is a service that lives away from the client and is shared. This is the transport for anything you deploy: a hosted server many users connect to, a server behind your company's auth, or a server that has to scale across instances. Under the 2026-07-28 spec this transport is stateless by default, so no single instance owns a client and you can run it behind an ordinary load balancer.

  • Many clients or users need to reach one server over the network.
  • The server is deployed remotely: a container, a serverless function, or an edge worker.
  • You need auth: Streamable HTTP servers are OAuth 2.1 resource servers with audience-bound tokens.
  • You want horizontal scale: with stateless mode any instance can answer any request, so autoscaling and load balancing just work.

How do I configure a stdio MCP server in a client?

For stdio you do not host anything. You tell the client the command to run, and the client spawns it and speaks JSON-RPC over the process pipes. A typical client config lists the command, its arguments, and any environment it needs. Here is what that entry looks like.

{
  "mcpServers": {
    "notes": {
      "command": "node",
      "args": ["/absolute/path/to/notes-server.js"],
      "env": {
        "NOTES_DIR": "/Users/me/notes"
      }
    }
  }
}

The client starts node with that script, writes requests to its stdin, and reads responses from its stdout. Your server keeps stdout clean for protocol messages and logs to stderr, because anything you print to stdout is parsed as JSON-RPC.

How do I set up a stateless Streamable HTTP server?

For Streamable HTTP you host an endpoint. With the SDK, you create the transport with sessionIdGenerator set to undefined, which selects stateless mode: no session store, no sticky routing. You wire it to a single POST route and deploy it like any other web service.

import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";

// Stateless: no session id means any instance can serve any request.
const transport = new StreamableHTTPServerTransport({
  sessionIdGenerator: undefined,
});

await server.connect(transport);

// Hand every POST /mcp to the transport.
app.post("/mcp", (req, res) => transport.handleRequest(req, res, req.body));

The step-by-step version of this, including the wrangler.toml and a verified deploy, is in the stateless and Cloudflare Workers guides: mcporbit.com/blog/make-an-mcp-server-stateless and mcporbit.com/blog/deploy-stateless-mcp-server-cloudflare-workers. For the auth side of a remote server, see mcporbit.com/blog/add-oauth-to-remote-mcp-server.

What happened to the HTTP plus SSE transport?

The original remote transport paired an HTTP endpoint for requests with a separate, long-lived server-sent-events channel for responses. The 2026-07-28 spec deprecates it in favor of Streamable HTTP, which folds streaming into the response of each POST and drops the always-open side channel. Deprecated does not mean removed: the spec guarantees at least twelve months before it can go away, so existing SSE clients keep working while you migrate. New remote servers should start on Streamable HTTP.

Can one server support both transports?

Yes, and it is common. The transport only decides how messages arrive; your tool, resource, and prompt handlers do not change. Build the server once, then give it two entrypoints: one that connects a stdio transport for local use, and one that mounts a Streamable HTTP transport behind a route for remote use. Local developers run the command, hosted users hit the URL, and both call the same handlers.


  • Make an MCP server stateless (2026-07-28 spec): mcporbit.com/blog/make-an-mcp-server-stateless
  • Deploy a stateless MCP server to Cloudflare Workers: mcporbit.com/blog/deploy-stateless-mcp-server-cloudflare-workers
  • Add OAuth 2.1 auth to a remote MCP server: mcporbit.com/blog/add-oauth-to-remote-mcp-server
  • MCP tools vs resources vs prompts, which to use: mcporbit.com/blog/mcp-tools-vs-resources-vs-prompts

Frequently asked questions

What is the difference between stdio and Streamable HTTP in MCP?
stdio runs the server as a local subprocess that one client launches and talks to over stdin and stdout, with no network or auth. Streamable HTTP runs the server as a remote HTTP endpoint that many clients reach over the network, and under the 2026-07-28 spec it is stateless by default.
Which MCP transport should I use?
Choose by where the server runs. Use stdio for a local server that a single client owns, such as a tool that touches local files. Use Streamable HTTP for a server you deploy and share with many clients over a network.
Is the SSE transport still supported in MCP?
The older HTTP plus SSE transport is deprecated as of the 2026-07-28 spec, with a minimum twelve-month window before removal. It still works for existing clients, but new remote servers should use Streamable HTTP, which streams over each response instead of a separate channel.
Does Streamable HTTP need sessions?
No. Under the 2026-07-28 spec Streamable HTTP is stateless by default: the Mcp-Session-Id header is removed and any server instance can handle any request. You enable this by creating the transport with sessionIdGenerator set to undefined.
Can the same MCP server run on both stdio and Streamable HTTP?
Yes. The transport only changes how messages are delivered, not what your server does. Share one set of tool, resource, and prompt handlers and give the server two entrypoints, one connecting a stdio transport and one mounting a Streamable HTTP transport.
Do I need authentication for a stdio MCP server?
No. Because the client spawns the server as a local subprocess, the operating system's process trust is the boundary, so there is no auth handshake. Authentication matters for Streamable HTTP servers, which act as OAuth 2.1 resource servers with audience-bound tokens.

About the author

Mark

Head of Marketing, MCPOrbit

Mark leads marketing at MCPOrbit and writes the build-it MCP tutorials, code tested end to end before it ships.

Share this post

MCPOrbit

Test an MCP server in 60 seconds.

Download MCPOrbit for free — no account, no telemetry. Hear about a server and test it before the curiosity wears off.

macOS 14+ · Apple Silicon & Intel · No account needed