Tools — Lifecycle & Registry
Define, register, sandbox-test, and wire custom tools into agents. Includes inline and registry-based tool definitions.
Tools are functions agents can call during a conversation. AgentBreeder supports two kinds:
| Kind | When to use |
|---|---|
| Custom function tool | A Python function you write — registered with a JSON Schema |
| MCP server tool | An MCP server exposing tools over stdio or HTTP — see MCP Servers → |
Both kinds are stored in the shared org tool registry and referenced the same way in agent.yaml.
Standard library (shipped)
AgentBreeder ships a small first-party stdlib at engine.tools.standard.*. Two tools are available out of the box:
| Tool | Module | Purpose |
|---|---|---|
web-search | engine.tools.standard.web_search | Tavily-backed web search |
markdown-writer | engine.tools.standard.markdown_writer | Write a Markdown file to disk |
Reference these from agent.yaml exactly like any other registered tool: tools: [{ref: tools/web-search}, {ref: tools/markdown-writer}].
Concepts
| Concept | Meaning |
|---|---|
| Registry tool | Tool stored by name — retrieved by ref at deploy time |
| Inline tool | Tool defined directly in agent.yaml — no registry entry needed |
| JSON Schema | Defines the input (and optionally output) shape of the tool |
| Sandbox | Isolated Docker container for testing tool code before wiring to an agent |
| Usage graph | Which agents in the org reference this tool — visible in Studio and API |
Step 1 — Define
Write a Python function. The function signature becomes the tool's input schema.
# tools/order_lookup.py
def order_lookup(order_id: str, include_tracking: bool = False) -> dict:
"""
Look up an order by ID.
Args:
order_id: The order ID (format: ORD-XXXXXX)
include_tracking: Whether to include shipping tracking info
Returns:
dict with order status, items, and optionally tracking
"""
# Your implementation here
return {
"order_id": order_id,
"status": "shipped",
"items": ["Widget A", "Widget B"],
"tracking": "1Z999AA10123456784" if include_tracking else None,
}Define the JSON Schema for the tool's inputs:
{
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order ID in format ORD-XXXXXX"
},
"include_tracking": {
"type": "boolean",
"description": "Whether to include shipping tracking info",
"default": false
}
},
"required": ["order_id"]
}Step 2 — Register
Go to Registry → Tools → New Tool. Fill in:
- Name — slug-friendly (e.g.,
order-lookup) - Type —
function,mcp, orapi - Description — shown in the registry and to agents
- Schema — paste your JSON Schema
- Endpoint — URL if the tool is hosted (optional for function tools)
Click Register. The tool is now available as tools/order-lookup.
# Push a tool — auto-detects language from the input:
# .py file → endpoint = python:<abs_path>
# .ts/.js/.mjs → endpoint = node:<abs_path>
# module path → kept as-is for in-process import (e.g., engine.tools.standard.web_search)
agentbreeder registry tool push tools/order_lookup.py \
--description "Look up an order by ID, with optional tracking info"
agentbreeder registry tool push engine.tools.standard.web_search \
--description "Tavily web search"
# List tools
agentbreeder registry tool list
# Run a tool with structured args
agentbreeder registry tool run order-lookup \
--args '{"order_id": "ORD-123456", "include_tracking": true}'All registry tool commands require AGENTBREEDER_API_TOKEN (a JWT from POST /api/v1/auth/login). tool run requires the deployer role.
curl -X POST http://localhost:8000/api/v1/registry/tools \
-H "Content-Type: application/json" \
-d '{
"name": "order-lookup",
"description": "Look up an order by ID, with optional tracking info",
"tool_type": "function",
"schema_definition": {
"type": "object",
"properties": {
"order_id": { "type": "string", "description": "Order ID (ORD-XXXXXX)" },
"include_tracking": { "type": "boolean", "default": false }
},
"required": ["order_id"]
},
"source": "manual"
}'Response:
{
"data": {
"id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"name": "order-lookup",
"description": "Look up an order by ID...",
"tool_type": "function",
"status": "active",
"source": "manual",
"created_at": "2026-04-14T00:00:00Z"
}
}from agenthub import Agent
agent = (
Agent("support-agent")
.with_framework("langgraph")
.with_tools([
"tools/order-lookup", # registry reference
"tools/zendesk-mcp",
])
.with_deploy(cloud="aws", runtime="app-runner")
)import { Agent } from "@agentbreeder/sdk";
const agent = new Agent("support-agent")
.withFramework("langgraph")
.withTools(["tools/order-lookup", "tools/zendesk-mcp"])
.withDeploy({ cloud: "aws", runtime: "app-runner" });Auto-Discover Tools with Scan
Run agentbreeder scan to discover tools from MCP servers and model gateways on your machine. Discovered tools are auto-registered in the registry and immediately usable as tools/ refs:
agentbreeder scan
# Found MCP servers:
# zendesk stdio ./.mcp.json (3 tools)
# slack stdio ./.mcp.json (5 tools)Step 3 — Sandbox Test
Before wiring a tool into a live agent, test it in an isolated Docker sandbox. The sandbox runs your Python code with 256MB memory, no network access by default, and a 30-second timeout.
curl -X POST http://localhost:8000/api/v1/tools/sandbox/execute \
-H "Content-Type: application/json" \
-d '{
"code": "def run(input):\n return {\"order_id\": input[\"order_id\"], \"status\": \"shipped\"}",
"input_json": { "order_id": "ORD-123456" },
"timeout_seconds": 15,
"network_enabled": false,
"tool_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}'Response:
{
"data": {
"execution_id": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"output": "{\"order_id\": \"ORD-123456\", \"status\": \"shipped\"}",
"stdout": "{\"order_id\": \"ORD-123456\", \"status\": \"shipped\"}\n",
"stderr": "",
"exit_code": 0,
"duration_ms": 142,
"timed_out": false,
"error": null
}
}Sandbox in Studio
Open any tool in the registry, click Test in Sandbox, paste your input JSON, and click Run. Output, stdout, stderr, and duration are shown inline.
Network access
Set network_enabled: true only if your tool code calls external services. Keep it false during unit testing to avoid flaky results and accidental side effects.
Step 3b — Execute / Try it (registered tools)
Once a tool is registered, run it directly without the sandbox. The execute endpoint dispatches based on the endpoint field stored on the tool record:
curl -X POST http://localhost:8000/api/v1/registry/tools/{tool_id}/execute \
-H "Authorization: Bearer $AGENTBREEDER_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"args": { "query": "transformer attention", "max_results": 3 }
}'Response:
{
"data": {
"output": { "results": [ /* ... */ ] },
"stdout": "",
"stderr": "",
"exit_code": 0,
"duration_ms": 412,
"error": null
}
}Endpoint dispatch
engine/tool_runner.py picks a dispatcher from the endpoint prefix:
| Prefix | Dispatcher | Example |
|---|---|---|
engine.tools.standard.<name> | In-process Python import | markdown-writer, ~25 ms |
python:<abs_path> | Python subprocess | get-current-time, ~50 ms |
node:<abs_path> | Node subprocess via npx tsx | get-utc-time, ~1.5 s cold |
http(s)://... | HTTP POST with JSON body | (configurable) |
Auth: requires the deployer role.
Try it tab in Studio
Open any tool at /tools/:id and switch to the Try it tab. Studio auto-generates a form from the tool's SCHEMA, you fill in the inputs, hit Run, and the result panel shows output, stdout/stderr, exit code, and duration inline.
Step 4 — Use in agent.yaml
name: microlearning-ebook-agent
framework: google_adk
tools:
- ref: tools/web-search # engine.tools.standard.web_search
- ref: tools/markdown-writer # engine.tools.standard.markdown_writer
- ref: tools/order-lookup # your own registered tool
- ref: mcp-servers/slack # MCP server also referenced as a toolname: support-agent
framework: langgraph
tools:
- name: get_current_time
type: function
description: "Return the current UTC time as ISO 8601"
schema:
type: object
properties: {}
required: []name: support-agent
framework: langgraph
tools:
- ref: tools/order-lookup # from registry
- name: get_current_time # inline, no registry entry needed
type: function
description: "Return the current UTC time"
schema:
type: object
properties: {}Resolver chain (local → stdlib → registry)
tools[].ref is resolved by engine.tool_resolver.resolve_tool() in this order:
- Local override —
<project>/tools/<snake_name>.py(a file in your project always wins) - Standard library —
engine.tools.standard.<snake_name>(first-party, e.g.,web_search,markdown_writer) - Registry API — metadata fetched from
/api/v1/registry/tools(the caller wraps the returned dict into a callable)
The TypeScript counterpart is resolveTool() in engine/runtimes/templates/node/_shared_loader.ts — same precedence, with local .ts / .js / .mjs files first, then registry metadata.
Wiring agent.py
# agent.py
from pathlib import Path
from engine.tool_resolver import resolve_tool
web_search = resolve_tool("tools/web-search", project_root=Path(__file__).parent)
markdown_writer = resolve_tool("tools/markdown-writer", project_root=Path(__file__).parent)
# Use them with whatever framework you're on:
TOOLS = [web_search, markdown_writer]Import-shadow gotcha (stdlib tools)
engine/tools/standard/__init__.py must not re-export tool functions. If it does, import engine.tools.standard.web_search as ws_mod returns the function, not the module — and any registry-seed script that reads ws_mod.SCHEMA breaks at startup. Keep __init__.py empty (or limit it to package metadata).
Step 5 — Discover Tool Usage
Find every agent in your org that uses a specific tool — useful before removing or updating a tool.
GET /api/v1/registry/tools/{tool_id}/usageResponse:
{
"data": [
{ "agent_id": "abc...", "agent_name": "support-agent", "agent_status": "deployed" },
{ "agent_id": "def...", "agent_name": "triage-agent", "agent_status": "deployed" }
]
}Tool YAML Schema
Tools can also be defined in a standalone tool.yaml file and registered via CLI:
spec_version: v1
name: order-lookup
version: 1.0.0
description: Look up an order by ID with optional tracking
team: customer-success
owner: alice@company.com
tags: [orders, ecommerce]
type: function # function | mcp | api
input_schema:
type: object
properties:
order_id:
type: string
description: Order ID in format ORD-XXXXXX
include_tracking:
type: boolean
default: false
required: [order_id]
output_schema:
type: object
properties:
order_id: { type: string }
status: { type: string }
tracking: { type: string, nullable: true }
implementation:
language: python
entrypoint: tools/order_lookup.py:order_lookup
dependencies:
- requests==2.31.0
timeout_seconds: 30
network_access: falseAPI Reference
| Method | Path | Description |
|---|---|---|
POST | /api/v1/registry/tools | Register a tool |
GET | /api/v1/registry/tools | List tools (filter by tool_type, source) |
GET | /api/v1/registry/tools/{id} | Get tool with full schema |
GET | /api/v1/registry/tools/{id}/usage | List agents using this tool |
POST | /api/v1/registry/tools/{id}/execute | Run a registered tool (dispatches by endpoint prefix; requires deployer role) |
POST | /api/v1/tools/sandbox/execute | Execute tool code in isolated sandbox |
Next Steps
| What | Where |
|---|---|
| Add MCP servers as tools | MCP Servers → |
| Build a knowledge base | Knowledge Bases → |
| Register system prompts | Prompts → |
| Full agent.yaml fields | agent.yaml Reference → |