@@ -472,6 +472,40 @@ def _tool_2():
472472 assert tools [0 ].name == '_tool_1'
473473 assert tools [1 ].name == '_tool_2'
474474
475+ async def test_canonical_tools_graceful_degradation_on_toolset_error (self ):
476+ """Test that canonical_tools returns tools from working toolsets when one fails."""
477+ from google .adk .tools .base_tool import BaseTool
478+ from google .adk .tools .base_toolset import BaseToolset
479+
480+ class FailingToolset (BaseToolset ):
481+
482+ async def get_tools (self , readonly_context = None ):
483+ raise ConnectionError ('MCP server unavailable' )
484+
485+ class WorkingToolset (BaseToolset ):
486+
487+ async def get_tools (self , readonly_context = None ):
488+ tool = mock .MagicMock (spec = BaseTool )
489+ tool .name = 'working_tool'
490+ tool ._get_declaration = mock .MagicMock (return_value = None )
491+ return [tool ]
492+
493+ def _regular_tool ():
494+ pass
495+
496+ agent = LlmAgent (
497+ name = 'test_agent' ,
498+ model = 'gemini-pro' ,
499+ tools = [_regular_tool , FailingToolset (), WorkingToolset ()],
500+ )
501+ ctx = await _create_readonly_context (agent )
502+ tools = await agent .canonical_tools (ctx )
503+
504+ # Should have the regular tool + working toolset tool, but not crash
505+ assert len (tools ) == 2
506+ assert tools [0 ].name == '_regular_tool'
507+ assert tools [1 ].name == 'working_tool'
508+
475509
476510# Tests for multi-provider model support via string model names
477511@pytest .mark .parametrize (
0 commit comments