MCP Transport Options: stdio, HTTP and When Each Fits
AI Agents

MCP Transport Options: stdio, HTTP and When Each Fits

MCP runs the same JSON-RPC messages over a local subprocess or an HTTP endpoint. The transport you pick decides your auth, scaling and debugging story.

The protocol layer of MCP is JSON-RPC, and it is identical no matter how the bytes move. What changes with the transport is everything around it: who owns the process, how you authenticate, whether you can scale horizontally, and how hard it is to see what went wrong.

There are two transports that matter in practice — a local subprocess speaking over standard input and output, and a remote HTTP endpoint. The choice is usually decided by where the data lives, not by preference.

stdio: a subprocess on the same machine

The host launches your server as a child process and exchanges newline-delimited JSON-RPC messages over its stdin and stdout. There is no network, no port, no listener.

This is the right default for anything touching local state. A server that reads the developer's working tree, runs their build, or queries a database on their laptop has no business being a network service — the data is local, and moving it over HTTP creates an attack surface for no gain.

Authentication is inherited rather than implemented. The server runs as the user who started the host, with that user's filesystem permissions and their existing credentials on disk. That is a genuine simplification, and it is also the thing to be careful about: a stdio server has whatever access its user has, which on a developer machine is usually everything. Agent sandboxing covers narrowing that.

The one implementation detail that catches everyone: stdout is the message channel, so anything else written there corrupts the stream. A stray print statement, a library that logs to stdout by default, a startup banner — each produces a connection that dies with an unhelpful parse error. Send every log line to stderr.

HTTP: a service other people can reach

The remote transport puts the same JSON-RPC messages over HTTP. The client posts a request to a single endpoint; the server replies either with a plain JSON response or with a Server-Sent Events stream when it needs to send multiple messages, such as progress notifications during a long tool call.

This is what you need when the server cannot live on the client machine: a shared internal service, a multi-tenant product, anything wrapping a system whose credentials must not be distributed to laptops. It is also the only option when the host itself is a hosted application rather than a desktop client.

Streaming responses are ordinary SSE, which means the usual infrastructure caveats apply. Proxies that buffer will make a streaming tool call look like a hang, and idle-connection timeouts will cut long operations. Streaming and server-sent events covers the failure modes, and they show up here unchanged.

Note that an earlier revision of the spec used a two-endpoint arrangement with a separate SSE channel, and some deployed servers still speak it. If you are writing a client, check which revision the servers you care about implement; if you are writing a server, implement the current one and check the specification rather than trusting a blog post about which shape is canonical.

Sessions and reconnection

Over stdio, session lifetime is process lifetime. The process starts, the connection initialises, work happens, the process exits. There is nothing to resume because there is nothing that outlives the pipe.

Over HTTP, the server may issue a session identifier during initialisation that the client returns on subsequent requests. That gives you continuity across separate HTTP requests, and it also gives you a scaling problem: if session state lives in process memory, every request in that session must reach the same instance.

The way out is to keep servers stateless and put anything that must persist behind shared storage, so any instance can serve any request. If you genuinely need in-memory session state, you need sticky routing and a defined behaviour for what happens when the instance holding it goes away. Design for reconnection explicitly — clients drop and retry, and a server that treats a reconnect as a fresh unauthenticated caller will break mid-task.

Authentication is a transport concern

This is the sharpest practical difference between the two. stdio has no authentication story because it does not need one; the process boundary and the user account are the boundary.

HTTP has all of it. You need to establish who is calling, what they are allowed to do, and how a token is obtained and refreshed. The specification describes an authorisation approach built on standard OAuth flows, and the important consequence is that a remote MCP server is an OAuth resource server with all the obligations that implies — validating tokens, scoping them properly, and never accepting a token that was issued for somebody else.

Do not paper over this with a shared secret in an environment variable across a team. A remote server without per-user identity cannot enforce per-user permissions, which means the agent effectively acts with the union of everyone's access. The MCP security model covers the trust boundaries in detail.

Debugging differs more than you expect

A stdio server fails in ways that look like nothing happening. The process exits, the host reports a closed connection, and the actual cause — a missing dependency, a crash on startup, a write to stdout — is in stderr that may or may not be surfaced. Run the server manually and pipe JSON-RPC into it before blaming the host.

An HTTP server fails in ways your existing observability can see. You get status codes, request logs, latency percentiles and traces. That is a real operational advantage and a reason some teams run HTTP even locally during development.

Whichever you use, log the JSON-RPC method and the tool name on every call. Correlating a bad agent decision with the exact tool response it received is most of the debugging work, and it is impossible after the fact if you did not record it. Agent observability and tracing covers the wider picture.

Choosing

Use stdio when the server needs local resources, when it is developer tooling, when the credentials are already on the machine, and when you want the simplest thing that works. That covers most servers people actually write.

Use HTTP when the server must be shared, when it holds credentials that cannot be distributed, when the host is itself a hosted product, or when you need centralised auditing and rate limiting. Accept that you are now running a service, with the auth, scaling and uptime obligations of one.

If you support both, keep the transport out of your handler code entirely — tools should not know how the request arrived. Most MCP SDKs make this easy, and it means a server that started as local tooling can be promoted to a shared service without a rewrite. MCP server design covers what belongs in those handlers.

Common questions

Why does my stdio MCP server disconnect immediately?

Most often because something wrote to stdout. That channel carries the JSON-RPC messages, so a print statement, a startup banner or a library logging to stdout corrupts the stream. Send all logging to stderr.

Do I need OAuth for a remote MCP server?

You need real per-user identity, and the specification builds on standard OAuth flows to provide it. A shared secret across a team means the agent acts with the union of everyone's access, so per-user permissions cannot be enforced.

Can one MCP server support both transports?

Yes, and it is worth designing for. Keep transport handling out of your tool handlers so a server written as local developer tooling can later be promoted to a shared HTTP service without rewriting the logic.

Similar articles

Building an MCP Server: A Working One in an Afternoon
AI Agents
AI Agents·9 min read

Building an MCP Server: A Working One in an Afternoon

A practical walkthrough of writing your first MCP server: choosing the tools, wiring the transport, handling errors, and testing it with a real agent.

Read
MCP Server Design: Fewer Tools, Sharper Boundaries
AI Agents
AI Agents·9 min read

MCP Server Design: Fewer Tools, Sharper Boundaries

Most MCP servers are a thin wrapper around an existing API, which is why agents use them badly. Design rules for servers models can actually operate.

Read
MCP vs Plain Tool Calling: When the Protocol Earns Its Keep
AI Agents
AI Agents·8 min read

MCP vs Plain Tool Calling: When the Protocol Earns Its Keep

MCP and a plain function schema look identical to the model. The difference is who owns the integration, and that decides which one you should use.

Read