YAML-driven, config-validated tool loader for Google ADK agents.
Define tools in simple YAML files. Config is validated at startup — broken configs never silently survive to call time.
# Core (OpenAPI + Function tools)
pip install adk-tools
# With MCP tool support
pip install "adk-tools[mcp]"
# With GCP auth (service_account + Secret Manager)
pip install "adk-tools[gcp]"
# Everything
pip install "adk-tools[all]"Install from source (during development):
git clone https://github.com/cloudsufi/adk-tools
cd adk-tools
pip install -e ".[all,dev]"One sub-folder per tool, each with a tool.yaml:
tools/
weather_api/
tool.yaml ← type: openapi, auth, timeout, …
openapi.yaml ← OpenAPI 3.x spec
input.yaml ← optional JSON Schema (validated at load time)
output.yaml ← optional JSON Schema
docs_mcp/
tool.yaml ← type: mcp, server_url or command
score_function/
tool.yaml ← type: function, static parameters
logic.py ← async def run(…, tool_context: ToolContext) -> dict
Load and pass to an ADK agent:
from adk_tools import load_tools
from google.adk.agents import LlmAgent
tools = load_tools("tools/") # validated at startup
agent = LlmAgent(model="gemini-2.0-flash", tools=tools, ...)For MCP tools (async connection handshake required):
from adk_tools import load_tools_async
tools, exit_stack = await load_tools_async("tools/")
async with exit_stack:
agent = LlmAgent(..., tools=tools)
# run agent hereDecorate any function and it is registered automatically:
# my_tools.py
from adk_tools import function_tool
from google.adk.tools.tool_context import ToolContext
@function_tool
async def greet_user(name: str, tool_context: ToolContext) -> str:
"""Greet a user by name."""
sid = tool_context.state.get("session_id", "?")
return f"Hello {name}! (session {sid})"
@function_tool
def compute_tax(amount: float, rate: float = 0.1) -> float:
"""Compute tax for an amount."""
return round(amount * rate, 2)# agent.py
import my_tools # triggers @function_tool registrations
from adk_tools import load_tools
tools = load_tools("tools/") # YAML tools + @function_tool tools merged
agent = LlmAgent(..., tools=tools)Wraps google.adk.tools.openapi_tool.OpenAPIToolset. Every operation in the spec becomes a separate ADK tool.
# tool.yaml
name: weather_api
description: Fetch weather forecasts.
config:
type: openapi
spec_file: openapi.yaml
auth:
type: bearer
token_env: WEATHER_API_TOKEN
timeout_seconds: 15Wraps google.adk.tools.mcp_tool.MCPToolset. Supports SSE (HTTP) and stdio transports.
config:
type: mcp
server_url: https://mcp.example.com/sse # SSE transport
tool_filter: [search_docs, get_doc] # expose only these tools
auth:
type: bearer
token_secret: projects/p/secrets/mcp-token/versions/latest # from GCP Secret Managerconfig:
type: mcp
command: python # stdio transport
args: [-m, my_mcp_server]
env_vars:
LOG_LEVEL: infoWraps google.adk.tools.FunctionTool around logic.py. Use tool_context: ToolContext for session state access.
config:
type: function
function: run # default; name of async def in logic.py
parameters:
model_version: v2.3 # static kwargs — hidden from LLM schema, injected at call time
threshold: "0.60"# logic.py
from google.adk.tools.tool_context import ToolContext
async def run(
company_size: str,
industry: str,
tool_context: ToolContext, # ADK injects this; not in LLM schema
model_version: str = "v2.3", # injected from tool.yaml config.parameters
) -> dict:
"""Score a sales lead."""
session_id = tool_context.state.get("session_id", "")
...Supported auth types for openapi and mcp tools:
| type | Fields | Source |
|---|---|---|
bearer |
token_env | token_secret |
env var or GCP Secret Manager |
api_key |
key_env | key_secret, header_name, location |
env var or GCP Secret Manager |
oauth2 |
client_id_env/secret, client_secret_env/secret, token_url |
env var or GCP Secret Manager |
service_account |
key_env | key_secret, scopes, audience |
env var (SA JSON) or GCP Secret Manager |
Read a credential from GCP Secret Manager instead of an env var:
auth:
type: bearer
token_secret: projects/my-project/secrets/api-token/versions/latestRequires: pip install "adk-tools[gcp]"
All tool.yaml configs are validated by Pydantic at startup:
- Unknown keys are rejected (
extra = "forbid") - Required fields are enforced
input.yaml/output.yamlare meta-validated as JSON Schema Draft-7 (requirespip install "adk-tools[validation]")- Missing referenced files (
openapi.yaml,logic.py) raiseFileNotFoundErrorimmediately
- Python ≥ 3.10
google-adk >= 0.4pydantic >= 2.5pyyaml >= 6.0