Skip to content

McpToolset does not handle MCP server restart #3321

@BrennanThomasDISW

Description

@BrennanThomasDISW

Describe the bug
If a ClientSession is created by an McpToolset, that session will be reused for any request with the same headers. However, if the MCP server suddenly restarts, the session is not marked as disconnected (MCPSessionManager._is_session_disconnected() still returns False), so the toolset will try to use it again on subsequent requests, resulting in a Session Terminated error.

ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "d:\workdir\xff\adk-testing\.venv\Lib\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 "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 60, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\fastapi\applications.py", line 1134, in __call__
    await super().__call__(scope, receive, send)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\applications.py", line 113, in __call__
    await self.middleware_stack(scope, receive, send)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\middleware\errors.py", line 186, in __call__
    raise exc
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\middleware\errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\middleware\exceptions.py", line 63, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\routing.py", line 716, in __call__
    await self.middleware_stack(scope, receive, send)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\routing.py", line 736, in app
    await route.handle(scope, receive, send)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\routing.py", line 290, in handle
    await self.app(scope, receive, send)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\fastapi\routing.py", line 124, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\starlette\_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\fastapi\routing.py", line 110, in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\fastapi\routing.py", line 390, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<3 lines>...
    )
    ^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\fastapi\routing.py", line 289, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\cli\adk_web_server.py", line 1387, in run_agent
    events = [event async for event in agen]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\runners.py", line 442, in run_async
    async for event in agen:
      yield event
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\runners.py", line 426, in _run_with_trace
    async for event in agen:
      yield event
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\runners.py", line 652, in _exec_with_plugin
    async for event in agen:
    ...<9 lines>...
      yield (modified_event if modified_event else event)
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\runners.py", line 415, in execute
    async for event in agen:
      yield event
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\agents\base_agent.py", line 294, in run_async
    async for event in agen:
      yield event
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\agents\llm_agent.py", line 408, in _run_async_impl
    async for event in agen:
    ...<3 lines>...
        return
  File "d:\workdir\xff\adk-testing\.venv\Lib\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 "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\flows\llm_flows\base_llm_flow.py", line 429, in _run_one_step_async
    async for event in agen:
    ...<3 lines>...
      yield event
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\flows\llm_flows\base_llm_flow.py", line 531, in _postprocess_async
    async for event in agen:
      yield event
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\flows\llm_flows\base_llm_flow.py", line 689, in _postprocess_handle_function_calls_async
    async for event in agen:
      yield event
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\agents\base_agent.py", line 294, in run_async
    async for event in agen:
      yield event
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\agents\llm_agent.py", line 408, in _run_async_impl
    async for event in agen:
    ...<3 lines>...
        return
  File "d:\workdir\xff\adk-testing\.venv\Lib\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 "d:\workdir\xff\adk-testing\.venv\Lib\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 "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\flows\llm_flows\base_llm_flow.py", line 472, in _preprocess_async
    tools = await _convert_tool_union_to_tools(
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<4 lines>...
    )
    ^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\agents\llm_agent.py", line 160, in _convert_tool_union_to_tools
    return await tool_union.get_tools_with_prefix(ctx)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\tools\base_toolset.py", line 114, in get_tools_with_prefix
    tools = await self.get_tools(readonly_context)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\tools\mcp_tool\mcp_session_manager.py", line 128, in wrapper
    return await func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\google\adk\tools\mcp_tool\mcp_toolset.py", line 180, in get_tools
    tools_response: ListToolsResult = await session.list_tools()
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\mcp\client\session.py", line 482, in list_tools
    result = await self.send_request(
             ^^^^^^^^^^^^^^^^^^^^^^^^
    ...<2 lines>...
    )
    ^
  File "d:\workdir\xff\adk-testing\.venv\Lib\site-packages\mcp\shared\session.py", line 286, in send_request
    raise McpError(response_or_error.error)
mcp.shared.exceptions.McpError: Session terminated

To Reproduce

  1. Have an agent execute a tool call provided by an McpToolset.
  2. Restart the MCP server.
  3. Send a message to the same agent. When it tries to list tools in the McpToolset, it will reuse the same (now terminated) session, resulting in the error.

Expected behavior
If the session was terminated, a new session should be started.

Desktop:

  • Windows
  • Python 3.13.2
  • google-adk 1.17.0

Metadata

Metadata

Labels

mcp[Component] Issues about MCP support

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions