Skip to content

Agent run_async hangs with "anyio.WouldBlock" and uncaught asyncio.CancelledError on unreachable MCP server URL #3788

@praveeniitm

Description

@praveeniitm

Describe the bug
I am using the Google ADK Python library to run an agent with an MCP toolset connected to an MCP server URL that is currently not reachable (set to an incorrect URL).

To Reproduce
Sample Code snippet

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from google.adk.tools.mcp_tool import McpToolset
from google.adk.agents import Agent
from google.adk.models.lite_llm import LiteLlm
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from google.genai import types
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
import uuid

app = FastAPI(title="ADK Agent API")

OPENAI_API_KEY = "xxxxx"
MCP_URL = "http://wrong_mcp_url/mcp/"

# Initialize components at module level for reuse
model = LiteLlm(model="openai/gpt-4o", api_key=OPENAI_API_KEY)

tool = McpToolset(connection_params= StreamableHTTPConnectionParams(url=MCP_URL))

root_agent = Agent(
    name="weather_agent",
    model=model,
    description="You are the Agent,",
    tools=[tool]
)

session_service = InMemorySessionService()
user_id = "admin"
app_name="test"

runner = Runner(
    agent=root_agent,
    app_name=app_name,
    session_service=session_service,
)

class MessageRequest(BaseModel):
    message: str

@app.post("/message")
async def send_message(req: MessageRequest):
    try:
        session_id = str(uuid.uuid4())
        
        await session_service.create_session(
            app_name=app_name,
            user_id=user_id,
            session_id=session_id
        )

        new_message = types.Content(
            role="user",
            parts=[types.Part(text=req.message)]
        )

        responses = []
        async for event in runner.run_async(
            user_id=user_id,
            session_id=session_id,
            new_message=new_message,
        ):
            if event.is_final_response() and event.content and event.content.parts:
                responses.append(event.content.parts[0].text)

        if not responses:
            return {"success": False, "response": "No response from agent"}

        return {"success": True, "response": responses[-1], "messages": responses}

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Agent execution failed: {str(e)}")


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=7003)

Error Log

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/anyio/streams/memory.py", line 111, in receive
    return self.receive_nowait()
           ~~~~~~~~~~~~~~~~~~~^^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/anyio/streams/memory.py", line 106, in receive_nowait
    raise WouldBlock
anyio.WouldBlock

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/uvicorn/protocols/http/h11_impl.py", line 403, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        self.scope, self.receive, self.send
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/starlette/applications.py", line 113, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/starlette/middleware/errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/starlette/middleware/exceptions.py", line 63, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/starlette/routing.py", line 716, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/starlette/routing.py", line 736, in app
    await route.handle(scope, receive, send)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/starlette/routing.py", line 290, in handle
    await self.app(scope, receive, send)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/starlette/routing.py", line 78, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/starlette/routing.py", line 75, in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/fastapi/routing.py", line 302, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<3 lines>...
    )
    ^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/fastapi/routing.py", line 213, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/admin/Desktop/temp/mcp_error.py", line 59, in send_message
    async for event in runner.run_async(
    ...<5 lines>...
            responses.append(event.content.parts[0].text)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/runners.py", line 428, in run_async
    async for event in agen:
      yield event
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/runners.py", line 412, in _run_with_trace
    async for event in agen:
      yield event
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/runners.py", line 498, in _exec_with_plugin
    async for event in agen:
    ...<9 lines>...
      yield (modified_event if modified_event else event)
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/runners.py", line 401, in execute
    async for event in agen:
      yield event
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/agents/base_agent.py", line 307, in run_async
    async for event in agen:
      yield event
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/agents/base_agent.py", line 297, in _run_with_trace
    async for event in agen:
      yield event
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/agents/llm_agent.py", line 395, in _run_async_impl
    async for event in agen:
    ...<3 lines>...
        return
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/flows/llm_flows/base_llm_flow.py", line 356, in run_async
    async for event in agen:
      last_event = event
      yield event
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/flows/llm_flows/base_llm_flow.py", line 375, in _run_one_step_async
    async for event in agen:
      yield event
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/flows/llm_flows/base_llm_flow.py", line 463, in _preprocess_async
    tools = await _convert_tool_union_to_tools(
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<4 lines>...
    )
    ^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/agents/llm_agent.py", line 157, in _convert_tool_union_to_tools
    return await tool_union.get_tools_with_prefix(ctx)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/tools/base_toolset.py", line 114, in get_tools_with_prefix
    tools = await self.get_tools(readonly_context)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/tools/mcp_tool/mcp_session_manager.py", line 128, in wrapper
    return await func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/tools/mcp_tool/mcp_toolset.py", line 159, in get_tools
    session = await self._mcp_session_manager.create_session()
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/google/adk/tools/mcp_tool/mcp_session_manager.py", line 362, in create_session
    await session.initialize()
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/mcp/client/session.py", line 151, in initialize
    result = await self.send_request(
             ^^^^^^^^^^^^^^^^^^^^^^^^
    ...<16 lines>...
    )
    ^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/mcp/shared/session.py", line 272, in send_request
    response_or_error = await response_stream_reader.receive()
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/anyio/streams/memory.py", line 119, in receive
    await receive_event.wait()
  File "/Users/admin/Desktop/temp/.venv/lib/python3.13/site-packages/anyio/_backends/_asyncio.py", line 1774, in wait
    await self._event.wait()
  File "/Users/admin/.local/share/uv/python/cpython-3.13.3-macos-aarch64-none/lib/python3.13/asyncio/locks.py", line 213, in wait
    await fut
asyncio.exceptions.CancelledError: Cancelled by cancel scope 154a0d350
INFO:     127.0.0.1:53849 - "POST /message HTTP/1.1" 500 Internal Server Error

Expected behavior
Would appreciate guidance on properly handling such connectivity failures in MCP tools to return meaningful errors.
Consider enhancing error propagation in run_async calls to allow catching connection errors gracefully.
Any configurations or best practices to detect and handle MCP server unreachability are welcome.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions