mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-23 14:04:18 +02:00
Update docs to reflect sync tools (#1234)
This commit is contained in:
parent
126dd7b16a
commit
f4c0beca27
1 changed files with 55 additions and 27 deletions
|
|
@ -108,6 +108,61 @@ def search_products_implementation(query: str, category: str | None = None) -> l
|
|||
</Expandable>
|
||||
</ParamField>
|
||||
</Card>
|
||||
|
||||
|
||||
### Async and Synchronous Tools
|
||||
|
||||
FastMCP is an async-first framework that seamlessly supports both asynchronous (`async def`) and synchronous (`def`) functions as tools. Async tools are preferred for I/O-bound operations to keep your server responsive.
|
||||
|
||||
While synchronous tools work seamlessly in FastMCP, they can block the event loop during execution. For CPU-intensive or potentially blocking synchronous operations, consider alternative strategies. One approach is to use `anyio` (which FastMCP already uses internally) to wrap them as async functions, for example:
|
||||
|
||||
```python {1, 13}
|
||||
import anyio
|
||||
from fastmcp import FastMCP
|
||||
|
||||
mcp = FastMCP()
|
||||
|
||||
def cpu_intensive_task(data: str) -> str:
|
||||
# Some heavy computation that could block the event loop
|
||||
return processed_data
|
||||
|
||||
@mcp.tool
|
||||
async def wrapped_cpu_task(data: str) -> str:
|
||||
"""CPU-intensive task wrapped to prevent blocking."""
|
||||
return await anyio.to_thread.run_sync(cpu_intensive_task, data)
|
||||
```
|
||||
|
||||
Alternative approaches include using `asyncio.get_event_loop().run_in_executor()` or other threading techniques to manage blocking operations without impacting server responsiveness. For example, here's a recipe for using the `asyncer` library (not included in FastMCP) to create a decorator that wraps synchronous functions, courtesy of [@hsheth2](https://github.com/jlowin/fastmcp/issues/864#issuecomment-3103678258):
|
||||
|
||||
<CodeGroup>
|
||||
```python Decorator Recipe
|
||||
import asyncer
|
||||
import functools
|
||||
from typing import Callable, ParamSpec, TypeVar, Awaitable
|
||||
|
||||
_P = ParamSpec("_P")
|
||||
_R = TypeVar("_R")
|
||||
|
||||
def make_async_background(fn: Callable[_P, _R]) -> Callable[_P, Awaitable[_R]]:
|
||||
@functools.wraps(fn)
|
||||
async def wrapper(*args: _P.args, **kwargs: _P.kwargs) -> _R:
|
||||
return await asyncer.asyncify(fn)(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
```
|
||||
|
||||
```python Using the Decorator {6}
|
||||
from fastmcp import FastMCP
|
||||
|
||||
mcp = FastMCP()
|
||||
|
||||
@mcp.tool()
|
||||
@make_async_background
|
||||
def my_tool() -> None:
|
||||
time.sleep(5)
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Tool Parameters
|
||||
|
||||
#### Type Annotations
|
||||
|
|
@ -259,33 +314,6 @@ dynamic_tool.disable()
|
|||
dynamic_tool.enable()
|
||||
```
|
||||
|
||||
### Async Tools
|
||||
|
||||
FastMCP seamlessly supports both standard (`def`) and asynchronous (`async def`) functions as tools.
|
||||
|
||||
```python
|
||||
# Synchronous tool (suitable for CPU-bound or quick tasks)
|
||||
@mcp.tool
|
||||
def calculate_distance(lat1: float, lon1: float, lat2: float, lon2: float) -> float:
|
||||
"""Calculate the distance between two coordinates."""
|
||||
# Implementation...
|
||||
return 42.5
|
||||
|
||||
# Asynchronous tool (ideal for I/O-bound operations)
|
||||
@mcp.tool
|
||||
async def fetch_weather(city: str) -> dict:
|
||||
"""Retrieve current weather conditions for a city."""
|
||||
# Use 'async def' for operations involving network calls, file I/O, etc.
|
||||
# This prevents blocking the server while waiting for external operations.
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(f"https://api.example.com/weather/{city}") as response:
|
||||
# Check response status before returning
|
||||
response.raise_for_status()
|
||||
return await response.json()
|
||||
```
|
||||
|
||||
Use `async def` when your tool needs to perform operations that might wait for external systems (network requests, database queries, file access) to keep your server responsive.
|
||||
|
||||
### Return Values
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue