Mastering Streamable HTTP in MCP SDK: Setup, Parameters, and Real‑World Examples

This guide provides a comprehensive walkthrough of the new streamable HTTP transport mode introduced in MCP SDK v1.9.0, covering server and client configuration, core parameters, session‑id handling, sample implementations, multi‑instance deployment, and practical testing results.

AI Large Model Application Practice
AI Large Model Application Practice
AI Large Model Application Practice
Mastering Streamable HTTP in MCP SDK: Setup, Parameters, and Real‑World Examples

Since MCP SDK version 1.8.0, three transport modes are supported: stdio, sse, and streamable-http. The new streamable-http mode requires matching client and server settings; a client using this mode cannot communicate with a server configured for sse. The article explains how to enable the mode on both sides.

1. Quick Start: Enabling Streamable HTTP

On the server, use the high‑level FastMCP API and set streamable_http_path="/mcp" while disabling stateless_http and json_response unless a different behavior is desired:

# Create FastMCP instance
app = FastMCP(
    name="SimpleServer",
    port=5050,
    stateless_http=False,
    json_response=False,
    streamable_http_path="/mcp",
)
if __name__ == '__main__':
    app.run(transport='streamable-http')

The three key parameters are:

transport : set to streamable-http;

stateless_http : controls whether a long‑lived SSE channel is created (False enables it);

json_response : determines if POST responses are JSON (False yields SSE‑style streaming).

2. Client Configuration

Replace the traditional client call with streamablehttp_client and use the provided get_session_id callback to obtain the session identifier:

try:
    async with streamablehttp_client(url=server_url) as (read, write, get_session_id):
        async with ClientSession(read, write) as session:
            print("Connection successful!")
            await session.initialize()
            print("Session initialized")
            session_id = get_session_id()
            print(f"Session ID: {session_id}")
            # ... further interaction ...

Key client changes:

Use streamablehttp_client instead of the previous client module;

Call get_session_id() to retrieve the server‑generated session‑id.

3. Core Parameters Deep Dive

stateless_http decides whether an SSE channel is established (False creates it) and whether the server manages client sessions. json_response toggles the response format of POST requests; when False, responses are streamed via SSE‑style payloads. Clients must send an Accept header of application/json, text/event-stream to indicate they can handle both formats.

4. Session‑ID Mechanics

The session‑id is generated by the server when stateless_http=False and is returned in the initialization response headers. It is automatically attached to subsequent client requests and can be used to correlate multiple interactions. The session expires when the client exits the streamablehttp_client context, triggering an HTTP DELETE that removes the session on the server.

5. Sample Implementation and Verification

A simple tool named hello demonstrates a long‑running task that reports progress:

@app.tool(name='hello')
async def hello(ctx: Context, name: str) -> str:
    steps = 10
    await ctx.report_progress(0.0, steps, 'MCP Server processing...')
    for step in range(1, steps + 1):
        await asyncio.sleep(1)
        logger.info(f"Processing step {step}")
        await ctx.report_progress(float(step), float(steps), f'Step {step}...')
    await ctx.report_progress(steps, steps, 'MCP Server request completed!')
    return f'Hello, {name}'

The client runs a command‑line program that connects to http://localhost:5050/mcp, obtains the session‑id, and receives progress notifications via the SSE channel.

6. Low‑Level API Server Development

When using the low‑level API, create a StreamableHTTPSessionManager and mount it to the desired path:

session_manager = StreamableHTTPSessionManager(app=mcp_server, json_response=True, stateless=False)
starlette_app = Starlette(
    debug=True,
    routes=[Mount("/mcp", app=session_manager.handle_request)],
    lifespan=lambda app: session_manager.run(),
)
config = uvicorn.Config(starlette_app, host="127.0.0.1", port=5050)
server = uvicorn.Server(config)
await server.serve()

7. Multi‑Application Instance Mode

Multiple FastMCP instances can be created with independent configurations (e.g., one stateless, one stateful) and mounted under different URL prefixes:

app1 = FastMCP(name="SimpleServer", stateless_http=True, json_response=False)
app2 = FastMCP(name="SimpleServer2", stateless_http=False, json_response=False)
# mount both apps
server.mount("/server1", app1.streamable_http_app())
server.mount("/server2", app2.streamable_http_app())

Each instance’s session_manager must be started via a lifespan context manager. Clients connect to URLs such as http://host:port/server1/mcp.

8. Full Communication Flow

The article summarizes the end‑to‑end interaction steps:

Connection: No pre‑established SSE handshake is required.

Client sends an initialization POST; if stateful, the response includes a session‑id.

Client may perform a GET to open an SSE channel when a session‑id exists.

Normal interactions use POST; SSE is used only for server‑initiated notifications, requests, or session‑recovery streams.

Visual diagrams (omitted here) illustrate the role of red (SSE) and blue (HTTP) arrows and the conditional dashed lines that appear only in stateful mode.

Overall, the new streamable HTTP mode offers greater flexibility, allowing developers to switch between stateful and stateless configurations for better scalability, though some features like session recovery are still experimental.

backend developmentapi-designSSEFastMCPStreamable HTTPMCP SDK
AI Large Model Application Practice
Written by

AI Large Model Application Practice

Focused on deep research and development of large-model applications. Authors of "RAG Application Development and Optimization Based on Large Models" and "MCP Principles Unveiled and Development Guide". Primarily B2B, with B2C as a supplement.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.