ADK Tool Creation
Core Rules
- Every tool is a plain Python function wrapped in
FunctionTool.
- Required signature pattern:
def my_tool(param1: str, param2: int, tool_context: ToolContext) -> dict:
- Always return a
dict with at minimum "status" and either "message" or "data" keys.
- Handle errors gracefully — return
{"status": "error", "error": "description"}. Never raise exceptions from a tool; the framework cannot recover from them gracefully.
- Write a clear, specific docstring. The LLM reads the docstring to decide when and how to call the tool. Include:
- A one-line summary of what the tool does.
- An
Args: section with each parameter described.
- A
Returns: section describing the response shape.
- Use type hints for every parameter — the framework inspects them to build the tool schema sent to the model.
- Access session state via
tool_context.state["key"] for reading and writing.
- To escalate (exit a LoopAgent early):
tool_context.actions.escalate = True.
- To skip LLM summarisation of the tool result:
tool_context.actions.skip_summarization = True.
- Wrap the function:
my_tool_instance = FunctionTool(func=my_tool).
Quick-Start Template
from google.adk.tools import FunctionTool
from google.adk.tools.tool_context import ToolContext
def do_something(query: str, tool_context: ToolContext) -> dict:
"""One-line summary of what this tool does.
Args:
query: Description of the query parameter.
Returns:
A dict with status and result data.
"""
try:
# ... implementation ...
result = {"answer": "42"}
return {"status": "success", "data": result}
except Exception as e:
return {"status": "error", "error": str(e)}
do_something_tool = FunctionTool(func=do_something)
Parameter Guidelines
- Use
str, int, float, bool, list[str], dict[str, Any] — keep types JSON-serialisable.
tool_context is always the last parameter and is injected by the framework (never supplied by the model).
- Optional parameters: use
param: str = "default". The model can omit them.
- Avoid
*args / **kwargs — the framework cannot generate a schema for them.
Return Format Convention
# Success
{"status": "success", "message": "Created item #42", "data": {...}}
# Error
{"status": "error", "error": "Item not found"}
# Partial / warning
{"status": "warning", "message": "Created but with issues", "warnings": [...]}
Registering Tools on an Agent
from google.adk.agents import LlmAgent
agent = LlmAgent(
name="my_agent",
model="gemini-2.0-flash",
instruction="You are a helpful assistant.",
tools=[do_something_tool],
)
A tool call may be denied before your function ever runs
In a generated agent, a tool doesn't execute unconditionally just because
the model called it. Three independent gates can intercept the call first:
- A command-safety classifier (
command_safety.classify) can return
deny/ask for a shell-executing tool's argv — but only if your own
tool guard calls it; it's a library function, not something the scaffold
wires in automatically.
exfil_guard, a before_tool_callback wired unconditionally into every
generated agent, can block a call whose arguments carry a secret-shaped
value before the tool body runs.
- During a cron run, the headless approval policy (
CronIsolationPlugin)
can auto-deny a non-shell tool outright, since no human is present to
approve it.
Design tools to expect this: surface a denial as a structured, non-fatal
result (e.g. {"status": "error", "error": "..."}, matching the Return
Format Convention above) rather than assuming the function body always
runs — the model should see a normal tool-error response it can react to,
not a crash. Load adk-long-horizon-guardrails for the command-safety
classifier and exfil_guard, and adk-cron-isolation for the headless
denial policy.
References
- Load
tool-patterns for complete CRUD, API wrapper, file-ops, and search tool implementations.
- Load
tool-context-api for the full ToolContext API reference (state, actions, artifacts).
- Load
async-tool-examples for async tool patterns with aiohttp, asyncpg, etc.
1---2name: adk-tool-creation3description: Building Google ADK function tools — ToolContext usage, proper signatures, error handling, return formats, type hints, and async patterns. Load this skill when creating custom tools for an agent.4---56# ADK Tool Creation78## Core Rules9101. Every tool is a plain Python function wrapped in `FunctionTool`.112. Required signature pattern:12 ```python13 def my_tool(param1: str, param2: int, tool_context: ToolContext) -> dict:14 ```153. Always return a `dict` with at minimum `"status"` and either `"message"` or `"data"` keys.164. Handle errors gracefully — return `{"status": "error", "error": "description"}`. **Never raise exceptions** from a tool; the framework cannot recover from them gracefully.175. Write a clear, specific docstring. The LLM reads the docstring to decide **when** and **how** to call the tool. Include:18 - A one-line summary of what the tool does.19 - An `Args:` section with each parameter described.20 - A `Returns:` section describing the response shape.216. Use type hints for **every** parameter — the framework inspects them to build the tool schema sent to the model.227. Access session state via `tool_context.state["key"]` for reading and writing.238. To escalate (exit a LoopAgent early): `tool_context.actions.escalate = True`.249. To skip LLM summarisation of the tool result: `tool_context.actions.skip_summarization = True`.2510. Wrap the function: `my_tool_instance = FunctionTool(func=my_tool)`.2627## Quick-Start Template2829```python30from google.adk.tools import FunctionTool31from google.adk.tools.tool_context import ToolContext323334def do_something(query: str, tool_context: ToolContext) -> dict:35 """One-line summary of what this tool does.3637 Args:38 query: Description of the query parameter.3940 Returns:41 A dict with status and result data.42 """43 try:44 # ... implementation ...45 result = {"answer": "42"}46 return {"status": "success", "data": result}47 except Exception as e:48 return {"status": "error", "error": str(e)}495051do_something_tool = FunctionTool(func=do_something)52```5354## Parameter Guidelines5556- Use `str`, `int`, `float`, `bool`, `list[str]`, `dict[str, Any]` — keep types JSON-serialisable.57- `tool_context` is **always the last parameter** and is injected by the framework (never supplied by the model).58- Optional parameters: use `param: str = "default"`. The model can omit them.59- Avoid `*args` / `**kwargs` — the framework cannot generate a schema for them.6061## Return Format Convention6263```python64# Success65{"status": "success", "message": "Created item #42", "data": {...}}6667# Error68{"status": "error", "error": "Item not found"}6970# Partial / warning71{"status": "warning", "message": "Created but with issues", "warnings": [...]}72```7374## Registering Tools on an Agent7576```python77from google.adk.agents import LlmAgent7879agent = LlmAgent(80 name="my_agent",81 model="gemini-2.0-flash",82 instruction="You are a helpful assistant.",83 tools=[do_something_tool],84)85```8687## A tool call may be denied before your function ever runs8889In a generated agent, a tool doesn't execute unconditionally just because90the model called it. Three independent gates can intercept the call first:9192- A command-safety classifier (`command_safety.classify`) can return93 `deny`/`ask` for a shell-executing tool's argv — but only if your own94 tool guard calls it; it's a library function, not something the scaffold95 wires in automatically.96- `exfil_guard`, a `before_tool_callback` wired unconditionally into every97 generated agent, can block a call whose arguments carry a secret-shaped98 value before the tool body runs.99- During a cron run, the headless approval policy (`CronIsolationPlugin`)100 can auto-deny a non-shell tool outright, since no human is present to101 approve it.102103Design tools to expect this: surface a denial as a structured, non-fatal104result (e.g. `{"status": "error", "error": "..."}`, matching the Return105Format Convention above) rather than assuming the function body always106runs — the model should see a normal tool-error response it can react to,107not a crash. Load `adk-long-horizon-guardrails` for the command-safety108classifier and `exfil_guard`, and `adk-cron-isolation` for the headless109denial policy.110111## References112113- Load `tool-patterns` for complete CRUD, API wrapper, file-ops, and search tool implementations.114- Load `tool-context-api` for the full ToolContext API reference (state, actions, artifacts).115- Load `async-tool-examples` for async tool patterns with `aiohttp`, `asyncpg`, etc.