modelcontextprotocol / modelcontextprotocol/python-sdk
FastMCP: streamable_http_app() silently breaks when BaseHTTPMiddleware is added
Ninguém assumiu esta issue ainda.
- Linguagem predominante
- Python
- Estrelas
- 24.3k
- Forks
- 4k
- Merge médio
- 1d 1h
- PRs com merge (30d)
- 31
Descrição
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
Guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Direção de pesquisa
Comece pelo ponto de entrada FastMCP.streamable_http_app() e inspecione como o middleware é registrado ao redor do app HTTP streamable. Reproduza a falha com o exemplo no-op de BaseHTTPMiddleware e, em seguida, determine como a detecção na inicialização e o comportamento dos avisos devem funcionar. Considera-se concluído quando a falha é exposta claramente e os usuários são direcionados ao Middleware do FastMCP ou à solução alternativa de ASGI bruto.
Escrita pelo modelo de indexação a partir do texto da issue.
Avaliação
- Stack de tecnologia
- python
- Domínio
- backend-api-design
- Tipo de issue
- Bug
- Dificuldade
- 3/5
- Tempo estimado
- 1-2 dias
- Status de atividade
- Ativa
- Clareza
- Razoavelmente clara
- Facilidade para iniciantes
- 64/100