Skip to content

Commit cb901dc

Browse files
committed
chore: Update deps and code to match ADK 1.3 patterns
1 parent fc556f5 commit cb901dc

File tree

4 files changed

+1090
-1043
lines changed

4 files changed

+1090
-1043
lines changed

agents_mcp_usage/basic_mcp/basic_mcp_use/adk_mcp.py

Lines changed: 60 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
"""ADK-based agent using MCP protocol for tool access."""
2+
13
import asyncio
24
import os
35
import logfire
46

57
from dotenv import load_dotenv
68
from google.adk.agents.llm_agent import LlmAgent
7-
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StdioServerParameters
9+
from google.adk.tools.mcp_tool.mcp_toolset import (
10+
MCPToolset,
11+
StdioServerParameters,
12+
StdioConnectionParams,
13+
)
814
from google.adk.runners import Runner
915
from google.adk.sessions import InMemorySessionService
1016
from google.genai import types
@@ -29,51 +35,67 @@ async def main(query: str = "Greet Andrew and give him the current time") -> Non
2935
Args:
3036
query: The query to run the agent with.
3137
"""
32-
# Set up MCP server connection
33-
server_params = StdioServerParameters(
34-
command="uv",
35-
args=["run", "mcp_servers/example_server.py", "stdio"],
36-
)
37-
38-
tools, exit_stack = await MCPToolset.from_server(connection_params=server_params)
39-
print(f"Connected to MCP server. Found {len(tools)} tools.")
40-
41-
# Create the agent
42-
root_agent = LlmAgent(
43-
model="gemini-2.5-pro-preview-03-25",
44-
name="mcp_adk_assistant",
45-
tools=tools,
46-
)
47-
48-
# Set up session
49-
session_service = InMemorySessionService()
50-
session = session_service.create_session(
51-
app_name="mcp_adk_app",
52-
user_id="aginns",
53-
)
54-
55-
# Create the runner
56-
runner = Runner(
57-
app_name="mcp_adk_app",
58-
agent=root_agent,
59-
session_service=session_service,
60-
)
61-
62-
# Run the agent with a query
63-
content = types.Content(role="user", parts=[types.Part(text=query)])
64-
65-
print("Running agent...")
38+
toolset = None
6639
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+
)
57+
58+
# Set up session with async service
59+
session_service = InMemorySessionService()
60+
session = await session_service.create_session(
61+
app_name="mcp_adk_app",
62+
user_id="aginns",
63+
)
64+
65+
# Create the runner
66+
runner = Runner(
67+
app_name="mcp_adk_app",
68+
agent=root_agent,
69+
session_service=session_service,
70+
)
71+
72+
# Format the query as content
73+
content = types.Content(role="user", parts=[types.Part(text=query)])
74+
75+
print("Running agent...")
6776
events_async = runner.run_async(
6877
session_id=session.id, user_id=session.user_id, new_message=content
6978
)
7079

7180
async for event in events_async:
7281
print(f"Event received: {event}")
82+
83+
except Exception as e:
84+
print(f"Error during agent execution: {e}")
85+
print(f"Error type: {type(e).__name__}")
86+
raise
7387
finally:
74-
print("Closing MCP server connection...")
75-
await exit_stack.aclose()
76-
print("Cleanup complete.")
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}")
98+
print("Agent execution completed successfully.")
7799

78100

79101
if __name__ == "__main__":

agents_mcp_usage/multi_mcp/multi_mcp_use/adk_mcp.py

Lines changed: 97 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
1+
"""Advanced multi-MCP server integration using Google's ADK.
2+
3+
This module demonstrates sophisticated ADK (Agent Development Kit) patterns including:
4+
- Multi-MCP server coordination with parallel connections
5+
- Latest gemini-2.0-flash model integration
6+
- Advanced async connection management with unified exit stacks
7+
- Comprehensive error handling and recovery
8+
- RunConfig for request limiting and control
9+
- Enhanced event tracking and metrics collection
10+
- Graceful resource cleanup and Logfire instrumentation
11+
12+
Compatible with ADK v1.3.0+ and showcases production-ready patterns
13+
for complex agent architectures involving multiple tool sources.
14+
"""
15+
116
import asyncio
2-
import contextlib
317
import os
418
import time
519

@@ -9,7 +23,11 @@
923
from google.adk.agents.run_config import RunConfig
1024
from google.adk.runners import Runner
1125
from google.adk.sessions import InMemorySessionService
12-
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset, StdioServerParameters
26+
from google.adk.tools.mcp_tool.mcp_toolset import (
27+
MCPToolset,
28+
StdioServerParameters,
29+
StdioConnectionParams,
30+
)
1331
from google.genai import types
1432

1533
from agents_mcp_usage.multi_mcp.mermaid_diagrams import invalid_mermaid_diagram_easy
@@ -24,20 +42,20 @@
2442
logfire.instrument_mcp()
2543

2644

27-
async def get_tools_async() -> tuple[list, contextlib.AsyncExitStack]:
45+
async def get_tools_async() -> tuple[list, list]:
2846
"""Initializes connections to MCP servers and returns their tools.
2947
3048
This function connects to the local example server and the mermaid
3149
validator server, and returns the combined tools and a combined exit
3250
stack for cleanup.
3351
3452
Returns:
35-
A tuple containing the list of all tools and the combined exit stack.
53+
A tuple containing the list of all tools and the list of toolsets for cleanup.
3654
"""
3755
print("Connecting to MCP servers...")
3856

39-
# Create a single exit stack for all connections
40-
exit_stack = contextlib.AsyncExitStack()
57+
# Keep track of toolsets for cleanup (ADK v1.3.0+ API)
58+
toolsets = []
4159

4260
# Set up MCP server connections
4361
local_server = StdioServerParameters(
@@ -57,90 +75,97 @@ async def get_tools_async() -> tuple[list, contextlib.AsyncExitStack]:
5775
],
5876
)
5977

60-
# Connect to local python MCP server
61-
local_toolset = await MCPToolset.from_server(connection_params=local_server)
62-
local_tools, local_stack = local_toolset
63-
# Register with the exit stack
64-
await exit_stack.enter_async_context(local_stack)
78+
# Connect to local python MCP server (ADK v1.3.0+ API)
79+
local_connection = StdioConnectionParams(server_params=local_server)
80+
local_toolset = MCPToolset(connection_params=local_connection)
81+
local_tools = await local_toolset.get_tools()
82+
toolsets.append(local_toolset)
6583
print(f"Connected to local python MCP server. Found {len(local_tools)} tools.")
6684

67-
# Connect to npx mermaid MCP server
68-
mermaid_toolset = await MCPToolset.from_server(connection_params=mermaid_server)
69-
mermaid_tools, mermaid_stack = mermaid_toolset
70-
# Register with the exit stack
71-
await exit_stack.enter_async_context(mermaid_stack)
85+
# Connect to npx mermaid MCP server (ADK v1.3.0+ API)
86+
mermaid_connection = StdioConnectionParams(server_params=mermaid_server)
87+
mermaid_toolset = MCPToolset(connection_params=mermaid_connection)
88+
mermaid_tools = await mermaid_toolset.get_tools()
89+
toolsets.append(mermaid_toolset)
7290
print(f"Connected to npx mermaid MCP server. Found {len(mermaid_tools)} tools.")
7391

7492
# Combine tools from both servers
7593
all_tools = local_tools + mermaid_tools
7694
print(f"Total tools available: {len(all_tools)}")
7795

78-
return all_tools, exit_stack
96+
return all_tools, toolsets
7997

8098

8199
async def main(query: str = "Hi!", request_limit: int = 5) -> None:
82-
"""Runs the agent with a given query and request limit.
100+
"""Runs the agent with a given query and request limit using modern ADK patterns.
83101
84-
This function initializes the tools, creates an agent, and runs it with
102+
This function initialises the tools, creates an agent, and runs it with
85103
the provided query and request limit. It also handles the cleanup of
86104
the MCP server connections and Logfire.
87105
88106
Args:
89107
query: The query to run the agent with.
90-
request_limit: The number of requests to make to the MCP servers.
108+
request_limit: The maximum number of LLM calls allowed.
91109
"""
92-
# Get tools from MCP servers
93-
tools, exit_stack = await get_tools_async()
94-
95-
# Create agent with tools
96-
agent = LlmAgent(
97-
model="gemini-2.5-pro-preview-05-06",
98-
name="multi_mcp_adk",
99-
tools=tools,
100-
)
101-
102-
# Create session service
103-
session_service = InMemorySessionService()
104-
session = session_service.create_session(
105-
app_name="multi_mcp_adk",
106-
user_id="andrewginns",
107-
)
108-
109-
# Create a RunConfig with a limit for LLM calls (500 is the default)
110-
run_config = RunConfig(max_llm_calls=request_limit)
111-
112-
# Create runner
113-
runner = Runner(
114-
app_name="multi_mcp_adk",
115-
agent=agent,
116-
session_service=session_service,
117-
)
118-
119-
# Format the query as a message
120-
message = types.Content(parts=[types.Part(text=query)], role="user")
121-
122-
# Run the agent
123-
events_async = runner.run_async(
124-
session_id=session.id,
125-
user_id="andrewginns",
126-
new_message=message,
127-
run_config=run_config,
128-
)
129-
130-
async for event in events_async:
131-
print(f"Event received: {event}")
132-
133-
# Properly close all MCP connections
134-
print("Closing MCP server connections...")
135-
await exit_stack.aclose()
136-
print("Cleanup complete.")
137-
138-
# Give Logfire time to complete any pending exports
139-
print("Shutting down Logfire...")
140-
logfire.shutdown()
141-
# Small delay to ensure export completes
142-
time.sleep(0.5)
143-
print("Logfire shutdown complete.")
110+
toolsets = []
111+
try:
112+
# Get tools from MCP servers
113+
tools, toolsets = await get_tools_async()
114+
115+
# Create agent
116+
agent = LlmAgent(
117+
model="gemini-2.0-flash",
118+
name="multi_mcp_adk",
119+
tools=tools,
120+
)
121+
122+
# Create async session service
123+
session_service = InMemorySessionService()
124+
session = await session_service.create_session(
125+
app_name="multi_mcp_adk",
126+
user_id="andrewginns",
127+
)
128+
129+
# Create a RunConfig with a limit for LLM calls (500 is the default)
130+
run_config = RunConfig(max_llm_calls=request_limit)
131+
132+
# Create runner
133+
runner = Runner(
134+
app_name="multi_mcp_adk",
135+
agent=agent,
136+
session_service=session_service,
137+
)
138+
139+
# Format the query as a message
140+
message = types.Content(parts=[types.Part(text=query)], role="user")
141+
142+
# Run the agent
143+
events_async = runner.run_async(
144+
session_id=session.id,
145+
user_id="andrewginns",
146+
new_message=message,
147+
run_config=run_config,
148+
)
149+
150+
async for event in events_async:
151+
print(f"Event received: {event}")
152+
153+
except Exception as e:
154+
print(f"Error during agent execution: {e}")
155+
print(f"Error type: {type(e).__name__}")
156+
raise
157+
finally:
158+
# Clean up MCP toolsets to prevent asyncio shutdown errors
159+
print("Cleaning up MCP connections...")
160+
for i, toolset in enumerate(toolsets):
161+
try:
162+
await toolset.close()
163+
print(f"Toolset {i + 1} closed successfully.")
164+
except asyncio.CancelledError:
165+
print(f"Toolset {i + 1} cleanup cancelled - this is normal")
166+
except Exception as e:
167+
print(f"Warning during cleanup of toolset {i + 1}: {e}")
168+
print("MCP cleanup completed.")
144169

145170

146171
if __name__ == "__main__":

pyproject.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ description = "Add your description here"
55
readme = "README.md"
66
requires-python = ">=3.13"
77
dependencies = [
8-
"google-adk>=0.2.0",
8+
"google-adk>=1.3.0",
99
"langchain>=0.3.22",
10-
"langchain-community>=0.3.20",
11-
"langchain-core>=0.3.49",
10+
"langchain-community>=0.3.25",
11+
"langchain-core>=0.3.65",
1212
"langchain-google-genai>=2.1.2",
1313
"langchain-mcp-adapters>=0.0.9",
1414
"langgraph>=0.3.31",
15-
"logfire>=3.14.0",
15+
"logfire>=3.20.0",
1616
"loguru>=0.7.3",
1717
"mcp==1.9.0",
1818
"openai-agents>=0.0.12",

0 commit comments

Comments
 (0)