Streamable HTTP server never returns the spec-mandated 405 for GET requests it won't serve as SSE (406/400 instead) — breaks client SSE-probe fallback
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Accessibilité débutants
- 58/100
- Type d'issue
- Bug
- Clarté
- Plutôt claire
- Activité
- Calme
- Stack technique
- python
- Domaine
- api, backend, networking
Piste de recherche
Commencez par reproduire les deux requêtes curl décrites dans l’issue, puis suivez les points d’entrée du serveur HTTP streamable _handle_get_request, _check_accept_headers et _validate_session. Vérifiez le comportement de GET avant la session ainsi que les cas de l’en-tête Accept, puis ajoutez ou mettez à jour la couverture afin qu’un GET non pris en charge renvoie 405 avec un en-tête Allow, tout en préservant la gestion valide de SSE.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Summary
The streamable-HTTP server transport never answers a GET it won't serve with 405 Method Not Allowed, even though the spec makes 405 the required signal:
The server MUST either return
Content-Type: text/event-streamin response to this HTTP GET, or else return HTTP 405 Method Not Allowed, indicating that the server does not offer an SSE stream at this endpoint.
— Streamable HTTP § Listening for Messages from the Server
Instead, a GET that can't be served yields:
Pre-session GET /mcp with… |
Server response |
|---|---|
Accept: */*, Accept: application/json, or no Accept |
406 Not Acceptable (_handle_get_request → _check_accept_headers, which does literal prefix matching so */* is not honored) |
Accept: text/event-stream (stateful server, no mcp-session-id) |
400 Bad Request: Missing session ID (_validate_session) |
So in stateful mode there is no request shape for which a pre-session GET returns 405. (405 is used elsewhere: DELETE without a session and unsupported methods.)
Why it matters — real interop break
Several client transports probe with exactly this GET before initialize to ask "do you offer a standalone SSE stream?", and treat only 405 as the graceful "no SSE — fall through to POST" signal (e.g. the TypeScript SDK's _startOrAuthSse explicitly special-cases 405). Any other status is a transport error, so against a stock python-SDK server the connection aborts before initialize is ever sent.
We hit this in production between two independently-built agents: the client authenticated successfully, then its GET probe got 406 (its relay sent Accept: */*), the transport threw, and the handshake never reached initialize — surfacing as "server doesn't respond to MCP protocol" while the server looked perfectly healthy to every python-SDK client (which only GETs after initialize, with a session id). We've deployed a workaround (a small ASGI shim returning 405 + Allow: POST for session-less GETs on the MCP path), but every stock python-SDK deployment presumably reproduces this.
Repro (mcp 1.28.1, stateful StreamableHTTP server)
curl -i -X GET http://localhost:8000/mcp -H 'Accept: */*' # → 406, expected 405
curl -i -X GET http://localhost:8000/mcp -H 'Accept: text/event-stream' # → 400, expected 405 (no session yet)
Suggested behavior
For a GET the server cannot serve as an SSE stream, respond 405 with an Allow header per the spec quote above — at minimum for the pre-session case (no mcp-session-id), where returning 400 makes the spec'd client probe impossible to satisfy. Separately (or as part of this), _check_accept_headers honoring */* / text/* per RFC 9110 §12.5.1 would remove the 406 arm for wildcard clients.
Related
- #2349 covers the POST-side strict dual-Accept requirement; this issue is about the GET/405 contract, which is distinct.
- #1641 raised wildcard-Accept non-compliance and is closed, but on 1.28.1
_check_accept_headersstill does literal prefix matching, and the GET path 406s wildcard clients.
Happy to provide full header traces or a PR if the maintainers agree on the intended shape.
- Langage dominant
- Python
- Étoiles
- 24.3k
- Forks
- 4k
- Merge moyen
- 1 j 11 h
- PR mergées (30 j)
- 30
Guide de contribution
Ouvrir le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de modelcontextprotocol/python-sdk
-
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
modelcontextprotocol/python-sdk#3566 ·
-
Streamable HTTP client logs a WARNING for valid 202 Accepted on session termination (DELETE) Ouvertev1 v2
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
modelcontextprotocol/python-sdk#3546 · 5 commentaires ·
-
v1 v2
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
modelcontextprotocol/python-sdk#3545 · 1 commentaire ·
-
v1 v2
Difficulté 1/5 Moins d'une heure Accessibilité débutants 91/100
modelcontextprotocol/python-sdk#3508 · 2 commentaires ·
-
Difficulté 2/5 1-3 heures Accessibilité débutants 64/100
modelcontextprotocol/python-sdk#3504 ·
Toutes les issues de modelcontextprotocol/python-sdk
Issues similaires
-
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
anthropics/skills#1811 · 1 commentaire ·
-
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
speaches-ai/speaches#678 ·
-
bug
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
datalayer/mcp-compose#42 ·
-
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
conda-forge/spacy-feedstock#177 ·
-
Difficulté 2/5 1-3 heures Accessibilité débutants 70/100
UKGovernmentBEIS/inspect_evals#2523 ·