Skip to main content

4. MCP StreamableHTTP Transport Protocol

Date: 2025-10-11

Status

Accepted

Category

Core Architecture

Context

The Model Context Protocol (MCP) needs a transport layer to communicate between clients and servers. The original MCP specification supported two transports:
  1. stdio: Standard input/output (pipes)
  2. SSE (Server-Sent Events): HTTP-based streaming
However, the MCP specification evolved to introduce StreamableHTTP, which offers significant improvements over SSE:
  • True bidirectional communication
  • Better error handling
  • More efficient streaming
  • Modern HTTP semantics
  • Broader client support
Use cases for different transports:
  • stdio: Claude Desktop app, local CLI tools
  • StreamableHTTP: Web clients, cloud deployments, production services
We need to choose which transport(s) to support as our primary production interface.

Decision

We will support two MCP server implementations:
  1. src/mcp_server_langgraph/mcp/server_streamable.py (PRIMARY - StreamableHTTP)
    • Modern StreamableHTTP transport
    • Production-recommended
    • Full HTTP features (CORS, auth headers, rate limiting)
    • Port 8000
  2. src/mcp_server_langgraph/mcp/server_stdio.py (stdio)
    • For Claude Desktop integration
    • Local development tool
    • No network overhead
Default: StreamableHTTP for all production deployments Note: The SSE transport (mcp_server_http.py) was removed on 2025-10-11 as it was deprecated and no longer needed.

Consequences

Positive Consequences

  • Future-Proof: Aligned with latest MCP specification
  • Better Streaming: More efficient than SSE
  • Bidirectional: Client can stream to server
  • Standard HTTP: Works with existing HTTP infrastructure
  • Cloud-Ready: Ideal for Kubernetes/Docker deployments
  • Health Checks: Built-in /health endpoints
  • API Docs: FastAPI auto-generates OpenAPI docs
  • Flexibility: Multiple transports for different use cases

Negative Consequences

  • Multiple Servers: Two separate server files to maintain
  • Confusion: Users must choose correct server (stdio vs StreamableHTTP)
  • Documentation: Must explain when to use each transport

Neutral Consequences

  • Code Duplication: Some shared logic across servers (mitigated with imports)
  • Testing: Must test both transports

Alternatives Considered

1. stdio Only

Description: Only support stdio transport Pros:
  • Simplest implementation
  • Perfect for Claude Desktop
  • No network complexity
  • Lowest latency
Cons:
  • Can’t deploy to cloud
  • No web client support
  • No remote access
  • Not scalable
Why Rejected: Insufficient for production deployments

2. SSE Only

Description: Only support SSE transport Pros:
  • HTTP-based
  • Good browser support
  • Simpler than bidirectional
Cons:
  • Deprecated in MCP spec
  • Unidirectional only
  • Less efficient
  • Not future-proof
Why Rejected: MCP spec moved away from SSE

3. WebSocket

Description: Use WebSocket instead of StreamableHTTP Pros:
  • Truly bidirectional
  • Real-time
  • Efficient
Cons:
  • Not in MCP specification
  • More complex protocol
  • Harder to debug
  • Connection management overhead
Why Rejected: Not part of MCP standard

4. gRPC

Description: Use gRPC for transport Pros:
  • Very efficient
  • Bidirectional streaming
  • Type-safe
Cons:
  • Not in MCP spec
  • Complex setup
  • Poor browser support
  • Requires protobuf
Why Rejected: Incompatible with MCP spec

5. Single Unified Server

Description: One server supporting multiple transports Pros:
  • Single codebase
  • Easier to maintain
  • Less confusion
Cons:
  • Complex implementation
  • Port conflicts
  • Harder to configure
  • Mixed concerns
Why Rejected: Cleaner to separate by transport

Implementation Details

StreamableHTTP Server (Primary)

# src/mcp_server_langgraph/mcp/server_streamable.py
app = FastAPI(title="MCP Server with LangGraph")

@app.post("/mcp")
async def handle_mcp_request(request: Request):
    # StreamableHTTP handler
    ...

@app.get("/health")
async def health_check():
    return {"status": "healthy"}

stdio Server

# src/mcp_server_langgraph/mcp/server_stdio.py
async def main():
    server = Server("mcp-server-langgraph")
    # stdio transport
    async with stdio_server() as streams:
        await server.run(streams[0], streams[1])

Docker Configuration

# Dockerfile
CMD ["python", "src/mcp_server_langgraph/mcp/server_streamable.py"]  # Default to StreamableHTTP

Usage Examples

# Production: StreamableHTTP
python -m mcp_server_langgraph.mcp.server_streamable
# → http://localhost:8000

# Claude Desktop: stdio
python -m mcp_server_langgraph.mcp.server_stdio
# → stdio communication

Client Configuration

// Claude Desktop config (.claude_desktop_config.json)
{
  "mcpServers": {
    "langgraph-agent": {
      "command": "python",
      "args": ["src/mcp_server_langgraph/mcp/server_stdio.py"]  // stdio transport
    }
  }
}

Migration Path

Phase 1

  • All three transports supported
  • StreamableHTTP recommended
  • SSE marked as deprecated

Phase 2 (6 months)

  • SSE warnings in logs
  • Documentation updated
  • Migration guide published

Phase 3 (COMPLETED 2025-10-11)

  • ✅ Removed SSE server (mcp_server_http.py)
  • ✅ Only StreamableHTTP + stdio remain
  • ✅ Removed sse-starlette dependency

References

Changelog

  • 2025-10-11: Removed SSE transport (mcp_server_http.py) and sse-starlette dependency. Updated decision to reflect two transports only (StreamableHTTP + stdio).