Jeremiah Lowin commited on
Commit
9fab331
·
unverified ·
2 Parent(s): af91f4bb816fb6

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

Browse files

fix: report_progress missing passing related_request_id causes notifications not working in streaming-http

src/fastmcp/server/context.py CHANGED
@@ -122,6 +122,7 @@ class Context:
122
  progress=progress,
123
  total=total,
124
  message=message,
 
125
  )
126
 
127
  async def read_resource(self, uri: str | AnyUrl) -> list[ReadResourceContents]:
 
122
  progress=progress,
123
  total=total,
124
  message=message,
125
+ related_request_id=self.request_id,
126
  )
127
 
128
  async def read_resource(self, uri: str | AnyUrl) -> list[ReadResourceContents]:
tests/client/test_streamable_http.py CHANGED
@@ -2,13 +2,16 @@ import asyncio
2
  import json
3
  import sys
4
  from collections.abc import AsyncGenerator
 
5
 
6
  import pytest
7
  import uvicorn
8
  from mcp import McpError
 
9
  from starlette.applications import Starlette
10
  from starlette.routing import Mount
11
 
 
12
  from fastmcp.client import Client
13
  from fastmcp.client.transports import StreamableHttpTransport
14
  from fastmcp.server.dependencies import get_http_request
@@ -38,6 +41,12 @@ def fastmcp_server():
38
  await asyncio.sleep(seconds)
39
  return f"Slept for {seconds} seconds"
40
 
 
 
 
 
 
 
41
  # Add a resource
42
  @server.resource(uri="data://users")
43
  async def get_users():
@@ -63,8 +72,10 @@ def fastmcp_server():
63
  return server
64
 
65
 
66
- def run_server(host: str, port: int, **kwargs) -> None:
67
- fastmcp_server().run(host=host, port=port, **kwargs)
 
 
68
 
69
 
70
  def run_nested_server(host: str, port: int) -> None:
@@ -88,8 +99,12 @@ def run_nested_server(host: str, port: int) -> None:
88
 
89
 
90
  @pytest.fixture()
91
- async def streamable_http_server() -> AsyncGenerator[str, None]:
92
- with run_server_in_process(run_server, transport="streamable-http") as url:
 
 
 
 
93
  async with Client(transport=StreamableHttpTransport(f"{url}/mcp")) as client:
94
  assert await client.ping()
95
  yield f"{url}/mcp"
@@ -117,6 +132,24 @@ async def test_http_headers(streamable_http_server: str):
117
  assert json_result["x-demo-header"] == "ABC"
118
 
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  async def test_nested_streamable_http_server_resolves_correctly():
121
  # tests patch for
122
  # https://github.com/modelcontextprotocol/python-sdk/pull/659
 
2
  import json
3
  import sys
4
  from collections.abc import AsyncGenerator
5
+ from unittest.mock import AsyncMock
6
 
7
  import pytest
8
  import uvicorn
9
  from mcp import McpError
10
+ from mcp.types import TextContent
11
  from starlette.applications import Starlette
12
  from starlette.routing import Mount
13
 
14
+ from fastmcp import Context
15
  from fastmcp.client import Client
16
  from fastmcp.client.transports import StreamableHttpTransport
17
  from fastmcp.server.dependencies import get_http_request
 
41
  await asyncio.sleep(seconds)
42
  return f"Slept for {seconds} seconds"
43
 
44
+ @server.tool
45
+ async def greet_with_progress(name: str, ctx: Context) -> str:
46
+ """Report progress for a greeting."""
47
+ await ctx.report_progress(0.5, 1.0, "Greeting in progress")
48
+ return f"Hello, {name}!"
49
+
50
  # Add a resource
51
  @server.resource(uri="data://users")
52
  async def get_users():
 
72
  return server
73
 
74
 
75
+ def run_server(host: str, port: int, stateless_http: bool = False, **kwargs) -> None:
76
+ server = fastmcp_server()
77
+ server.settings.stateless_http = stateless_http
78
+ server.run(host=host, port=port, **kwargs)
79
 
80
 
81
  def run_nested_server(host: str, port: int) -> None:
 
99
 
100
 
101
  @pytest.fixture()
102
+ async def streamable_http_server(
103
+ stateless_http: bool = False,
104
+ ) -> AsyncGenerator[str, None]:
105
+ with run_server_in_process(
106
+ run_server, stateless_http=stateless_http, transport="streamable-http"
107
+ ) as url:
108
  async with Client(transport=StreamableHttpTransport(f"{url}/mcp")) as client:
109
  assert await client.ping()
110
  yield f"{url}/mcp"
 
132
  assert json_result["x-demo-header"] == "ABC"
133
 
134
 
135
+ @pytest.mark.parametrize("streamable_http_server", [True, False], indirect=True)
136
+ async def test_greet_with_progress_tool(streamable_http_server: str):
137
+ """Test calling the greet tool."""
138
+ progress_handler = AsyncMock(return_value=None)
139
+
140
+ async with Client(
141
+ transport=StreamableHttpTransport(streamable_http_server),
142
+ progress_handler=progress_handler,
143
+ ) as client:
144
+ result = await client.call_tool("greet_with_progress", {"name": "Alice"})
145
+
146
+ assert isinstance(result, list)
147
+ assert isinstance(result[0], TextContent)
148
+ assert result[0].text == "Hello, Alice!"
149
+
150
+ progress_handler.assert_called_once_with(0.5, 1.0, "Greeting in progress")
151
+
152
+
153
  async def test_nested_streamable_http_server_resolves_correctly():
154
  # tests patch for
155
  # https://github.com/modelcontextprotocol/python-sdk/pull/659