Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nearai/ironclaw/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Tools are IronClaw’s interface to the outside world. They enable the agent to perform actions: call APIs, read files, execute code, search memory, and more. The tool system is designed for security, extensibility, and self-expansion.

Tool Types

Built-in Tools

Core tools written in Rust
  • echo, time, json
  • http, web_fetch
  • shell, read_file, write_file
  • memory_search, memory_write

WASM Tools

Sandboxed tools in WebAssembly
  • User-built tools
  • Dynamically created by agent
  • Capability-based security
  • Hot-reloadable

MCP Servers

Model Context Protocol extensions
  • Filesystem access
  • Database connections
  • External APIs
  • Third-party integrations

Tool Trait

All tools implement a common interface:
#[async_trait]
pub trait Tool: Send + Sync {
    /// Tool name (must be unique)
    fn name(&self) -> &str;
    
    /// Human-readable description for LLM
    fn description(&self) -> &str;
    
    /// JSON Schema for parameters
    fn parameters_schema(&self) -> serde_json::Value;
    
    /// Execute the tool
    async fn execute(
        &self,
        params: serde_json::Value,
        ctx: &JobContext,
    ) -> Result<ToolOutput, ToolError>;
    
    /// Execution domain (orchestrator vs container)
    fn domain(&self) -> ToolDomain {
        ToolDomain::Orchestrator
    }
    
    /// Require user approval before execution
    fn requires_approval(&self, _params: &serde_json::Value) -> ApprovalRequirement {
        ApprovalRequirement::NotRequired
    }
    
    /// Rate limiting configuration
    fn rate_limit_config(&self) -> Option<ToolRateLimitConfig> {
        None
    }
    
    /// Execution timeout
    fn execution_timeout(&self) -> Duration {
        Duration::from_secs(30)
    }
}

Built-in Tools

Utility Tools

Description: Simple echo for testing and debuggingParameters:
{
  "message": "string"
}
Example:
{
  "message": "Hello, world!"
}
// Returns: "Hello, world!"
Description: Returns current time in various formatsParameters:
{
  "format": "iso8601 | unix | human",
  "timezone": "UTC | America/New_York | ..."
}
Example:
{
  "format": "human",
  "timezone": "America/Los_Angeles"
}
// Returns: "Tuesday, March 3, 2026 at 2:30 PM PST"
Description: Query, transform, and validate JSON dataParameters:
{
  "operation": "parse | stringify | query | validate",
  "data": "string or object",
  "path": "optional JSONPath query"
}
Example:
{
  "operation": "query",
  "data": {"users": [{"name": "Alice", "age": 30}]},
  "path": "$.users[0].name"
}
// Returns: "Alice"

Network Tools

Description: Call external APIs with full controlParameters:
{
  "url": "string",
  "method": "GET | POST | PUT | DELETE",
  "headers": {"key": "value"},
  "body": "optional request body",
  "credential": "optional credential name"
}
Credential Injection:
{
  "url": "https://api.openai.com/v1/chat/completions",
  "method": "POST",
  "credential": "OPENAI_API_KEY",
  "headers": {"Content-Type": "application/json"},
  "body": "{...}"
}
// Orchestrator injects: Authorization: Bearer sk-...
// Tool never sees actual key
The tool requests a credential by name, but never sees the actual value. The orchestrator injects it at the HTTP boundary.
Description: Fetch URLs and convert HTML to readable markdownParameters:
{
  "url": "string",
  "selector": "optional CSS selector",
  "convert_to_markdown": true
}
Example:
{
  "url": "https://docs.example.com/api",
  "selector": "article.documentation",
  "convert_to_markdown": true
}
// Returns clean markdown of documentation
Features:
  • HTML to Markdown conversion
  • CSS selector filtering
  • JavaScript rendering (headless browser)
  • Image alt-text extraction

File Tools

Description: Read files from the working directoryDomain: Container (sandboxed environment only)Parameters:
{
  "path": "string"
}
Security:
  • Only available in Docker containers
  • Cannot read files outside job workspace
  • Path traversal (../) blocked
Description: Create or overwrite filesDomain: ContainerParameters:
{
  "path": "string",
  "content": "string"
}
Approval: Requires user approval for destructive operations
Description: List files and directoriesDomain: ContainerParameters:
{
  "path": "string",
  "recursive": false
}
Description: Apply code changes via unified diff formatDomain: ContainerParameters:
{
  "patch": "unified diff string"
}
Example:
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,4 @@
 fn main() {
+    println!("Hello, world!");
     // existing code
 }

Memory Tools

Description: Full-text + semantic search using Reciprocal Rank FusionParameters:
{
  "query": "string",
  "limit": 10
}
Example:
{
  "query": "project alpha deployment issues",
  "limit": 5
}
Returns:
[
  {
    "path": "projects/alpha/notes.md",
    "score": 0.89,
    "content": "Deployment failed due to...",
    "chunk_index": 3
  },
  ...
]
Description: Create or update workspace filesParameters:
{
  "path": "string",
  "content": "string",
  "mode": "write | append"
}
Automatic Indexing: Written content is automatically:
  • Chunked (500 char chunks with 50 char overlap)
  • Embedded (vector embeddings for semantic search)
  • Indexed (BM25 for full-text search)
Description: Read a specific workspace file by pathParameters:
{
  "path": "string"
}
Description: List workspace files and directoriesParameters:
{
  "directory": "string",
  "recursive": false
}

WASM Sandbox

Untrusted tools run in isolated WebAssembly containers.

Architecture

┌───────────────────────────────────────────────────────────┐
│                   WASM Tool Execution                     │
│                                                           │
│  Tool Call ──► Validate ──► Allowlist ──► Inject ──► Run │
│                Schema      Endpoints     Creds      WASM  │
│                                                           │
│                      ◄──── Leak Scan ◄──── Result        │
│                            Sanitize                       │
└───────────────────────────────────────────────────────────┘

Capability System

WASM tools start with zero capabilities:
Capabilities::none()
// Can only process JSON input/output
// No network, no secrets, no filesystem

Security Boundaries

Threat: Infinite loops, CPU exhaustionProtection:
const DEFAULT_FUEL_LIMIT: u64 = 200_000_000;
// Approximately 2 seconds of execution
Behavior:
  • Fuel consumed per WASM instruction
  • Automatic termination when fuel exhausted
  • Per-execution timeout (30s default)

Host Functions

WASM tools can call host-provided functions:
// Logging
log(level: u8, message: &str)

// Time
time_now() -> i64

// HTTP (if capability granted)
http_call(
    url: &str,
    method: &str,
    headers: &str,
    body: &str,
    credential_name: Option<&str>
) -> Result<HttpResponse>

// Workspace (if capability granted)
workspace_read(path: &str) -> Result<String>
workspace_write(path: &str, content: &str) -> Result<()>
workspace_search(query: &str, limit: u32) -> Result<Vec<SearchResult>>

// Tool Invocation (if capability granted)
invoke_tool(name: &str, params: &str) -> Result<String>

Building WASM Tools

1

Create Rust Project

cargo new --lib my_tool
cd my_tool
2

Add Dependencies

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

[lib]
crate-type = ["cdylib"]
3

Implement Tool

use serde::{Deserialize, Serialize};

#[derive(Deserialize)]
struct Input {
    query: String,
}

#[derive(Serialize)]
struct Output {
    result: String,
}

#[no_mangle]
pub extern "C" fn execute(input_ptr: *const u8, input_len: usize) -> u64 {
    let input = unsafe {
        std::slice::from_raw_parts(input_ptr, input_len)
    };
    
    let params: Input = serde_json::from_slice(input).unwrap();
    
    let output = Output {
        result: format!("Processed: {}", params.query),
    };
    
    let output_json = serde_json::to_vec(&output).unwrap();
    
    // Return pointer and length as u64
    let ptr = output_json.as_ptr() as u64;
    let len = output_json.len() as u64;
    (ptr << 32) | len
}
4

Build WASM Module

cargo build --target wasm32-wasip1 --release
5

Register with IronClaw

let wasm_bytes = std::fs::read(
    "target/wasm32-wasip1/release/my_tool.wasm"
)?;

registry.register_wasm(WasmToolRegistration {
    name: "my_tool",
    wasm_bytes: &wasm_bytes,
    runtime: &runtime,
    capabilities: Capabilities::none(),
    limits: None,
    description: Some("My custom tool"),
    schema: Some(serde_json::json!({
        "type": "object",
        "properties": {
            "query": {"type": "string"}
        },
        "required": ["query"]
    })),
    secrets_store: None,
    oauth_refresh: None,
}).await?;
Use the build_software tool to have IronClaw build WASM tools for you automatically.

Dynamic Tool Building

IronClaw can build new tools on the fly.

Build Software Tool

{
  "description": "Build a tool that fetches cryptocurrency prices from CoinGecko API",
  "software_type": "wasm_tool",
  "language": "rust",
  "requirements": [
    "Fetch price for a given coin ID",
    "Support USD, EUR, GBP currencies",
    "Return current price and 24h change"
  ]
}

Build Process

Iterative Refinement

The builder uses an iterative loop:
  1. Plan: Break down requirements into steps
  2. Generate: Write code using LLM
  3. Compile: Build in Docker sandbox
  4. Test: Run test cases
  5. Fix: If tests fail, analyze errors and regenerate
  6. Validate: Ensure schema matches
  7. Register: Add to tool registry
The builder can iterate up to 10 times to fix compilation errors and test failures.

MCP Protocol

Model Context Protocol servers provide additional capabilities.

MCP Architecture

┌─────────────────────────────────────────────────────┐
│                  IronClaw Core                      │
│                                                     │
│  ┌──────────────────────────────────────────────┐  │
│  │           MCP Client Manager              │  │
│  │                                              │  │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  │  │
│  │  │ Filesystem  │ PostgreSQL │  │  GitHub  │  │  │
│  │  │   MCP    │  │    MCP   │  │   MCP    │  │  │
│  │  └─────┬────┘  └─────┬────┘  └─────┬────┘  │  │
│  └────────┼─────────────┼─────────────┼───────┘  │
│           │             │             │          │
│           └─────────────┴─────────────┘          │
│                         │                        │
│                    Tool Registry                 │
└─────────────────────────────────────────────────┘

MCP Server Configuration

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/projects"],
      "env": {}
    },
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "POSTGRES_CONNECTION_STRING": "postgresql://..."
      }
    }
  }
}

MCP Tool Wrapping

MCP server tools are automatically wrapped as IronClaw tools:
// MCP server exposes: read_file, write_file, list_directory
// IronClaw wraps as:
tool_registry.register("mcp_filesystem_read_file")
tool_registry.register("mcp_filesystem_write_file")  
tool_registry.register("mcp_filesystem_list_directory")
MCP servers run as untrusted processes. Do not grant them access to sensitive credentials.

Tool Registry

Central registry managing all available tools.
pub struct ToolRegistry {
    tools: RwLock<HashMap<String, Arc<dyn Tool>>>,
    builtin_names: RwLock<HashSet<String>>,
    credential_registry: Option<Arc<SharedCredentialRegistry>>,
    secrets_store: Option<Arc<dyn SecretsStore>>,
    rate_limiter: RateLimiter,
}

Protected Tool Names

Core tools cannot be shadowed:
const PROTECTED_TOOL_NAMES: &[&str] = &[
    "echo", "time", "json", "http", "shell",
    "read_file", "write_file", "list_dir",
    "memory_search", "memory_write", "memory_read",
    "create_job", "list_jobs", "cancel_job",
    "build_software",
    // ... and more
];
Dynamically registered tools (WASM, MCP) cannot override protected names. This prevents malicious tools from replacing security-critical operations.

Tool Discovery

// List all tools
let tools = registry.list().await;

// Get tool definitions for LLM
let definitions = registry.tool_definitions().await;

// Get specific tool
let tool = registry.get("memory_search").await;

// Check if tool exists
if registry.has("crypto_price").await {
    // ...
}

Rate Limiting

Per-tool rate limits prevent abuse:
pub struct ToolRateLimitConfig {
    pub max_calls: u32,      // Max calls per window
    pub window_secs: u64,    // Window duration
    pub burst_size: Option<u32>, // Allow bursts
}

Approval System

Sensitive operations require user approval:
pub enum ApprovalRequirement {
    NotRequired,
    Required { reason: String },
    ConditionallyRequired { condition: Box<dyn Fn(&Value) -> bool> },
}
Example: Conditional Approval
impl Tool for WriteFileTool {
    fn requires_approval(&self, params: &Value) -> ApprovalRequirement {
        let path = params["path"].as_str().unwrap_or("");
        
        if path.ends_with(".rs") || path.ends_with(".toml") {
            ApprovalRequirement::Required {
                reason: "Modifying source code".into()
            }
        } else {
            ApprovalRequirement::NotRequired
        }
    }
}
Approval Flow:
  1. Tool execution requested
  2. Check requires_approval(params)
  3. If required, send StatusUpdate::ApprovalNeeded
  4. Wait for user response
  5. Execute if approved, skip if denied

Next Steps

WASM Sandbox

Deep dive into WASM security and capabilities

MCP Integration

Connect Model Context Protocol servers

Building Tools

Create custom tools dynamically

Tool Examples

Real-world tool implementations

Build docs developers (and LLMs) love