From 43be4007609530a00b89ddc9cad225263e8731a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ak=C4=B1n?= <79704490+akintunca@users.noreply.github.com> Date: Fri, 3 Oct 2025 17:44:37 +0200 Subject: [PATCH 1/3] MCP tool connection hanging BUG fix Fixing the bug described here: https://github.com/google/adk-python/issues/3084 --- src/google/adk/tools/mcp_tool/mcp_toolset.py | 47 ++++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/google/adk/tools/mcp_tool/mcp_toolset.py b/src/google/adk/tools/mcp_tool/mcp_toolset.py index 150336f3f2..4e899f7c35 100644 --- a/src/google/adk/tools/mcp_tool/mcp_toolset.py +++ b/src/google/adk/tools/mcp_tool/mcp_toolset.py @@ -104,6 +104,9 @@ def __init__( errlog: TextIO = sys.stderr, auth_scheme: Optional[AuthScheme] = None, auth_credential: Optional[AuthCredential] = None, + session_close_timeout: float = 5.0, + session_create_timeout: float = 15.0, + list_tools_timeout: float = 30.0, ): """Initializes the MCPToolset. @@ -140,6 +143,9 @@ def __init__( ) self._auth_scheme = auth_scheme self._auth_credential = auth_credential + self._session_close_timeout = session_close_timeout + self._session_create_timeout = session_create_timeout + self._list_tools_timeout = list_tools_timeout @retry_on_closed_resource async def get_tools( @@ -155,11 +161,44 @@ async def get_tools( Returns: List[BaseTool]: A list of tools available under the specified context. """ - # Get session from session manager - session = await self._mcp_session_manager.create_session() + import asyncio + + # Close stale session manager and create fresh one + try: + await asyncio.wait_for( + self._mcp_session_manager.close(), + timeout=self._session_close_timeout + ) + except (asyncio.TimeoutError, Exception): + pass # Ignore close errors + + # Recreate session manager with fresh connections + self._mcp_session_manager = MCPSessionManager( + connection_params=self._connection_params, + errlog=self._errlog, + ) + + # Get session from session manager with timeout + try: + session = await asyncio.wait_for( + self._mcp_session_manager.create_session(), + timeout=self._session_create_timeout + ) + except asyncio.TimeoutError: + raise RuntimeError( + f"Failed to create MCP session: timeout after {self._session_create_timeout}s" + ) - # Fetch available tools from the MCP server - tools_response: ListToolsResult = await session.list_tools() + # Fetch available tools from the MCP server with timeout + try: + tools_response: ListToolsResult = await asyncio.wait_for( + session.list_tools(), + timeout=self._list_tools_timeout + ) + except asyncio.TimeoutError: + raise RuntimeError( + f"Failed to list MCP tools: timeout after {self._list_tools_timeout}s" + ) # Apply filtering based on context and tool_filter tools = [] From 3f85ce4ca4325ccf78bce29bc891995c85f64d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ak=C4=B1n?= <79704490+akintunca@users.noreply.github.com> Date: Mon, 6 Oct 2025 08:48:07 +0200 Subject: [PATCH 2/3] Update src/google/adk/tools/mcp_tool/mcp_toolset.py Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/google/adk/tools/mcp_tool/mcp_toolset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/google/adk/tools/mcp_tool/mcp_toolset.py b/src/google/adk/tools/mcp_tool/mcp_toolset.py index 4e899f7c35..c5b4627698 100644 --- a/src/google/adk/tools/mcp_tool/mcp_toolset.py +++ b/src/google/adk/tools/mcp_tool/mcp_toolset.py @@ -169,8 +169,8 @@ async def get_tools( self._mcp_session_manager.close(), timeout=self._session_close_timeout ) - except (asyncio.TimeoutError, Exception): - pass # Ignore close errors + except (asyncio.TimeoutError, Exception) as e: + logger.warning('Ignoring error while closing stale MCP session manager: %s', e) # Recreate session manager with fresh connections self._mcp_session_manager = MCPSessionManager( From 43ab094336aafb7f38d22465cb010535d2046274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ak=C4=B1n?= <79704490+akintunca@users.noreply.github.com> Date: Mon, 6 Oct 2025 08:50:16 +0200 Subject: [PATCH 3/3] Update mcp_toolset.py --- src/google/adk/tools/mcp_tool/mcp_toolset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/google/adk/tools/mcp_tool/mcp_toolset.py b/src/google/adk/tools/mcp_tool/mcp_toolset.py index c5b4627698..8efe72fd15 100644 --- a/src/google/adk/tools/mcp_tool/mcp_toolset.py +++ b/src/google/adk/tools/mcp_tool/mcp_toolset.py @@ -21,6 +21,7 @@ from typing import TextIO from typing import Union import warnings +import asyncio from pydantic import model_validator from typing_extensions import override @@ -161,7 +162,6 @@ async def get_tools( Returns: List[BaseTool]: A list of tools available under the specified context. """ - import asyncio # Close stale session manager and create fresh one try: