From b0ee1a47f21b5180f4a3b4860f943bb9cd62ade4 Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Thu, 5 Mar 2026 16:53:31 -0700 Subject: [PATCH 1/3] fix: add warning log when rejecting unknown/expired session ID Fixes #2204 --- src/mcp/server/streamable_http_manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mcp/server/streamable_http_manager.py b/src/mcp/server/streamable_http_manager.py index 50bcd5e79..cca58395e 100644 --- a/src/mcp/server/streamable_http_manager.py +++ b/src/mcp/server/streamable_http_manager.py @@ -225,7 +225,7 @@ async def run_server(*, task_status: TaskStatus[None] = anyio.TASK_STATUS_IGNORE read_stream, write_stream = streams task_status.started() try: - # Use a cancel scope for idle timeout — when the + # Use a cancel scope for idle timeout \u2014 when the # deadline passes the scope cancels app.run() and # execution continues after the ``with`` block. # Incoming requests push the deadline forward. @@ -272,6 +272,7 @@ async def run_server(*, task_status: TaskStatus[None] = anyio.TASK_STATUS_IGNORE # Unknown or expired session ID - return 404 per MCP spec # TODO: Align error code once spec clarifies # See: https://github.com/modelcontextprotocol/python-sdk/issues/1821 + logger.warning("Rejected request with unknown or expired session ID: %s", request_mcp_session_id) error_response = JSONRPCError( jsonrpc="2.0", id=None, From 9b50b0dd442d8194f2f17582e4fadc7d7896c06e Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Thu, 5 Mar 2026 16:54:36 -0700 Subject: [PATCH 2/3] test: verify warning log for unknown session ID --- tests/server/test_streamable_http_manager.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/server/test_streamable_http_manager.py b/tests/server/test_streamable_http_manager.py index 54a898cc5..924df55dc 100644 --- a/tests/server/test_streamable_http_manager.py +++ b/tests/server/test_streamable_http_manager.py @@ -1,6 +1,7 @@ """Tests for StreamableHTTPSessionManager.""" import json +import logging from typing import Any from unittest.mock import AsyncMock, patch @@ -269,7 +270,7 @@ async def mock_receive(): @pytest.mark.anyio -async def test_unknown_session_id_returns_404(): +async def test_unknown_session_id_returns_404(caplog: pytest.LogCaptureFixture): """Test that requests with unknown session IDs return HTTP 404 per MCP spec.""" app = Server("test-unknown-session") manager = StreamableHTTPSessionManager(app=app) @@ -299,7 +300,8 @@ async def mock_send(message: Message): async def mock_receive(): return {"type": "http.request", "body": b"{}", "more_body": False} # pragma: no cover - await manager.handle_request(scope, mock_receive, mock_send) + with caplog.at_level(logging.WARNING, logger="mcp.server.streamable_http_manager"): + await manager.handle_request(scope, mock_receive, mock_send) # Find the response start message response_start = next( @@ -316,6 +318,11 @@ async def mock_receive(): assert error_data["error"]["code"] == INVALID_REQUEST assert error_data["error"]["message"] == "Session not found" + # Verify warning was logged with the session ID + assert any( + "non-existent-session-id" in record.message for record in caplog.records + ), "Should log a warning with the unknown session ID" + @pytest.mark.anyio async def test_e2e_streamable_http_server_cleanup(): From 0becf183f5fe60be45150b54ee6d030622efed4b Mon Sep 17 00:00:00 2001 From: Daniel Pittman Date: Thu, 5 Mar 2026 17:07:15 -0700 Subject: [PATCH 3/3] style: reformat assert to satisfy ruff --- tests/server/test_streamable_http_manager.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/server/test_streamable_http_manager.py b/tests/server/test_streamable_http_manager.py index 924df55dc..68a845df4 100644 --- a/tests/server/test_streamable_http_manager.py +++ b/tests/server/test_streamable_http_manager.py @@ -319,9 +319,9 @@ async def mock_receive(): assert error_data["error"]["message"] == "Session not found" # Verify warning was logged with the session ID - assert any( - "non-existent-session-id" in record.message for record in caplog.records - ), "Should log a warning with the unknown session ID" + assert any("non-existent-session-id" in record.message for record in caplog.records), ( + "Should log a warning with the unknown session ID" + ) @pytest.mark.anyio