From 9f4a8006d74441040617a42ac65b82a5b04d98f1 Mon Sep 17 00:00:00 2001 From: Lee Hubbard Date: Thu, 5 Feb 2026 12:22:14 -0600 Subject: [PATCH 1/3] fix: pass related_request_id in report_progress for SSE streaming Progress notifications were not being delivered to clients because related_request_id was not passed to send_progress_notification(), causing the SSE transport to drop the notification. --- src/mcp/server/mcpserver/server.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mcp/server/mcpserver/server.py b/src/mcp/server/mcpserver/server.py index 8c1fc342b..9806aa0f8 100644 --- a/src/mcp/server/mcpserver/server.py +++ b/src/mcp/server/mcpserver/server.py @@ -1052,6 +1052,7 @@ async def report_progress(self, progress: float, total: float | None = None, mes progress=progress, total=total, message=message, + related_request_id=self.request_id, ) async def read_resource(self, uri: str | AnyUrl) -> Iterable[ReadResourceContents]: From e4f97e4300243768160464cd446a9e9aa5310dc1 Mon Sep 17 00:00:00 2001 From: Akshan Krithick Date: Wed, 11 Feb 2026 12:22:12 -0800 Subject: [PATCH 2/3] test: add unit test for related_request_id in progress notifications Update existing test assertions to include related_request_id, and add a dedicated test verifying that report_progress() correctly passes the request_id as related_request_id to send_progress_notification(). --- tests/issues/test_176_progress_token.py | 39 +++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/tests/issues/test_176_progress_token.py b/tests/issues/test_176_progress_token.py index fb4bb0101..3fd5aa23f 100644 --- a/tests/issues/test_176_progress_token.py +++ b/tests/issues/test_176_progress_token.py @@ -35,6 +35,39 @@ async def test_progress_token_zero_first_call(): # Verify progress notifications assert mock_session.send_progress_notification.call_count == 3, "All progress notifications should be sent" - mock_session.send_progress_notification.assert_any_call(progress_token=0, progress=0.0, total=10.0, message=None) - mock_session.send_progress_notification.assert_any_call(progress_token=0, progress=5.0, total=10.0, message=None) - mock_session.send_progress_notification.assert_any_call(progress_token=0, progress=10.0, total=10.0, message=None) + mock_session.send_progress_notification.assert_any_call( + progress_token=0, progress=0.0, total=10.0, message=None, related_request_id="test-request" + ) + mock_session.send_progress_notification.assert_any_call( + progress_token=0, progress=5.0, total=10.0, message=None, related_request_id="test-request" + ) + mock_session.send_progress_notification.assert_any_call( + progress_token=0, progress=10.0, total=10.0, message=None, related_request_id="test-request" + ) + + +async def test_report_progress_passes_related_request_id(): + """Test that report_progress passes the request_id as related_request_id.""" + + mock_session = AsyncMock() + mock_session.send_progress_notification = AsyncMock() + + request_context = ServerRequestContext( + request_id="req-abc-123", + session=mock_session, + meta={"progress_token": "tok-1"}, + lifespan_context=None, + experimental=Experimental(), + ) + + ctx = Context(request_context=request_context, mcp_server=MagicMock()) + + await ctx.report_progress(50, 100, message="halfway") + + mock_session.send_progress_notification.assert_awaited_once_with( + progress_token="tok-1", + progress=50, + total=100, + message="halfway", + related_request_id="req-abc-123", + ) From 037098a750993ba2d0b43f794e75ba5c998710a4 Mon Sep 17 00:00:00 2001 From: Max Isbey <224885523+maxisbey@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:46:06 +0000 Subject: [PATCH 3/3] test: move related_request_id test to test_server.py Move test_report_progress_passes_related_request_id from test_176_progress_token.py (which tests falsy progress tokens) to test_server.py where Context behavior tests belong. --- tests/issues/test_176_progress_token.py | 27 ------------------- tests/server/mcpserver/test_server.py | 35 ++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/tests/issues/test_176_progress_token.py b/tests/issues/test_176_progress_token.py index 3fd5aa23f..5d5f8b8fc 100644 --- a/tests/issues/test_176_progress_token.py +++ b/tests/issues/test_176_progress_token.py @@ -44,30 +44,3 @@ async def test_progress_token_zero_first_call(): mock_session.send_progress_notification.assert_any_call( progress_token=0, progress=10.0, total=10.0, message=None, related_request_id="test-request" ) - - -async def test_report_progress_passes_related_request_id(): - """Test that report_progress passes the request_id as related_request_id.""" - - mock_session = AsyncMock() - mock_session.send_progress_notification = AsyncMock() - - request_context = ServerRequestContext( - request_id="req-abc-123", - session=mock_session, - meta={"progress_token": "tok-1"}, - lifespan_context=None, - experimental=Experimental(), - ) - - ctx = Context(request_context=request_context, mcp_server=MagicMock()) - - await ctx.report_progress(50, 100, message="halfway") - - mock_session.send_progress_notification.assert_awaited_once_with( - progress_token="tok-1", - progress=50, - total=100, - message="halfway", - related_request_id="req-abc-123", - ) diff --git a/tests/server/mcpserver/test_server.py b/tests/server/mcpserver/test_server.py index 979dc580f..84bcca667 100644 --- a/tests/server/mcpserver/test_server.py +++ b/tests/server/mcpserver/test_server.py @@ -1,7 +1,7 @@ import base64 from pathlib import Path from typing import Any -from unittest.mock import patch +from unittest.mock import AsyncMock, MagicMock, patch import pytest from inline_snapshot import snapshot @@ -10,6 +10,8 @@ from starlette.routing import Mount, Route from mcp.client import Client +from mcp.server.context import ServerRequestContext +from mcp.server.experimental.request_context import Experimental from mcp.server.mcpserver import Context, MCPServer from mcp.server.mcpserver.exceptions import ToolError from mcp.server.mcpserver.prompts.base import Message, UserMessage @@ -1415,3 +1417,34 @@ def test_streamable_http_no_redirect() -> None: # Verify path values assert streamable_routes[0].path == "/mcp", "Streamable route path should be /mcp" + + +async def test_report_progress_passes_related_request_id(): + """Test that report_progress passes the request_id as related_request_id. + + Without related_request_id, the streamable HTTP transport cannot route + progress notifications to the correct SSE stream, causing them to be + silently dropped. See #953 and #2001. + """ + mock_session = AsyncMock() + mock_session.send_progress_notification = AsyncMock() + + request_context = ServerRequestContext( + request_id="req-abc-123", + session=mock_session, + meta={"progress_token": "tok-1"}, + lifespan_context=None, + experimental=Experimental(), + ) + + ctx = Context(request_context=request_context, mcp_server=MagicMock()) + + await ctx.report_progress(50, 100, message="halfway") + + mock_session.send_progress_notification.assert_awaited_once_with( + progress_token="tok-1", + progress=50, + total=100, + message="halfway", + related_request_id="req-abc-123", + )