Skip to content

Commit d38abab

Browse files
committed
feat: Add Google ADK multi-mcp agent
1 parent 2299715 commit d38abab

File tree

2 files changed

+152
-3
lines changed

2 files changed

+152
-3
lines changed

agents_mcp_usage/multi_mcp/README.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ Agents utilising multiple MCP servers can be dramatically more complex than an A
1717
# Run the Pydantic-AI multi-MCP example
1818
uv run agents_mcp_usage/multi_mcp/multi_mcp_use/pydantic_mcp.py
1919

20+
# Run the Google ADK multi-MCP example
21+
uv run agents_mcp_usage/multi_mcp/multi_mcp_use/adk_mcp.py
22+
2023
# Run the multi-MCP evaluation
2124
uv run agents_mcp_usage/multi_mcp/eval_multi_mcp/evals_pydantic_mcp.py
2225
```
@@ -31,7 +34,7 @@ graph LR
3134
User((User)) --> |"Run script<br>(e.g., pydantic_mcp.py)"| Agent
3235
3336
subgraph "Agent Framework"
34-
Agent["Pydantic-AI Agent<br>(pydantic_mcp.py)"]
37+
Agent["Pydantic-AI/ADK Agent<br>(pydantic_mcp.py/adk_mcp.py)"]
3538
end
3639
3740
subgraph "MCP Servers"
@@ -48,7 +51,7 @@ graph LR
4851
end
4952
5053
subgraph "LLM Providers"
51-
LLMs["PydanticAI LLM call"]
54+
LLMs["PydanticAI/Gemini LLM call"]
5255
end
5356
5457
Logfire[("Logfire<br>Tracing")]
@@ -93,7 +96,7 @@ This diagram illustrates how an agent can leverage multiple specialised MCP serv
9396
```mermaid
9497
sequenceDiagram
9598
participant User
96-
participant Agent as Pydantic-AI Agent
99+
participant Agent as Pydantic-AI/ADK Agent
97100
participant PyMCP as Python MCP Server
98101
participant NodeMCP as Node.js MCP Server
99102
participant LLM as LLM Provider
@@ -195,6 +198,23 @@ Key features:
195198
- Shows how to coordinate between different MCP servers
196199
- Includes Logfire instrumentation for comprehensive tracing
197200

201+
### Google ADK Multi-MCP
202+
203+
**File:** `multi_mcp_use/adk_mcp.py`
204+
205+
This example demonstrates how to use multiple MCP servers with Google's Agent Development Kit (ADK).
206+
207+
```bash
208+
uv run agents_mcp_usage/multi_mcp/multi_mcp_use/adk_mcp.py
209+
```
210+
211+
Key features:
212+
- Uses Google's ADK framework with Gemini model
213+
- Connects to both Python MCP server and Node.js Mermaid validator
214+
- Demonstrates proper connection management with contextlib.AsyncExitStack
215+
- Shows how to handle asynchronous MCP tool integration
216+
- Uses a simple test case that utilizes both MCP servers in a single query
217+
198218
### Multi-MCP Evaluation
199219

