Skip to content
Back to skills

Adk Tool Creation

ASecurity

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.

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 2, 2026
ai-agentspythongoshellreactrailsapi

Works with

  • api

Security analysis

A100/100

Pro scans all 4 files and shows the line behind each finding

Scanned October 2, 2026

npx -y skills add Folken2/nuvel --skill adk-tool-creation --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Adk Tool Creation?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Adk Tool Creation
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/folken2-adk-tool-creation/badge)](https://www.skillsdirectory.com/skills/folken2-adk-tool-creation)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: adk-tool-creation
description: >-
  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.
---

# ADK Tool Creation

## Core Rules

1. Every tool is a plain Python function wrapped in `FunctionTool`.
2. Required signature pattern:
   ```python
   def my_tool(param1: str, param2: int, tool_context: ToolContext) -> dict:
   ```
3. Always return a `dict` with at minimum `"status"` and either `"message"` or `"data"` keys.
4. Handle errors gracefully — return `{"status": "error", "error": "description"}`. **Never raise exceptions** from a tool; the framework cannot recover from them gracefully.
5. 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.
6. Use type hints for **every** parameter — the framework inspects them to build the tool schema sent to the model.
7. Access session state via `tool_context.state["key"]` for reading and writing.
8. To escalate (exit a LoopAgent early): `tool_context.actions.escalate = True`.
9. To skip LLM summarisation of the tool result: `tool_context.actions.skip_summarization = True`.
10. Wrap the function: `my_tool_instance = FunctionTool(func=my_tool)`.

## Quick-Start Template

```python
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

```python
# 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

```python
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.

Files in this skill

  • SKILL.md4.5 KB
  • references/async-tool-examples.md6.6 KB
  • references/tool-context-api.md5.1 KB
  • references/tool-patterns.md10.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.