🌐 AI搜索 & 代理 主页
Skip to content

Commit ec4ccd7

Browse files
wukathcopybara-github
authored andcommitted
feat: Create APIRegistryToolset to add tools from Cloud API registry to agent
This calls the cloudapiregistry.googleapis.com API to get MCP tools from the project's registry, and adds them to ADK. Co-authored-by: Kathy Wu <wukathy@google.com> PiperOrigin-RevId: 837166909
1 parent f283027 commit ec4ccd7

File tree

6 files changed

+406
-0
lines changed

6 files changed

+406
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# BigQuery API Registry Agent
2+
3+
This agent demonstrates how to use `ApiRegistry` to discover and interact with Google Cloud services like BigQuery via tools exposed by an MCP server registered in an API Registry.
4+
5+
## Prerequisites
6+
7+
- A Google Cloud project with the API Registry API enabled.
8+
- An MCP server exposing BigQuery tools registered in API Registry.
9+
10+
## Configuration & Running
11+
12+
1. **Configure:** Edit `agent.py` and replace `your-google-cloud-project-id` and `your-mcp-server-name` with your Google Cloud Project ID and the name of your registered MCP server.
13+
2. **Run in CLI:**
14+
```bash
15+
adk run contributing/samples/api_registry_agent -- --log-level DEBUG
16+
```
17+
3. **Run in Web UI:**
18+
```bash
19+
adk web contributing/samples/
20+
```
21+
Navigate to `http://127.0.0.1:8080` and select the `api_registry_agent` agent.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from . import agent
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import os
16+
17+
from google.adk.agents.llm_agent import LlmAgent
18+
from google.adk.tools.api_registry import ApiRegistry
19+
20+
# TODO: Fill in with your GCloud project id and MCP server name
21+
PROJECT_ID = "your-google-cloud-project-id"
22+
MCP_SERVER_NAME = "your-mcp-server-name"
23+
24+
# Header required for BigQuery MCP server
25+
header_provider = lambda context: {
26+
"x-goog-user-project": PROJECT_ID,
27+
}
28+
api_registry = ApiRegistry(PROJECT_ID, header_provider=header_provider)
29+
registry_tools = api_registry.get_toolset(
30+
mcp_server_name=MCP_SERVER_NAME,
31+
)
32+
root_agent = LlmAgent(
33+
model="gemini-2.0-flash",
34+
name="bigquery_assistant",
35+
instruction="""
36+
Help user access their BigQuery data via API Registry tools.
37+
""",
38+
tools=[registry_tools],
39+
)

src/google/adk/tools/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
if TYPE_CHECKING:
2222
from ..auth.auth_tool import AuthToolArguments
2323
from .agent_tool import AgentTool
24+
from .api_registry import ApiRegistry
2425
from .apihub_tool.apihub_toolset import APIHubToolset
2526
from .base_tool import BaseTool
2627
from .discovery_engine_search_tool import DiscoveryEngineSearchTool
@@ -84,6 +85,7 @@
8485
'VertexAiSearchTool': ('.vertex_ai_search_tool', 'VertexAiSearchTool'),
8586
'MCPToolset': ('.mcp_tool.mcp_toolset', 'MCPToolset'),
8687
'McpToolset': ('.mcp_tool.mcp_toolset', 'McpToolset'),
88+
'ApiRegistry': ('.api_registry', 'ApiRegistry'),
8789
}
8890

8991
__all__ = list(_LAZY_MAPPING.keys())
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from __future__ import annotations
16+
17+
import sys
18+
from typing import Any
19+
from typing import Dict
20+
from typing import List
21+
from typing import Optional
22+
from typing import Union
23+
24+
import google.auth
25+
import google.auth.transport.requests
26+
import httpx
27+
28+
from .base_toolset import ToolPredicate
29+
from .mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
30+
from .mcp_tool.mcp_toolset import McpToolset
31+
32+
# TODO(wukathy): Update to prod URL once it is available.
33+
API_REGISTRY_URL = "https://staging-cloudapiregistry.sandbox.googleapis.com"
34+
35+
36+
class ApiRegistry:
37+
"""Registry that provides McpToolsets for MCP servers registered in API Registry."""
38+
39+
def __init__(
40+
self,
41+
api_registry_project_id: str,
42+
location: str = "global",
43+
header_provider: Optional[
44+
Callable[[ReadonlyContext], Dict[str, str]]
45+
] = None,
46+
):
47+
"""Initialize the API Registry.
48+
49+
Args:
50+
api_registry_project_id: The project ID for the Google Cloud API Registry.
51+
location: The location of the API Registry resources.
52+
header_provider: Optional function to provide additional headers for MCP
53+
server calls.
54+
"""
55+
self.api_registry_project_id = api_registry_project_id
56+
self.location = location
57+
self._credentials, _ = google.auth.default()
58+
self._mcp_servers: Dict[str, Dict[str, Any]] = {}
59+
self._header_provider = header_provider
60+
61+
url = f"{API_REGISTRY_URL}/v1beta/projects/{self.api_registry_project_id}/locations/{self.location}/mcpServers"
62+
try:
63+
request = google.auth.transport.requests.Request()
64+
self._credentials.refresh(request)
65+
headers = {
66+
"Authorization": f"Bearer {self._credentials.token}",
67+
"Content-Type": "application/json",
68+
}
69+
with httpx.Client() as client:
70+
response = client.get(url, headers=headers)
71+
response.raise_for_status()
72+
mcp_servers_list = response.json().get("mcpServers", [])
73+
for server in mcp_servers_list:
74+
server_name = server.get("name", "")
75+
if server_name:
76+
self._mcp_servers[server_name] = server
77+
except (httpx.HTTPError, ValueError) as e:
78+
# Handle error in fetching or parsing tool definitions
79+
raise RuntimeError(
80+
f"Error fetching MCP servers from API Registry: {e}"
81+
) from e
82+
83+
def get_toolset(
84+
self,
85+
mcp_server_name: str,
86+
tool_filter: Optional[Union[ToolPredicate, List[str]]] = None,
87+
tool_name_prefix: Optional[str] = None,
88+
) -> McpToolset:
89+
"""Return the MCP Toolset based on the params.
90+
91+
Args:
92+
mcp_server_name: Filter to select the MCP server name to get tools
93+
from.
94+
tool_filter: Optional filter to select specific tools. Can be a list of
95+
tool names or a ToolPredicate function.
96+
tool_name_prefix: Optional prefix to prepend to the names of the tools
97+
returned by the toolset.
98+
99+
Returns:
100+
McpToolset: A toolset for the MCP server specified.
101+
"""
102+
server = self._mcp_servers.get(mcp_server_name)
103+
if not server:
104+
raise ValueError(
105+
f"MCP server {mcp_server_name} not found in API Registry."
106+
)
107+
if not server.get("urls"):
108+
raise ValueError(f"MCP server {mcp_server_name} has no URLs.")
109+
110+
mcp_server_url = server["urls"][0]
111+
request = google.auth.transport.requests.Request()
112+
self._credentials.refresh(request)
113+
headers = {
114+
"Authorization": f"Bearer {self._credentials.token}",
115+
}
116+
return McpToolset(
117+
connection_params=StreamableHTTPConnectionParams(
118+
url="https://" + mcp_server_url,
119+
headers=headers,
120+
),
121+
tool_filter=tool_filter,
122+
tool_name_prefix=tool_name_prefix,
123+
header_provider=self._header_provider,
124+
)

0 commit comments

Comments
 (0)