200220
**File:** `eval_multi_mcp/evals_pydantic_mcp.py`
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import asyncio
2+
import contextlib
3+
import os
4+
5+
import logfire
6+
from dotenv import load_dotenv
7+
from google.adk.agents.llm_agent import LlmAgent
8+
from google.adk.agents.run_config import RunConfig
9+
from google.adk.runners import Runner
10+
from google.adk.sessions import InMemorySessionService
11+
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StdioServerParameters
12+
from google.genai import types
13+
14+
from agents_mcp_usage.multi_mcp.mermaid_diagrams import invalid_mermaid_diagram_easy
15+
16+
load_dotenv()
17+
18+
# Set API key for Google AI API from environment variable
19+
os.environ["GOOGLE_API_KEY"] = os.getenv("GEMINI_API_KEY", "")
20+
21+
# Configure logging if LOGFIRE_TOKEN is set
22+
logfire.configure(send_to_logfire="if-token-present", service_name="adk-basic-mcp")
23+
logfire.instrument_mcp()
24+
25+
26+
async def get_tools_async():
27+
"""Initializes connections to MCP servers and returns their tools along with a combined exit stack."""
28+
print("Connecting to MCP servers...")
29+
30+
# Create a single exit stack for all connections
31+
exit_stack = contextlib.AsyncExitStack()
32+
33+
# Set up MCP server connections
34+
local_server = StdioServerParameters(
35+
command="uv",
36+
args=[
37+
"run",
38+
"run_server.py",
39+
"stdio",
40+
],
41+
)
42+
43+
mermaid_server = StdioServerParameters(
44+
command="npx",
45+
args=[
46+
"-y",
47+
"@rtuin/mcp-mermaid-validator@latest",
48+
],
49+
)
50+
51+
# Connect to local python MCP server
52+
local_toolset = await MCPToolset.from_server(connection_params=local_server)
53+
local_tools, local_stack = local_toolset
54+
# Register with the exit stack
55+
await exit_stack.enter_async_context(local_stack)
56+
print(f"Connected to local python MCP server. Found {len(local_tools)} tools.")
57+
58+
# Connect to npx mermaid MCP server
59+
mermaid_toolset = await MCPToolset.from_server(connection_params=mermaid_server)
60+
mermaid_tools, mermaid_stack = mermaid_toolset
61+
# Register with the exit stack
62+
await exit_stack.enter_async_context(mermaid_stack)
63+
print(f"Connected to npx mermaid MCP server. Found {len(mermaid_tools)} tools.")
64+
65+
# Combine tools from both servers
66+
all_tools = local_tools + mermaid_tools
67+
print(f"Total tools available: {len(all_tools)}")
68+
69+
return all_tools, exit_stack
70+
71+
72+
async def main(query: str = "Hi!", request_limit: int = 5) -> None:
73+
"""
74+
Main function to run the agent
75+
76+
Args:
77+
query (str): The query to run the agent with
78+
request_limit (int): The number of requests to make to the MCP servers
79+
"""
80+
# Get tools from MCP servers
81+
tools, exit_stack = await get_tools_async()
82+
83+
# Create agent with tools
84+
agent = LlmAgent(
85+
model="gemini-2.5-pro-preview-03-25",
86+
name="multi_mcp_adk",
87+
tools=tools,
88+
)
89+
90+
# Create session service
91+
session_service = InMemorySessionService()
92+
session = session_service.create_session(
93+
app_name="multi_mcp_adk",
94+
user_id="andrewginns",
95+
)
96+
97+
# Create a RunConfig with a limit for LLM calls (500 is the default)
98+
run_config = RunConfig(max_llm_calls=request_limit)
99+
100+
# Create runner
101+
runner = Runner(
102+
app_name="multi_mcp_adk",
103+
agent=agent,
104+
session_service=session_service,
105+
)
106+
107+
# Format the query as a message
108+
message = types.Content(parts=[types.Part(text=query)], role="user")
109+
110+
# Run the agent
111+
events_async = runner.run_async(
112+
session_id=session.id,
113+
user_id="andrewginns",
114+
new_message=message,
115+
run_config=run_config,
116+
)
117+
118+
async for event in events_async:
119+
print(f"Event received: {event}")
120+
121+
# Properly close all MCP connections
122+
print("Closing MCP server connections...")
123+
await exit_stack.aclose()
124+
print("Cleanup complete.")
125+
126+
127+
if __name__ == "__main__":
128+
query = f"Add the current time and fix the mermaid diagram syntax using the validator: {invalid_mermaid_diagram_easy}. Return only the fixed mermaid diagram between backticks."
129+
asyncio.run(main(query))

0 commit comments

Comments
 (0)