Skip to main content
Custom tools extend what your agent can do. A tool is a function with a name, a description the LLM reads, a schema for inputs, and an execute function that does the actual work.

Basic Tool

Use createTool with a zod schema for the simplest approach:
The SDK converts the zod schema to JSON Schema automatically. Input is fully typed in the execute function. For working examples of tools in real agents, see the cli-agent (shell tool with zod) and code-review-bot (multiple tools with completion lifecycle).

Anatomy of a Tool

Every tool has four parts:

The Name

Use snake_case. Keep it descriptive but concise:
  • search_database, not db or performDatabaseSearchOperation
  • send_email, not email or handleEmailSending

The Description

This is the most important field for tool call accuracy. The LLM uses it to decide when and how to use the tool.
Include:
  • What the tool does
  • What it returns
  • When to use it (and when not to)
  • Constraints (rate limits, read-only, max results, etc.)

The Input Schema

With zod, use .describe() on every field:
Use z.enum for fields with a fixed set of values. This dramatically improves accuracy.

Using AgentToolContext

The execute function receives a context object with execution metadata:

Error Handling

Return errors as structured data rather than throwing:
When a tool returns an error, the agent sees it and can adjust its approach. When a tool throws, it counts as a “mistake” and increments the consecutive mistake counter.

Completion Tools

Mark a tool with lifecycle: { completesRun: true } to make it end the agent loop when called successfully:
See the code-review-bot example for this pattern in a complete application.

Testing Tools

Test your tools in isolation before giving them to an agent:

Registering Tools

Tool Design Rules

Good tools are specific and predictable.
  • Use action-oriented names: get_pull_request, search_database, deploy_service.
  • Describe what the tool does, when to use it, and what it returns.
  • Put constraints in the description: rate limits, read-only behavior, required permissions.
  • Add descriptions for every input property.
  • Return structured JSON instead of prose when possible.
  • Respect context.abortSignal in long-running tools.