Skip to content

Commit b54674c

Browse files
committed
feat: Enable ADK web UI
1 parent a28f47a commit b54674c

File tree

3 files changed

+119
-34
lines changed

3 files changed

+119
-34
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,7 @@ lint:
66
uv run ruff check .
77

88
leaderboard:
9-
uv run -- streamlit run agents_mcp_usage/multi_mcp/eval_multi_mcp/merbench_ui.py
9+
uv run -- streamlit run agents_mcp_usage/multi_mcp/eval_multi_mcp/merbench_ui.py
10+
11+
adk_basic_ui:
12+
cd agents_mcp_usage/basic_mcp && uv run adk web
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
# Basic MCP usage examples package
2+
3+
# Allow discovery of the ADK agent via the ADK web UI
4+
from .adk_mcp import root_agent

agents_mcp_usage/basic_mcp/basic_mcp_use/adk_mcp.py

Lines changed: 112 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
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

38
import asyncio
49
import os
510
import logfire
11+
from typing import List, Tuple, Any
612

713
from dotenv import load_dotenv
814
from google.adk.agents.llm_agent import LlmAgent
@@ -15,6 +21,8 @@
1521
from google.adk.sessions import InMemorySessionService
1622
from google.genai import types
1723

24+
from agents_mcp_usage.utils import get_mcp_server_path
25+
1826
load_dotenv()
1927

2028
# Set API key for Google AI API from environment variable
@@ -24,36 +32,115 @@
2432
logfire.configure(send_to_logfire="if-token-present", service_name="adk-basic-mcp")
2533
logfire.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

28132
async 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

Comments
 (0)