MCP Transport Mechanisms: STDIO vs Streamable HTTP
This writup is intended for anyone who is interested in technical details of the 2 modes of communication supported by MCP. I have also published a writeup for non technical users here. Refer to this writeup for non technical version. https://builder.aws.com/content/35A2sMpmNFpA28IOKKaBiH2Gpjl/understanding-mcp-transport-options-a-simple-non-technical-guide
For non-technical audience: https://builder.aws.com/content/35A2sMpmNFpA28IOKKaBiH2Gpjl/understanding-mcp-transport-options-a-simple-non-technical-guide
Summary
The Model Context Protocol (MCP) defines two standard transport mechanisms for client-server communication. The choice between STDIO and Streamable HTTP depends primarily on deployment context: STDIO excels for local, low-latency, single-client environments, while Streamable HTTP supports scalable, remote, multi-client scenarios.
1. MCP with STDIO Transport
Overview
STDIO transport enables communication through standard input and output streams, where the client launches the MCP server as a subprocess. The server reads JSON-RPC messages from its standard input (stdin) and sends messages to its standard output (stdout).
Technical Characteristics
Communication Protocol:
- Messages are newline-delimited JSON-RPC 2.0 format and MUST NOT contain embedded newlines
- Messages may be JSON-RPC requests, notifications, responses, or a JSON-RPC batch containing one or more requests and/or notifications
- The server MAY write UTF-8 strings to its standard error (stderr) for logging purposes. Clients MAY capture, forward, or ignore this logging
Critical Requirements:
- The server MUST NOT write anything to its stdout that is not a valid MCP message
- The client MUST NOT write anything to the server's stdin that is not a valid MCP message
Performance & Latency:
- Very low latency due to local process communication
- Bypasses network stack entirely
- Minimal overhead per connection
- Note: While the write-up mentions "microsecond-level response times," the official MCP specification does not provide specific latency benchmarks. The actual latency depends on implementation and system resources.
Deployment & Scalability:
- Limited to local, single-machine deployments
- One-to-one relationship between client and server process
- No support for remote access or concurrent clients
- Server runs as a subprocess of the client
Security:
- Clients SHOULD support stdio whenever possible
- No network exposure, inherently more secure for local operations
- Suitable for security-sensitive operations
Use Cases:
- Local CLI tools and command-line integrations
- IDE integrations (e.g., Cursor, Claude Desktop for local servers)
- Development environments
- File system operations, Git servers
- Any scenario requiring local-only access
STDIO Flow Diagram
┌─────────────────────────────────────────────────────────────┐│ STDIO Transport Flow │└─────────────────────────────────────────────────────────────┘
┌──────────┐ ┌──────────────┐│ Client │ │ MCP Server ││ Process │ │ (Subprocess)│└─────┬────┘ └──────┬───────┘ │ │ │ 1. Launch subprocess │ │───────────────────────────────────────────────>│ │ │ │ │ │ 2. Write JSON-RPC message to STDIN │ │ (newline-delimited, no embedded newlines) │ │───────────────────────────────────────────────>│ │ │ │ │ │ 3. Read JSON-RPC response from STDOUT │ │<───────────────────────────────────────────────│ │ (newline-delimited) │ │ │ │ │ │ 4. Optional: Read logs from STDERR │ │<┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄│ │ (UTF-8 strings, not MCP messages) │ │ │ │ │ │ Message Exchange Loop │ │ ╔══════════════════════════════════════╗ │ │ ║ Multiple request/response cycles ║ │ │ ║ over STDIN/STDOUT ║ │ │ ╚══════════════════════════════════════╝ │ │ │ │ │ │ 5. Close STDIN, terminate subprocess │ │───────────────────────────────────────────────>│ │ │ │ Process Exits │ │ │<───────────────────────────────────────────────┘ │ Communication Medium: Local process STDIN/STDOUTProtocol: JSON-RPC 2.0Message Format: Newline-delimited JSONConcurrency: Single client-server pairNetwork: No network stack involved
2. MCP with Streamable HTTP Transport
Overview
Streamable HTTP transport replaced the deprecated HTTP+SSE transport from protocol version 2024-11-05 (as of specification version 2025-03-26). In this transport, the server operates as an independent process that can handle multiple client connections using HTTP POST and GET requests.
Technical Characteristics
Communication Protocol:
- The server MUST provide a single HTTP endpoint path (the MCP endpoint) that supports both POST and GET methods
- The client MUST use HTTP POST to send JSON-RPC messages to the MCP endpoint
- Server can optionally make use of Server-Sent Events (SSE) to stream multiple server messages
- Messages may be JSON-RPC requests, notifications, responses, or a JSON-RPC batch containing one or more requests and/or notifications
Request/Response Handling:
- The client MUST include an Accept header, listing both application/json and text/event-stream as supported content types
- If the server accepts the input, the server MUST return HTTP status code 202 Accepted with no body
- If the input contains any number of JSON-RPC requests, the server MUST either return Content-Type: text/event-stream to initiate an SSE stream, or Content-Type: application/json to return one JSON object
Session Management:
- A server using the Streamable HTTP transport MAY assign a session ID at initialization time, by including it in an Mcp-Session-Id header on the HTTP response containing the InitializeResult
- If an Mcp-Session-Id is returned by the server during initialization, clients MUST include it in the Mcp-Session-Id header on all of their subsequent HTTP requests
Stream Resumption:
- If the client wishes to resume after a broken connection, it SHOULD issue an HTTP GET to the MCP endpoint, and include the Last-Event-ID header to indicate the last event ID it received
- The server MAY use this header to replay messages that would have been sent after the last event ID
Performance & Latency:
- Higher latency compared to STDIO due to HTTP parsing and network transmission
- Note: The write-up mentions "typically 10-50 ms" latency, but the official specification does not provide specific latency benchmarks. Actual latency varies based on network conditions and implementation.
Deployment & Scalability:
- Supports remote access and cloud deployments
- Enables multi-client concurrent connections
- Horizontal scalability through standard HTTP infrastructure
- Can be deployed behind load balancers, proxies, and CDNs
Security:
- Servers MUST validate the Origin header on all incoming connections to prevent DNS rebinding attacks
- Supports standard HTTP authentication mechanisms
- Requires HTTPS in production environments
- Infrastructure-friendly features: CORS, session pooling, authentication
Use Cases:
- Cloud services and SaaS platforms
- Web integrations and browser-based applications
- API gateways and microservices architectures
- Multi-user applications requiring concurrent access
- Remote MCP servers accessible over the internet
Streamable HTTP Flow Diagram
┌─────────────────────────────────────────────────────────────┐│ Streamable HTTP Transport Flow │└─────────────────────────────────────────────────────────────┘
┌──────────┐ ┌──────────────┐│ Client │ │ MCP Server ││ │ │ (HTTP Process)│└─────┬────┘ └──────┬───────┘ │ │ │ 1. POST /mcp (Initialize Request) │ │ Headers: │ │ Accept: application/json, text/event-stream │ Body: { method: "initialize", ... } │ │───────────────────────────────────────────────>│ │ │ │ │ │ 2. HTTP 200 OK (Initialize Response) │ │ Headers: │ │ Mcp-Session-Id: <session-uuid> │ │ Content-Type: application/json │ │ Body: { result: { capabilities: ... } } │ │<───────────────────────────────────────────────│ │ │ │ [Session ID stored for subsequent requests] │ │ │ │ │ │ 3. POST /mcp (Tool Call Request) │ │ Headers: │ │ Mcp-Session-Id: <session-uuid> │ │ Accept: application/json, text/event-stream │ Body: { method: "tools/call", params: {...}}│ │───────────────────────────────────────────────>│ │ │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ Option A: Simple JSON Response │ │ │ └─────────────────────────────────────┘ │ │ │ │ 4a. HTTP 200 OK │ │ Content-Type: application/json │ │ Body: { result: { content: [...] } } │ │<───────────────────────────────────────────────│ │ │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ Option B: Streaming SSE Response │ │ │ └─────────────────────────────────────┘ │ │ │ │ 4b. HTTP 200 OK │ │ Content-Type: text/event-stream │ │ │ │ ╔═══════════════════════════════════════╗ │ │ ║ SSE Stream (multiple events) ║ │ │<═╬═══════════════════════════════════════╬════│ │ ║ event: message ║ │ │ ║ data: { "jsonrpc": "2.0", ... } ║ │ │ ║ ║ │ │ ║ event: message ║ │ │ ║ data: { "jsonrpc": "2.0", ... } ║ │ │ ║ ║ │ │ ║ [Connection closes when complete] ║ │ │ ╚═══════════════════════════════════════╝ │ │ │ │ │ │ 5. POST /mcp (Subsequent Request) │ │ Headers: Mcp-Session-Id: <session-uuid> │ │───────────────────────────────────────────────>│ │ │ │ 6. HTTP 202 Accepted (Notification) │ │ [No response body for notifications] │ │<───────────────────────────────────────────────│ │ │ │ │ │ ┌─────────────────────────────────────┐ │ │ │ Connection Recovery (Optional) │ │ │ └─────────────────────────────────────┘ │ │ │ │ 7. GET /mcp (Resume after disconnect) │ │ Headers: │ │ Mcp-Session-Id: <session-uuid> │ │ Last-Event-ID: <last-received-id> │ │───────────────────────────────────────────────>│ │ │ │ 8. HTTP 200 OK (Resume stream) │ │ Content-Type: text/event-stream │ │ [Replays missed messages, continues stream]│ │<───────────────────────────────────────────────│ │ │
Communication Medium: HTTP/HTTPS over networkProtocol: JSON-RPC 2.0 over HTTPSingle Endpoint: /mcp for both POST and GETSession Management: Mcp-Session-Id headerStreaming: Optional Server-Sent Events (SSE)Concurrency: Multiple concurrent clients supportedSecurity: Origin validation, HTTPS, authentication
3. Comparison Summary
Feature Comparison Table
Feature | STDIO | Streamable HTTP |
|---|---|---|
Communication Medium | Local process STDIN/STDOUT | HTTP/HTTPS endpoints |
Latency | Very low (local process communication) | Moderate (network + HTTP overhead) |
Protocol | JSON-RPC 2.0 over standard streams | JSON-RPC 2.0 over HTTP |
Message Format | Newline-delimited JSON | HTTP POST/GET with JSON body |
Deployment | Local machine only | Remote/cloud/web |
Multi-client Support | No (1:1 client-server) | Yes (concurrent connections) |
Scalability | Limited (single process) | High (horizontal scaling) |
Network Exposure | None (local only) | Yes (requires security measures) |
Security | More secure (no network) | Standard HTTP security required |
Resource Usage | Low per connection | Higher per connection |
Session Management | Process lifetime | Optional Mcp-Session-Id header |
Stream Resumption | Not applicable | Supported via Last-Event-ID |
Streaming Support | Not applicable | Optional SSE streaming |
Use Cases | CLI tools, IDE, local dev | Cloud services, APIs, SaaS |
Specification Status | Standard transport | Replaced HTTP+SSE (2025-03-26) |
Decision Criteria
Choose STDIO when:
- Deploying on a single local machine
- Building IDE integrations or CLI tools
- Security and network isolation are priorities
- Low latency is critical
- Single-client usage is sufficient
- No remote access is required
Choose Streamable HTTP when:
- Deploying to cloud or remote environments
- Supporting multiple concurrent clients
- Building web applications or SaaS platforms
- Horizontal scalability is required
- Remote access is needed
- Integration with existing HTTP infrastructure (proxies, load balancers)
4. Conclusion
The Model Context Protocol provides two well-defined transport mechanisms optimized for different deployment scenarios. STDIO is recommended for local integrations whenever possible, offering minimal overhead and enhanced security. Streamable HTTP provides the flexibility and scalability needed for cloud-based, multi-user applications with proper security measures in place.
The choice between transports should be driven by deployment requirements: local vs. remote access, single vs. multiple concurrent clients, and security vs. scalability priorities. Both transports maintain the same JSON-RPC 2.0 message format and MCP protocol semantics, ensuring consistent behavior regardless of the underlying transport mechanism.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article