Merge pull request #838 from alexsee/alexsee/fix/report-progress-missing-related-request-id

fix: report_progress missing passing related_request_id causes notifications not working in streaming-http
This commit is contained in:
Jeremiah Lowin 2025-06-15 12:34:55 -04:00 committed by GitHub
commit df78b2171d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 38 additions and 4 deletions

View file

@ -122,6 +122,7 @@ class Context:
progress=progress,
total=total,
message=message,
related_request_id=self.request_id,
)
async def read_resource(self, uri: str | AnyUrl) -> list[ReadResourceContents]:

View file

@ -2,13 +2,16 @@ import asyncio
import json
import sys
from collections.abc import AsyncGenerator
from unittest.mock import AsyncMock
import pytest
import uvicorn
from mcp import McpError
from mcp.types import TextContent
from starlette.applications import Starlette
from starlette.routing import Mount
from fastmcp import Context
from fastmcp.client import Client
from fastmcp.client.transports import StreamableHttpTransport
from fastmcp.server.dependencies import get_http_request
@ -38,6 +41,12 @@ def fastmcp_server():
await asyncio.sleep(seconds)
return f"Slept for {seconds} seconds"
@server.tool
async def greet_with_progress(name: str, ctx: Context) -> str:
"""Report progress for a greeting."""
await ctx.report_progress(0.5, 1.0, "Greeting in progress")
return f"Hello, {name}!"
# Add a resource
@server.resource(uri="data://users")
async def get_users():
@ -63,8 +72,10 @@ def fastmcp_server():
return server
def run_server(host: str, port: int, **kwargs) -> None:
fastmcp_server().run(host=host, port=port, **kwargs)
def run_server(host: str, port: int, stateless_http: bool = False, **kwargs) -> None:
server = fastmcp_server()
server.settings.stateless_http = stateless_http
server.run(host=host, port=port, **kwargs)
def run_nested_server(host: str, port: int) -> None:
@ -88,8 +99,12 @@ def run_nested_server(host: str, port: int) -> None:
@pytest.fixture()
async def streamable_http_server() -> AsyncGenerator[str, None]:
with run_server_in_process(run_server, transport="streamable-http") as url:
async def streamable_http_server(
stateless_http: bool = False,
) -> AsyncGenerator[str, None]:
with run_server_in_process(
run_server, stateless_http=stateless_http, transport="streamable-http"
) as url:
async with Client(transport=StreamableHttpTransport(f"{url}/mcp")) as client:
assert await client.ping()
yield f"{url}/mcp"
@ -117,6 +132,24 @@ async def test_http_headers(streamable_http_server: str):
assert json_result["x-demo-header"] == "ABC"
@pytest.mark.parametrize("streamable_http_server", [True, False], indirect=True)
async def test_greet_with_progress_tool(streamable_http_server: str):
"""Test calling the greet tool."""
progress_handler = AsyncMock(return_value=None)
async with Client(
transport=StreamableHttpTransport(streamable_http_server),
progress_handler=progress_handler,
) as client:
result = await client.call_tool("greet_with_progress", {"name": "Alice"})
assert isinstance(result, list)
assert isinstance(result[0], TextContent)
assert result[0].text == "Hello, Alice!"
progress_handler.assert_called_once_with(0.5, 1.0, "Greeting in progress")
async def test_nested_streamable_http_server_resolves_correctly():
# tests patch for
# https://github.com/modelcontextprotocol/python-sdk/pull/659