modelcontextprotocol / modelcontextprotocol/python-sdk
FastMCP: streamable_http_app() silently breaks when BaseHTTPMiddleware is added
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 24.3k
- Forks
- 4k
- Ø Merge
- 1 T. 1 Std.
- Gemergte PRs (30 T.)
- 31
Beschreibung
Description
Adding a Starlette BaseHTTPMiddleware (e.g., for auth) to FastMCP.streamable_http_app() silently breaks the MCP server. Every request crashes with ClosedResourceError — the client sees "peer closed connection without sending complete message body."
Reproduction
from mcp.server.fastmcp import FastMCP
from starlette.middleware.base import BaseHTTPMiddleware
mcp = FastMCP("test")
# Any BaseHTTPMiddleware — even a no-op passthrough
class AuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request, call_next):
return await call_next(request)
mcp.streamable_http_app().add_middleware(BaseHTTPMiddleware, dispatch=AuthMiddleware)
Run the server, send any MCP initialize request → ClosedResourceError.
Root cause
BaseHTTPMiddleware wraps the ASGI receive/send channels in a way incompatible with SSE streaming. This is a known Starlette limitation (encode/starlette#919), but FastMCP users hit it naturally when they reach for the obvious auth pattern.
Expected behavior
At minimum: warn at startup when a BaseHTTPMiddleware subclass is detected on a streamable HTTP app. Ideally: document prominently that users should use FastMCP's own Middleware class (fastmcp.server.middleware.Middleware) instead of Starlette's BaseHTTPMiddleware.
Workaround (raw ASGI middleware)
from starlette.types import ASGIApp, Receive, Scope, Send
class RawAuthMiddleware:
def __init__(self, app: ASGIApp):
self.app = app
async def __call__(self, scope: Scope, receive: Receive, send: Send):
# auth check here — read headers from scope
await self.app(scope, receive, send)
mcp.streamable_http_app().add_middleware(RawAuthMiddleware)
Environment
- mcp / FastMCP from
modelcontextprotocol/python-sdk - Starlette (any version — this is architectural, not a regression)
- Python 3.12
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne beim Einstiegspunkt FastMCP.streamable_http_app() und untersuche, wie Middleware um die streamable HTTP-App registriert wird. Reproduziere den Fehler mit dem no-op-BaseHTTPMiddleware-Beispiel und ermittle anschließend, wie die Erkennung beim Startup und das Warnverhalten funktionieren sollen. Als erledigt gilt die Aufgabe, wenn der Fehler klar sichtbar gemacht wird und Nutzer auf FastMCPs Middleware oder den Raw-ASGI-Workaround verwiesen werden.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- python
- Bereich
- backend-api-design
- Issue-Typ
- Bug
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-2 Tage
- Aktivitätsstatus
- Aktiv
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 64/100