Merge pull request #3195 from jlowin/fix/stateless-http-disable-get-sse

Return 405 for GET SSE on stateless HTTP servers
This commit is contained in:
Jeremiah Lowin 2026-02-16 09:32:21 -05:00 committed by GitHub
commit b4eb1adbeb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 28 additions and 1 deletions

View file

@ -326,6 +326,11 @@ def create_streamable_http_app(
)
# Create protected HTTP endpoint route
# Stateless servers have no session tracking, so GET SSE streams
# (for server-initiated notifications) serve no purpose.
http_methods = (
["POST", "DELETE"] if stateless_http else ["GET", "POST", "DELETE"]
)
server_routes.append(
Route(
streamable_http_path,
@ -334,15 +339,17 @@ def create_streamable_http_app(
auth.required_scopes,
resource_metadata_url,
),
methods=["GET", "POST", "DELETE"],
methods=http_methods,
)
)
else:
# No auth required
http_methods = ["POST", "DELETE"] if stateless_http else None
server_routes.append(
Route(
streamable_http_path,
endpoint=streamable_http_app,
methods=http_methods,
)
)

View file

@ -231,6 +231,26 @@ async def test_elicitation_tool(streamable_http_server: str, request):
assert result.data == "You said your name was: Alice!"
@pytest.mark.parametrize("streamable_http_server", [True], indirect=True)
async def test_stateless_http_rejects_get_sse(streamable_http_server: str):
"""Stateless servers should reject GET SSE requests with 405."""
import httpx
async with httpx.AsyncClient() as http_client:
response = await http_client.get(streamable_http_server)
assert response.status_code == 405
@pytest.mark.parametrize("streamable_http_server", [True], indirect=True)
async def test_stateless_http_still_accepts_post(streamable_http_server: str):
"""Stateless servers should still handle POST requests normally."""
async with Client(
transport=StreamableHttpTransport(streamable_http_server)
) as client:
result = await client.call_tool("greet", {"name": "World"})
assert result.data == "Hello, World!"
async def test_nested_streamable_http_server_resolves_correctly(nested_server: str):
"""Test patch for https://github.com/modelcontextprotocol/python-sdk/pull/659"""
async with Client(transport=StreamableHttpTransport(nested_server)) as client: