defineAgent is advertised to the model, and the runtime handles the full call-validate-execute cycle automatically.
The AgentTool interface
Every tool you define implements this interface:
A unique identifier for the tool. The model uses this name when requesting a call. Use
snake_case — most model providers require it.A plain-English description of what the tool does. The model reads this to decide when to call the tool, so write it from the model’s perspective: what information does the tool provide, and when should it be used?
A Zod schema for the tool’s input. Preferred over
inputSchema — the runtime converts it to JSON Schema automatically (to advertise to the model) and validates the model’s input against it before calling execute. If validation fails, the model receives a descriptive error result instead of a crash.A raw JSON Schema for the tool’s input. Use this if you cannot express the input as a Zod schema. If both
zodSchema and inputSchema are present, zodSchema is used for validation and inputSchema is ignored.Annotates the tool as one that mutates external state (sends an email, writes to a database, calls a payment API, etc.). This is a documentation signal — use it to communicate intent to other developers reading the agent definition.
The async function that runs when the model calls this tool. Return any serializable value — it becomes the tool result fed back to the model. Throw an error to return an error result.
The ToolExecMeta argument
execute receives a second meta argument with runtime context:
The unique ID for this tool invocation, assigned by the model. Useful for correlating logs and traces.
The request’s
AbortSignal. Pass it to any fetch calls or async work inside the tool so that a client disconnect cancels in-flight I/O.Throw this to suspend the run and request human approval before proceeding (human-in-the-loop). The run is checkpointed and the client receives a
suspended event. Resume with resumeAgent after the operator approves.Complete tool example
Input validation
The runtime validates tool inputs againstzodSchema before calling execute. You never need to validate inside the function body:
Preventing infinite loops with maxIterations
By default the agent runtime caps the model↔tool loop at 10 iterations. Each call to the model counts as one iteration, regardless of how many tools it calls in that turn. Set maxIterations on defineAgent to tighten or loosen this limit:
final event with whatever text the model produced last. The stoppedAtCap flag in AgentRunResult tells you whether the run ended this way.
Standalone tools and anvil mcp
Tools defined inline in defineAgent are only available to that agent route. If you also want a tool served via the MCP protocol (for use with Claude Desktop or other MCP clients), define it as a standalone tool in server/tools/:
anvil mcp serves both server/tools/*.ts files and any MCP-exposed route-derived tools from the same endpoint. Route-level tools defined in defineAgent are not automatically MCP-exposed — only server/tools/ files and routes with meta.mcp.expose: true appear there.