fix: return 405 for pre-session GET the server won't serve as SSE
Closes #3102
Summary
Per the Streamable HTTP transport spec (Listening for Messages from the Server):
The server MUST either return Content-Type: text/event-stream in 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.
In stateful mode, a pre-session GET (no mcp-session-id header) returned 400 Bad Request: Missing session ID instead. Since client transports that probe for a standalone SSE stream before initialize treat only 405 as the graceful "no SSE — fall back to POST" signal (e.g. the TypeScript SDK's _startOrAuthSse), any other status aborts the handshake — the interop break described in #3102 (credit to @fgranata for the thorough root-cause analysis).
The 406-for-wildcard-Accept arm of the report is already fixed on main via check_accept_headers; this PR addresses the remaining 400 path.
Changes
_handle_get_request: a session-less GET in stateful mode now returns 405 withAllow: GET, POST, DELETE(matching_handle_unsupported_request), before Accept validation — the spec's requirement applies to any GET the server won't serve as SSE, regardless of Accept header.- New regression test covering the client-probe shapes (
Accept: */*,application/json, absent,text/event-stream), asserting status,Allowheader, and JSON-RPC error code. - Updated one existing test that asserted the old 400 behavior.
Backward compatibility
Post-session GETs (valid mcp-session-id + SSE Accept) are unchanged and still serve SSE. Stateless mode is unaffected. POST/DELETE session validation is unchanged.