1- """ADK-based agent using MCP protocol for tool access."""
1+ """ADK-based agent using MCP protocol for tool access.
2+
3+ This module provides an ADK agent that can be used both in the ADK web UI
4+ and directly from the command line. The agent uses MCP tools to access
5+ external functionality.
6+ """
27
38import asyncio
49import os
510import logfire
11+ from typing import List , Tuple , Any
612
713from dotenv import load_dotenv
814from google .adk .agents .llm_agent import LlmAgent
1521from google .adk .sessions import InMemorySessionService
1622from google .genai import types
1723
24+ from agents_mcp_usage .utils import get_mcp_server_path
25+
1826load_dotenv ()
1927
2028# Set API key for Google AI API from environment variable
2432logfire .configure (send_to_logfire = "if-token-present" , service_name = "adk-basic-mcp" )
2533logfire .instrument_mcp ()
2634
35+ # Global variable to store toolset instances for cleanup
36+ _ACTIVE_TOOLSETS = []
37+
38+
39+ # Initialize the MCP tools and agent for ADK web UI
40+ async def init_mcp_toolset () -> Tuple [List [Any ], List [MCPToolset ]]:
41+ """Initialize and return the MCP tools and toolsets.
42+
43+ Returns:
44+ Tuple[List[Any], List[MCPToolset]]: A tuple of (tools, toolsets)
45+ """
46+ global _ACTIVE_TOOLSETS
47+
48+ # Use absolute path to MCP server based on project root
49+ mcp_server_path = get_mcp_server_path ("example_server.py" )
50+
51+ server_params = StdioServerParameters (
52+ command = "uv" ,
53+ args = ["run" , str (mcp_server_path ), "stdio" ],
54+ )
55+ connection_params = StdioConnectionParams (server_params = server_params )
56+ toolset = MCPToolset (connection_params = connection_params )
57+
58+ try :
59+ tools = await toolset .get_tools ()
60+ _ACTIVE_TOOLSETS .append (toolset )
61+ return tools , [toolset ]
62+ except Exception as e :
63+ # Clean up in case of initialization error
64+ try :
65+ await toolset .close ()
66+ except Exception :
67+ pass
68+ raise e
69+
70+
71+ async def cleanup_toolsets ():
72+ """Clean up any active MCP toolset connections."""
73+ global _ACTIVE_TOOLSETS
74+
75+ for toolset in _ACTIVE_TOOLSETS :
76+ try :
77+ await toolset .close ()
78+ print ("MCP toolset connection closed." )
79+ except asyncio .CancelledError :
80+ print ("MCP cleanup cancelled - this is normal" )
81+ except Exception as e :
82+ print (f"Warning: Error during toolset cleanup: { e } " )
83+
84+ _ACTIVE_TOOLSETS = []
85+
86+
87+ # Define a before_agent_callback to attach tools
88+ async def attach_tools_callback (callback_context ):
89+ """Callback to attach tools to the agent before it runs.
90+
91+ Args:
92+ callback_context: The callback context from ADK.
93+
94+ Returns:
95+ None: The callback doesn't modify the content.
96+ """
97+ await ensure_tools_attached ()
98+ return None
99+
100+
101+ # This is the agent that will be imported by the ADK web UI
102+ root_agent = LlmAgent (
103+ model = "gemini-2.0-flash" ,
104+ name = "mcp_adk_assistant" ,
105+ instruction = "You are an assistant that uses MCP tools to help users." ,
106+ before_agent_callback = attach_tools_callback , # This ensures tools are attached
107+ )
108+
109+
110+ # Flag to track if tools have been attached
111+ TOOLS_ATTACHED = False
112+
113+
114+ # Function to dynamically attach tools to the agent
115+ async def ensure_tools_attached ():
116+ """Ensures that tools are attached to the agent before it's used."""
117+ global TOOLS_ATTACHED
118+
119+ if not TOOLS_ATTACHED :
120+ try :
121+ tools , _ = await init_mcp_toolset ()
122+ print (f"✓ Connected to MCP server. Found { len (tools )} tools." )
123+ # Update the agent's tools
124+ root_agent .tools = tools
125+ TOOLS_ATTACHED = True
126+ except Exception as e :
127+ print (f"Error attaching MCP tools: { e } " )
128+ # Set empty tools to avoid errors
129+ root_agent .tools = []
130+
27131
28132async def main (query : str = "Greet Andrew and give him the current time" ) -> None :
29133 """Runs the agent with a given query.
30134
31- This function sets up the MCP server, creates an LLM agent, and runs it
32- with a specified query. It also handles the cleanup of the MCP server
33- connection.
135+ This function sets up a runner for the agent and runs it with a specified query.
136+ It also handles the cleanup of the MCP server connection.
34137
35138 Args:
36139 query: The query to run the agent with.
37140 """
38- toolset = None
39141 try :
40- # Set up MCP server connection with enhanced error handling
41- server_params = StdioServerParameters (
42- command = "uv" ,
43- args = ["run" , "mcp_servers/example_server.py" , "stdio" ],
44- )
45-
46- connection_params = StdioConnectionParams (server_params = server_params )
47- toolset = MCPToolset (connection_params = connection_params )
48- tools = await toolset .get_tools ()
49- print (f"✓ Connected to MCP server. Found { len (tools )} tools." )
50-
51- # Create the agent
52- root_agent = LlmAgent (
53- model = "gemini-2.0-flash" ,
54- name = "mcp_adk_assistant" ,
55- tools = tools ,
56- )
142+ # Ensure tools are attached to the agent
143+ await ensure_tools_attached ()
57144
58145 # Set up session with async service
59146 session_service = InMemorySessionService ()
@@ -62,7 +149,7 @@ async def main(query: str = "Greet Andrew and give him the current time") -> Non
62149 user_id = "aginns" ,
63150 )
64151
65- # Create the runner
152+ # Create the runner using the globally defined agent
66153 runner = Runner (
67154 app_name = "mcp_adk_app" ,
68155 agent = root_agent ,
@@ -85,16 +172,8 @@ async def main(query: str = "Greet Andrew and give him the current time") -> Non
85172 print (f"Error type: { type (e ).__name__ } " )
86173 raise
87174 finally :
88- # Clean up MCP toolset to prevent asyncio shutdown errors
89- if toolset :
90- print ("Closing MCP server connection..." )
91- try :
92- await toolset .close ()
93- print ("MCP connection closed successfully." )
94- except asyncio .CancelledError :
95- print ("MCP cleanup cancelled - this is normal" )
96- except Exception as e :
97- print (f"Warning: Error during cleanup: { e } " )
175+ # Clean up MCP toolsets to prevent asyncio shutdown errors
176+ await cleanup_toolsets ()
98177 print ("Agent execution completed successfully." )
99178
100179
0 commit comments