- Create
src/tools/builtin/my_tool.rs - Implement the
Tooltrait - Add
mod my_tool;andpub useinsrc/tools/builtin/mod.rs - Register in
ToolRegistry::register_builtin_tools()inregistry.rs - Add tests
WASM tools are the preferred way to add new capabilities. They run in a sandboxed environment with explicit capabilities.
- Create a new crate in
tools-src/<name>/ - Implement the WIT interface (
wit/tool.wit) - Create
<name>.capabilities.jsondeclaring required permissions - Build with
cargo build --target wasm32-wasip2 --release - Install with
ironclaw tool install path/to/tool.wasm
See tools-src/ for examples.
CRITICAL: Keep tool-specific logic out of the main agent codebase.
The main agent provides generic infrastructure; tools are self-contained units that declare their requirements through capabilities files.
- API endpoints the tool needs (HTTP allowlist)
- Credentials required (secret names, injection locations)
- Rate limits and timeouts
- Auth setup instructions (see below)
- Workspace paths the tool can read
- Service-specific auth flows (OAuth for Notion, Slack, etc.)
- Service-specific CLI commands (
auth notion,auth slack) - Service-specific configuration handling
- Hardcoded API URLs or token formats
Tools declare their auth requirements in <tool>.capabilities.json under the auth section. Two methods are supported:
For services that support OAuth, users just click through browser login:
{
"auth": {
"secret_name": "notion_api_token",
"display_name": "Notion",
"oauth": {
"authorization_url": "https://api.notion.com/v1/oauth/authorize",
"token_url": "https://api.notion.com/v1/oauth/token",
"client_id_env": "NOTION_OAUTH_CLIENT_ID",
"client_secret_env": "NOTION_OAUTH_CLIENT_SECRET",
"scopes": [],
"use_pkce": false,
"pending_instructions": "If the provider blocks the shared OAuth app, configure your own client credentials and retry.",
"extra_params": { "owner": "user" }
},
"env_var": "NOTION_TOKEN"
}
}To enable OAuth for a tool:
- Register a public OAuth app with the service (e.g., notion.so/my-integrations)
- Configure redirect URIs:
http://localhost:9876/callbackthroughhttp://localhost:9886/callback - Set environment variables for client_id and client_secret
OAuth tools can also declare auth.oauth.pending_instructions to show provider-specific
guidance next to the auth URL while the flow is pending. This is useful for recovery
paths such as custom client credentials when a shared OAuth app is blocked.
For services without OAuth or when OAuth isn't configured:
{
"auth": {
"secret_name": "openai_api_key",
"display_name": "OpenAI",
"instructions": "Get your API key from platform.openai.com/api-keys",
"setup_url": "https://platform.openai.com/api-keys",
"token_hint": "Starts with 'sk-'",
"env_var": "OPENAI_API_KEY"
}
}When running ironclaw tool auth <tool>:
- Check
env_var- if set in environment, use it directly - Check
oauth- if configured, open browser for OAuth flow - Fall back to
instructions+ manual token entry
The agent reads auth config from the tool's capabilities file and provides the appropriate flow. No service-specific code in the main agent.
Both are first-class in the extension system (ironclaw tool install handles both), but they have different strengths.
WASM Tools (IronClaw native)
- Sandboxed: fuel metering, memory limits, no access except what's allowlisted
- Credentials injected by host runtime, tool code never sees the actual token
- Output scanned for secret leakage before returning to the LLM
- Auth (OAuth/manual) declared in
capabilities.json, agent handles the flow - Single binary, no process management, works offline
- Cost: must build yourself in Rust, no ecosystem, synchronous only
MCP Servers (Model Context Protocol)
- Growing ecosystem of pre-built servers (GitHub, Notion, Postgres, etc.)
- Any language (TypeScript/Python most common)
- Can do websockets, streaming, background polling
- Cost: external process with full system access (no sandbox), manages own credentials, IronClaw can't prevent leaks
Decision guide:
| Scenario | Use |
|---|---|
| Good MCP server already exists | MCP |
| Handles sensitive credentials (email send, banking) | WASM |
| Quick prototype or one-off integration | MCP |
| Core capability you'll maintain long-term | WASM |
| Needs background connections (websockets, polling) | MCP |
| Multiple tools share one OAuth token (e.g., Google suite) | WASM |
The LLM-facing interface is identical for both (tool name, schema, execute), so swapping between them is transparent to the agent.