| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Offload synchronous function calls to a thread to prevent blocking the event loop. This change ensures that context is correctly propagated using anyio's run_sync.
There was a problem hiding this comment.
1 issue found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/mcp/server/fastmcp/utilities/func_metadata.py">
<violation number="1" location="src/mcp/server/fastmcp/utilities/func_metadata.py:96">
P1: Add the missing `anyio` import before using `anyio.to_thread.run_sync`; otherwise every synchronous tool call fails at runtime.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
Sorry, something went wrong.
| return await fn(**arguments_parsed_dict) | ||
| else: | ||
| return fn(**arguments_parsed_dict) | ||
| return await anyio.to_thread.run_sync(lambda: fn(**arguments_parsed_dict)) |
There was a problem hiding this comment.
P1: Add the missing anyio import before using anyio.to_thread.run_sync; otherwise every synchronous tool call fails at runtime.
Prompt for AI agentsCheck if this issue is valid — if so, understand the root cause and fix it. At src/mcp/server/fastmcp/utilities/func_metadata.py, line 96:
<comment>Add the missing `anyio` import before using `anyio.to_thread.run_sync`; otherwise every synchronous tool call fails at runtime.</comment>
<file context>
@@ -93,7 +93,11 @@ async def call_fn_with_arg_validation(
return await fn(**arguments_parsed_dict)
else:
- return fn(**arguments_parsed_dict)
+ return await anyio.to_thread.run_sync(lambda: fn(**arguments_parsed_dict))
+ # Sync functions are offloaded to a thread to avoid blocking the event loop.
+ # anyio.to_thread.run_sync() uses copy_context() internally, so contextvars
</file context>
Sorry, something went wrong.
|
Thanks for the PR. This has since landed via #1909. I'm closing this out as part of a backlog cleanup now that v2 is out. Feel free to reopen if this is still relevant. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Summary
Sync tool functions registered with FastMCP were called directly on the
asyncio event loop, blocking it for the duration of the call. Any sync
tool performing I/O (e.g. using requests, time.sleep, file reads)
would stall all other concurrent tasks on the same server.
Change
In call_fn_with_arg_validation (src/mcp/server/fastmcp/utilities/func_metadata.py),
wrap sync calls with anyio.to_thread.run_sync() instead of calling
them directly:
Before:
After:
This is consistent with how FastAPI handles sync route handlers, and how
FileResource and DirectoryResource already handle blocking reads
within this codebase.
anyio.to_thread.run_sync() uses copy_context() internally so
contextvars propagate correctly to the worker thread. The MCP Context
object is unaffected as it is passed explicitly via
arguments_to_pass_directly.
Testing
Added a test that registers a sync tool using time.sleep and asserts
that two concurrent calls complete in roughly the time of one sleep,
confirming they run in parallel without blocking the event loop.
Closes #1839