MCP Transport: stdio vs Streamable HTTP
How stdio Transport Works
With stdio transport, the MCP client launches the server as a child process using a shell command (like python server.py or node dist/index.js). The client writes JSON-RPC messages to the server's standard input, and the server writes responses to its standard output. Standard error is available for logging and debugging, separate from the protocol messages.
The server process starts when the client opens a session and stops when the session ends. The server inherits the user's environment variables, filesystem access, and network permissions. There is no network traffic because all communication happens through OS-level pipes between parent and child processes.
This simplicity is stdio's main advantage. No network configuration, no port management, no TLS certificates, no DNS, no firewall rules. The server process runs on the same machine as the client with the same security context. For development tools that need access to local files, local databases, or local environment variables, stdio is the natural choice because the server already has everything it needs.
The limitations are equally straightforward. A stdio server cannot serve multiple clients simultaneously because it is tied to one parent process. It cannot persist between sessions because it starts and stops with the client. It cannot run on a different machine because it must be launchable as a local subprocess. And it cannot be shared with other users because it runs under a single user's account.
How Streamable HTTP Transport Works
With Streamable HTTP, the MCP server runs as a standard HTTP service that listens on a port and accepts incoming requests. Clients send JSON-RPC messages as HTTP POST requests to the server's endpoint. The server processes each request and returns the result as an HTTP response. For operations that produce streaming output, the server can use standard HTTP streaming mechanisms.
The server runs independently of any client. It starts on its own (or through a container orchestrator), stays running between client sessions, and can serve multiple clients simultaneously. Clients connect by URL, so the server can run anywhere: on the same machine, on a different machine in the same network, or in the cloud behind a public endpoint.
Streamable HTTP replaced the earlier SSE (Server-Sent Events) transport that was part of the original MCP specification. SSE used a persistent connection for streaming results from server to client. Streamable HTTP handles the same use case through standard HTTP response streaming, which is simpler, better supported by proxies and load balancers, and does not require a persistent connection.
Choosing the Right Transport
Use stdio when:
- The server needs local filesystem access (file managers, git tools, code analyzers)
- The server needs local environment variables or credentials (development secrets, local database connections)
- Only one user needs the server at a time
- The server has no state that needs to persist between sessions
- You want the simplest possible setup with no infrastructure
Use Streamable HTTP when:
- Multiple users or clients need to connect to the same server
- The server manages state that must persist across sessions (memory stores, databases, caches)
- The server should run independently from any specific client
- You need authentication and access control (API keys, OAuth)
- You need to deploy, monitor, and scale the server as a production service
Performance Comparison
stdio has lower latency per message because there is no network overhead. Messages flow through OS pipes, which typically add microseconds of latency. HTTP adds network round-trip time (milliseconds for local, more for remote), TLS handshake overhead (on first connection), and HTTP header overhead per request.
For most MCP use cases, the difference is negligible. A tool invocation that takes 100 milliseconds to execute does not benefit meaningfully from saving 2 milliseconds on transport. The transport latency becomes noticeable only for tools that are very fast (under 5 milliseconds) and called very frequently (dozens of times per second). In practice, most MCP tools involve I/O operations (database queries, file reads, API calls) that dominate the response time.
stdio also has lower memory overhead per connection because there is no HTTP server process, no connection pool, and no TLS state to maintain. A stdio server is just a process reading from stdin and writing to stdout. An HTTP server needs a web framework, a connection manager, and optionally a TLS library. For simple servers, this difference matters; for servers with meaningful business logic, the framework overhead is a small fraction of total memory use.
Security Implications
stdio servers inherit the security context of the user who starts the client. The server can access anything the user can access: files, databases, network resources, and environment variables. This is appropriate for personal development tools but problematic for shared or sensitive resources. There is no way to restrict a stdio server's access beyond what the user's OS permissions allow.
HTTP servers support explicit authentication and authorization. You can require API keys, validate OAuth tokens, enforce per-user scopes, and audit access. You can also restrict the server's own access to backend resources using service accounts with minimal privileges. The security boundary is explicit and configurable rather than inherited from the user's session.
For production deployments that handle user data, HTTP transport with authentication is the correct choice. For personal development tools that only need local access, stdio's inherited security is simpler and sufficient.
Migration Path
A well-designed MCP server separates tool logic from transport. The tool functions are independent of how they are invoked. The transport layer is just the entry point that receives requests, dispatches them to tool handlers, and returns results. This means you can start with stdio for development and switch to HTTP for production without rewriting any tool logic.
Both the Python and TypeScript SDKs support this separation. In Python with FastMCP, the transport is a single parameter on the run() call. In TypeScript, you swap the transport class and add an HTTP server wrapper. The tool registrations, handler functions, and business logic remain identical.
Adaptive Recall uses HTTP transport exclusively because the memory service must persist between sessions, serve multiple users, and run as a managed cloud service. Local development tools that work with your filesystem or local databases should start with stdio and only migrate to HTTP if they need multi-user access or remote deployment.
Connect to a production memory server over HTTP. Adaptive Recall handles transport, authentication, and scaling so you focus on your tools.
Get Started Free