Async MCP Tools in Python

If a tool waits on HTTP, databases, queues, or storage, make it async and use async-compatible libraries.

@mcp.tool()
async def search_docs(query: str) -> list[dict]:
    """Search the documentation service."""
    response = await http_client.get("/search", params={"q": query})
    response.raise_for_status()
    return response.json()["results"]

Reuse clients

Do not create a new connection pool or HTTP client for every call. Initialize shared dependencies during server/application lifespan.

Bound concurrency

If a tool fans out to many services, use semaphores or bounded task groups. Unbounded concurrency can overwhelm downstream systems.

Cancellation

Where libraries support it, propagate request cancellation into in-flight work so abandoned agent calls stop consuming resources.