Skip to content

Commit 47f4f75

Browse files
committed
fix resource
1 parent 301aa96 commit 47f4f75

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

src/mcp/server/fastmcp/resources/types.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,12 @@ class FunctionResource(Resource):
5454
async def read(self) -> str | bytes:
5555
"""Read the resource by calling the wrapped function."""
5656
try:
57-
result = await self.fn() if inspect.iscoroutinefunction(self.fn) else self.fn()
57+
# Call the function first to see if it returns a coroutine
58+
result = self.fn()
59+
# If it's a coroutine, await it
60+
if inspect.iscoroutine(result):
61+
result = await result
62+
5863
if isinstance(result, Resource):
5964
return await result.read()
6065
elif isinstance(result, bytes):

tests/issues/test_188_concurrency.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
import anyio
22
import pytest
3+
from pydantic import AnyUrl
34

45
from mcp.server.fastmcp import FastMCP
56
from mcp.shared.memory import create_connected_server_and_client_session as create_session
67

8+
_resource_name = "slow://slow_resource"
9+
710

811
@pytest.mark.anyio
9-
async def test_messages_are_executed_concurrently():
12+
async def test_messages_are_executed_concurrently_tools():
1013
server = FastMCP("test")
1114
event = anyio.Event()
1215
tool_started = anyio.Event()
@@ -44,3 +47,42 @@ async def trigger():
4447
"trigger_end",
4548
"tool_end",
4649
], f"Expected concurrent execution, but got: {call_order}"
50+
51+
52+
@pytest.mark.anyio
53+
async def test_messages_are_executed_concurrently_tools_and_resources():
54+
server = FastMCP("test")
55+
event = anyio.Event()
56+
tool_started = anyio.Event()
57+
call_order = []
58+
59+
@server.tool("sleep")
60+
async def sleep_tool():
61+
call_order.append("waiting_for_event")
62+
tool_started.set()
63+
await event.wait()
64+
call_order.append("tool_end")
65+
return "done"
66+
67+
@server.resource(_resource_name)
68+
async def slow_resource():
69+
# Wait for tool to start before setting the event
70+
await tool_started.wait()
71+
event.set()
72+
call_order.append("resource_end")
73+
return "slow"
74+
75+
async with create_session(server._mcp_server) as client_session:
76+
# First tool will wait on event, second will set it
77+
async with anyio.create_task_group() as tg:
78+
# Start the tool first (it will wait on event)
79+
tg.start_soon(client_session.call_tool, "sleep")
80+
# Then the resource (it will set the event)
81+
tg.start_soon(client_session.read_resource, AnyUrl(_resource_name))
82+
83+
# Verify that both ran concurrently
84+
assert call_order == [
85+
"waiting_for_event",
86+
"resource_end",
87+
"tool_end",
88+
], f"Expected concurrent execution, but got: {call_order}"

0 commit comments

Comments
 (0)