I’ve been working on a project to support SSE for MCP. Couldn’t find any good example on the client in Python for supporting SSE with FastAPI MCP. So I wrote it up myself and thought I will share everyone. Hope everyone find it useful.

What is the Model Context Protocol?
Model Context Protocol (MCP) is an emerging standard for communication between applications and AI models or services. It provides a structured way to:
- Establish a session between client and server
- Call model-powered tools with parameters
- Process streaming results in a standardized format
- Maintain context across multiple interactions
This protocol is particularly valuable for applications that need to interact with AI services while supporting streaming responses - a pattern that’s becoming increasingly common as models generate content incrementally.
The MCP Flow: How It Works
MCP over Server-Sent Events (SSE) creates a robust pattern for streaming AI responses: the client opens a persistent SSE connection, gets a session ID back, then sends commands as normal HTTP POSTs while results stream back over that open channel.
the mechanism — SSE session handshake and why it works give me the detail
The key insight is that SSE is half-duplex by design: the browser (or httpx/aiohttp) opens one long-lived text/event-stream GET, and the server pushes newline-delimited data: frames down it. MCP exploits this by returning a session_id in the very first SSE frame, then accepting all commands as ordinary HTTP POSTs that carry that ID as a query param. The server fans the POST response back through the already-open SSE channel — so you get full-duplex semantics without WebSockets.
┌────────┐ ┌────────┐
│ │ 1. GET /mcp (SSE connection) │ │
│ │ ──────────────────────────────────►│ │
│ │ 2. data: session_id=<uuid> │ │
│ │ ◄──────────────────────────────────│ │
│ │ 3. POST /mcp/messages/?session_id │ │
│ Client │ body: {method:"initialize"} │ Server │
│ │ ──────────────────────────────────►│ │
│ │ 4. POST /mcp/messages/?session_id │ │
│ │ body: {method:"tools/call",...} │ │
│ │ ──────────────────────────────────►│ │
│ │ 5. data: {result chunks...} │ │
│ │ ◄──────────────────────────────────│ │
└────────┘ └────────┘Under the hood, fastapi-mcp-client uses Python’s httpx with stream=True to hold the GET open, a asyncio.Queue to bridge incoming SSE frames to callers, and an asyncio.Event to signal when the session ID is ready before the first tool call fires. The server side is the mcp package’s FastApiMCPServer, which registers tools as FastAPI route handlers and writes framed JSON to the SSE response body.
Try it yourself — install the package and spin up the bundled echo server in one terminal, then connect from another:
# terminal 1 — run the example MCP server
pip install fastapi-mcp-client
python -m fastapi_mcp_client.examples.server
# terminal 2 — watch the SSE frames raw
curl -N http://localhost:8000/mcp
# you'll see: data: {"type":"session","session_id":"..."}
# then call a tool in terminal 3 and watch results stream hereIf curl -N shows a session ID and then streams data: lines when you POST a tool call, the handshake is working exactly as described.
This pattern allows for efficient, one-way streaming from server to client with a persistent connection, ideal for AI-generated content.
The Gap in the Python Ecosystem
While FastAPI supports SSE and the MCP server implementation exists, there was a significant gap:
- No dedicated Python client libraries for MCP over SSE
- Challenges in maintaining session state across requests
- Lack of examples showing proper error handling for stream interruptions
- No standardized approach for processing the streamed events
These gaps meant developers had to implement complex, error-prone boilerplate code to interact with MCP servers.
Introducing fastapi-mcp-client
The fastapi-mcp-client library solves these problems with a clean, async-first API that handles all the complexities of the MCP protocol:
import asyncio
from fastapi_mcp_client import MCPClient
async def main():
async with MCPClient("http://localhost:8000") as client:
# Standard call - simple and clean
result = await client.call_operation("echo", {"message": "Hello, MCP!"})
print(f"Echo result: {result}")
# Streaming call - same simple interface
stream = await client.call_operation(
"generate_numbers",
{"count": 5},
stream=True
)
async for event in stream:
print(f"Event: {event}")
asyncio.run(main())
The library takes care of:
- Establishing and maintaining the SSE connection
- Session management
- Protocol message formatting
- Error handling
- Processing streaming responses
Real-World Use Cases
This client excels in several scenarios:
- AI-Powered Chat Applications: Stream token-by-token responses directly to users
- Document Search Systems: Display search results as they’re discovered
- Content Generation: Show incremental progress for long-running generation tasks
- Data Processing Pipelines: Stream processed chunks rather than waiting for full completion
Getting Started
Installation is straightforward with either pip or uv:
# Install with pip
pip install fastapi-mcp-client
# Or with UV
uv add fastapi-mcp-client
The repository includes example servers and clients to help you get started quickly.
Check out the GitHub repository for more examples and documentation.