# Google Adk Function Tool

> Create custom function tools for ADK agents. Use when writing Python functions that agents can call — covers docstring conventions, ToolContext, FunctionTool, async tools, and state manipulation via tools.

- Skill: `eagleisbatman/google-adk-function-tool` (Agent Skill)
- Install (CLI): `npx skillmds@latest add eagleisbatman/google-adk-function-tool`
- Raw SKILL.md: https://api.skillmd.com/api/skills/eagleisbatman/google-adk-function-tool/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: eagleisbatman (https://skillmd.com/u/eagleisbatman)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/eagleisbatman/google-adk-function-tool

---


# Google ADK — Function Tools

## Core Concept

Any Python function with a docstring becomes a tool. ADK auto-converts it to a `FunctionTool` with schema derived from type hints and docstring.

## Basic Function Tool

```python
def get_weather(city: str) -> dict:
    """Retrieves the current weather for a city.

    Args:
        city: The name of the city to get weather for.

    Returns:
        dict with status and weather report.
    """
    # Implementation
    return {"status": "success", "report": f"Sunny in {city}, 25°C"}

root_agent = Agent(
    name="weather_agent",
    model="gemini-2.5-flash",
    instruction="Help users check weather.",
    tools=[get_weather],
)
```

## Function Tool Requirements

1. **Must have a docstring** — used as the tool description for the LLM
2. **Must have type hints** — used to generate the JSON schema
3. **Args section in docstring** — each parameter needs a description
4. **Return type** — helps the LLM understand the response

## Using ToolContext

`ToolContext` gives tools access to session state, artifacts, and agent actions:

```python
from google.adk.tools.tool_context import ToolContext

def save_preference(preference: str, tool_context: ToolContext) -> str:
    """Saves a user preference to session state.

    Args:
        preference: The preference to save.
    """
    tool_context.state["user_preference"] = preference
    return f"Saved preference: {preference}"

def get_history(tool_context: ToolContext) -> str:
    """Retrieves conversation history from state."""
    history = tool_context.state.get("history", [])
    return "\n".join(history) if history else "No history."
```

**Note:** `tool_context` parameter is automatically injected — do NOT include it in the docstring Args.

## ToolContext Capabilities

| Property/Method | Description |
|----------------|-------------|
| `tool_context.state` | Read/write session state dict |
| `tool_context.actions` | Control agent flow (skip_summarization, escalate, transfer_to_agent) |
| `tool_context.function_call_id` | ID of the current function call |
| `tool_context.function_call_event` | The event that triggered this tool |

## Async Function Tools

```python
import aiohttp

async def fetch_data(url: str) -> dict:
    """Fetches data from a URL.

    Args:
        url: The URL to fetch data from.

    Returns:
        The response data as a dictionary.
    """
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.json()
```

## Explicit FunctionTool

For more control, wrap explicitly:

```python
from google.adk.tools import FunctionTool

def _internal_search(query: str) -> list[str]:
    """Searches the internal knowledge base.

    Args:
        query: Search query string.
    """
    return ["result1", "result2"]

search_tool = FunctionTool(func=_internal_search)

agent = Agent(
    name="searcher",
    model="gemini-2.5-flash",
    tools=[search_tool],
)
```

## Manipulating Agent Flow via ToolContext

```python
def transfer_to_specialist(department: str, tool_context: ToolContext) -> str:
    """Transfers the conversation to a specialist department.

    Args:
        department: The department to transfer to (billing, technical, sales).
    """
    tool_context.actions.transfer_to_agent = department
    return f"Transferring to {department}."

def escalate_issue(reason: str, tool_context: ToolContext) -> str:
    """Escalates the issue to a human operator.

    Args:
        reason: Why this needs human intervention.
    """
    tool_context.actions.escalate = True
    return f"Escalated: {reason}"
```

## Working with Artifacts

```python
from google.adk.tools.tool_context import ToolContext
from google.genai import types
import json

async def save_report(report: str, tool_context: ToolContext) -> str:
    """Saves a generated report as an artifact.

    Args:
        report: The report content to save.
    """
    artifact = types.Part.from_text(text=report)
    version = await tool_context.save_artifact("report.txt", artifact)
    return f"Report saved (version {version})."

async def load_report(tool_context: ToolContext) -> str:
    """Loads the previously saved report."""
    artifact = await tool_context.load_artifact("report.txt")
    if artifact:
        return artifact.text
    return "No report found."
```

## Supported Parameter Types

| Python Type | JSON Schema Type |
|-------------|-----------------|
| `str` | string |
| `int` | integer |
| `float` | number |
| `bool` | boolean |
| `list[str]` | array of strings |
| `dict` | object |
| `Optional[str]` | string (nullable) |
| Enum | string with enum values |
| Pydantic BaseModel | object with properties |

## Key Rules

- Function name becomes the tool name the LLM sees
- Docstring is the tool description — make it clear and actionable
- `tool_context` is NEVER shown to the LLM — it's injected automatically
- Return strings for simple responses, dicts for structured data
- Keep tools focused — one action per tool
- Use descriptive names: `get_weather` not `gw`, `save_document` not `save`

## Related Skills

- `google-adk-llm-agent` — Attaching tools to agents
- `google-adk-callbacks` — Before/after tool callbacks
- `google-adk-mcp-tool` — MCP server tools
- `google-adk-openapi-tool` — REST API tools from OpenAPI specs

