> ## 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.

# Tool System

> Extensible tool architecture with WASM sandbox, MCP protocol, and dynamic building

## 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

<CardGroup cols={3}>
  <Card title="Built-in Tools" icon="box">
    Core tools written in Rust

    * `echo`, `time`, `json`
    * `http`, `web_fetch`
    * `shell`, `read_file`, `write_file`
    * `memory_search`, `memory_write`
  </Card>

  <Card title="WASM Tools" icon="cube">
    Sandboxed tools in WebAssembly

    * User-built tools
    * Dynamically created by agent
    * Capability-based security
    * Hot-reloadable
  </Card>

  <Card title="MCP Servers" icon="server">
    Model Context Protocol extensions

    * Filesystem access
    * Database connections
    * External APIs
    * Third-party integrations
  </Card>
</CardGroup>

## Tool Trait

All tools implement a common interface:

<CodeGroup>
  ```rust Tool Trait theme={null}
  #[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)
      }
  }
  ```
</CodeGroup>

## Built-in Tools

### Utility Tools

<AccordionGroup>
  <Accordion title="echo - Echo input back">
    **Description**: Simple echo for testing and debugging

    **Parameters**:

    ```json theme={null}
    {
      "message": "string"
    }
    ```

    **Example**:

    ```json theme={null}
    {
      "message": "Hello, world!"
    }
    // Returns: "Hello, world!"
    ```
  </Accordion>

  <Accordion title="time - Get current time">
    **Description**: Returns current time in various formats

    **Parameters**:

    ```json theme={null}
    {
      "format": "iso8601 | unix | human",
      "timezone": "UTC | America/New_York | ..."
    }
    ```

    **Example**:

    ```json theme={null}
    {
      "format": "human",
      "timezone": "America/Los_Angeles"
    }
    // Returns: "Tuesday, March 3, 2026 at 2:30 PM PST"
    ```
  </Accordion>

  <Accordion title="json - Parse and manipulate JSON">
    **Description**: Query, transform, and validate JSON data

    **Parameters**:

    ```json theme={null}
    {
      "operation": "parse | stringify | query | validate",
      "data": "string or object",
      "path": "optional JSONPath query"
    }
    ```

    **Example**:

    ```json theme={null}
    {
      "operation": "query",
      "data": {"users": [{"name": "Alice", "age": 30}]},
      "path": "$.users[0].name"
    }
    // Returns: "Alice"
    ```
  </Accordion>
</AccordionGroup>

### Network Tools

<AccordionGroup>
  <Accordion title="http - Make HTTP requests">
    **Description**: Call external APIs with full control

    **Parameters**:

    ```json theme={null}
    {
      "url": "string",
      "method": "GET | POST | PUT | DELETE",
      "headers": {"key": "value"},
      "body": "optional request body",
      "credential": "optional credential name"
    }
    ```

    **Credential Injection**:

    ```json theme={null}
    {
      "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
    ```

    <Warning>
      The tool requests a credential by **name**, but never sees the actual value. The orchestrator injects it at the HTTP boundary.
    </Warning>
  </Accordion>

  <Accordion title="web_fetch - Fetch and convert web pages">
    **Description**: Fetch URLs and convert HTML to readable markdown

    **Parameters**:

    ```json theme={null}
    {
      "url": "string",
      "selector": "optional CSS selector",
      "convert_to_markdown": true
    }
    ```

    **Example**:

    ```json theme={null}
    {
      "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
  </Accordion>
</AccordionGroup>

### File Tools

<AccordionGroup>
  <Accordion title="read_file - Read file contents">
    **Description**: Read files from the working directory

    **Domain**: `Container` (sandboxed environment only)

    **Parameters**:

    ```json theme={null}
    {
      "path": "string"
    }
    ```

    **Security**:

    * Only available in Docker containers
    * Cannot read files outside job workspace
    * Path traversal (`../`) blocked
  </Accordion>

  <Accordion title="write_file - Write file contents">
    **Description**: Create or overwrite files

    **Domain**: `Container`

    **Parameters**:

    ```json theme={null}
    {
      "path": "string",
      "content": "string"
    }
    ```

    **Approval**: Requires user approval for destructive operations
  </Accordion>

  <Accordion title="list_dir - List directory contents">
    **Description**: List files and directories

    **Domain**: `Container`

    **Parameters**:

    ```json theme={null}
    {
      "path": "string",
      "recursive": false
    }
    ```
  </Accordion>

  <Accordion title="apply_patch - Apply unified diff patch">
    **Description**: Apply code changes via unified diff format

    **Domain**: `Container`

    **Parameters**:

    ```json theme={null}
    {
      "patch": "unified diff string"
    }
    ```

    **Example**:

    ```diff theme={null}
    --- a/src/main.rs
    +++ b/src/main.rs
    @@ -1,3 +1,4 @@
     fn main() {
    +    println!("Hello, world!");
         // existing code
     }
    ```
  </Accordion>
</AccordionGroup>

### Memory Tools

<AccordionGroup>
  <Accordion title="memory_search - Hybrid search across workspace">
    **Description**: Full-text + semantic search using Reciprocal Rank Fusion

    **Parameters**:

    ```json theme={null}
    {
      "query": "string",
      "limit": 10
    }
    ```

    **Example**:

    ```json theme={null}
    {
      "query": "project alpha deployment issues",
      "limit": 5
    }
    ```

    **Returns**:

    ```json theme={null}
    [
      {
        "path": "projects/alpha/notes.md",
        "score": 0.89,
        "content": "Deployment failed due to...",
        "chunk_index": 3
      },
      ...
    ]
    ```
  </Accordion>

  <Accordion title="memory_write - Write to workspace">
    **Description**: Create or update workspace files

    **Parameters**:

    ```json theme={null}
    {
      "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)
  </Accordion>

  <Accordion title="memory_read - Read workspace file">
    **Description**: Read a specific workspace file by path

    **Parameters**:

    ```json theme={null}
    {
      "path": "string"
    }
    ```
  </Accordion>

  <Accordion title="memory_tree - Browse workspace structure">
    **Description**: List workspace files and directories

    **Parameters**:

    ```json theme={null}
    {
      "directory": "string",
      "recursive": false
    }
    ```
  </Accordion>
</AccordionGroup>

## WASM Sandbox

Untrusted tools run in isolated WebAssembly containers.

### Architecture

```text theme={null}
┌───────────────────────────────────────────────────────────┐
│                   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:

<CodeGroup>
  ```rust No Capabilities (Default) theme={null}
  Capabilities::none()
  // Can only process JSON input/output
  // No network, no secrets, no filesystem
  ```

  ```rust HTTP Capability theme={null}
  Capabilities::none().with_http(
      HttpCapability::new(vec![
          EndpointPattern::host("api.openai.com")
              .with_path_prefix("/v1/")
              .with_method("POST"),
      ])
  )
  ```

  ```rust Secrets Capability theme={null}
  Capabilities::none().with_secrets(
      SecretsCapability::new(vec![
          "OPENAI_API_KEY",
          "ANTHROPIC_API_KEY",
      ])
  )
  ```

  ```rust Workspace Capability theme={null}
  Capabilities::none().with_workspace(
      WorkspaceCapability::read_only()
  )
  // Or: WorkspaceCapability::read_write()
  ```

  ```rust Tool Invoke Capability theme={null}
  Capabilities::none().with_tool_invoke(
      ToolInvokeCapability::new(vec![
          "memory_search",
          "web_fetch",
      ])
  )
  ```
</CodeGroup>

### Security Boundaries

<Tabs>
  <Tab title="Fuel Metering">
    **Threat**: Infinite loops, CPU exhaustion

    **Protection**:

    ```rust theme={null}
    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)
  </Tab>

  <Tab title="Memory Limits">
    **Threat**: Unbounded allocations

    **Protection**:

    ```rust theme={null}
    pub struct ResourceLimits {
        pub memory_limit: usize, // Default: 10MB
    }
    ```

    **Behavior**:

    * Hard cap enforced by Wasmtime ResourceLimiter
    * Memory growth tracking
    * Instance discarded on overflow
  </Tab>

  <Tab title="Network Isolation">
    **Threat**: Unauthorized API calls

    **Protection**:

    ```rust theme={null}
    AllowlistValidator::validate(
        &request_url,
        &allowed_patterns
    )
    ```

    **Behavior**:

    * Every HTTP request validated against allowlist
    * Host + path + method matching
    * Deny by default
    * Leak detection on response
  </Tab>

  <Tab title="Credential Injection">
    **Threat**: Secret exposure

    **Protection**:

    ```rust theme={null}
    // WASM requests credential by name
    http_call(url, "OPENAI_API_KEY")

    // Orchestrator injects actual value
    injector.inject(&request, &secrets_store)
    ```

    **Behavior**:

    * WASM never sees actual credential
    * Injection at host boundary
    * Leak scan on all outputs
    * Automatic redaction
  </Tab>
</Tabs>

### Host Functions

WASM tools can call host-provided functions:

<CodeGroup>
  ```rust Available Host Functions theme={null}
  // 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>
  ```
</CodeGroup>

### Building WASM Tools

<Steps>
  <Step title="Create Rust Project">
    ```bash theme={null}
    cargo new --lib my_tool
    cd my_tool
    ```
  </Step>

  <Step title="Add Dependencies">
    ```toml theme={null}
    [dependencies]
    serde = { version = "1.0", features = ["derive"] }
    serde_json = "1.0"

    [lib]
    crate-type = ["cdylib"]
    ```
  </Step>

  <Step title="Implement Tool">
    ```rust theme={null}
    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
    }
    ```
  </Step>

  <Step title="Build WASM Module">
    ```bash theme={null}
    cargo build --target wasm32-wasip1 --release
    ```
  </Step>

  <Step title="Register with IronClaw">
    ```rust theme={null}
    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?;
    ```
  </Step>
</Steps>

<Tip>
  Use the `build_software` tool to have IronClaw build WASM tools for you automatically.
</Tip>

## Dynamic Tool Building

IronClaw can build new tools on the fly.

### Build Software Tool

<CodeGroup>
  ```json Request theme={null}
  {
    "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"
    ]
  }
  ```

  ```json Response theme={null}
  {
    "success": true,
    "tool_name": "crypto_price",
    "description": "Fetch cryptocurrency prices from CoinGecko",
    "parameters_schema": {
      "type": "object",
      "properties": {
        "coin_id": {"type": "string"},
        "currency": {"type": "string", "enum": ["usd", "eur", "gbp"]}
      },
      "required": ["coin_id"]
    },
    "capabilities": {
      "http": {
        "allowed_endpoints": [
          {"host": "api.coingecko.com", "path_prefix": "/api/v3/"}
        ]
      }
    }
  }
  ```
</CodeGroup>

### Build Process

```mermaid theme={null}
sequenceDiagram
    participant User
    participant LLM
    participant Builder
    participant Sandbox
    participant Registry
    
    User->>LLM: "Build a crypto price tool"
    LLM->>Builder: build_software(description, type, requirements)
    Builder->>Builder: Generate Rust code
    Builder->>Sandbox: Compile to WASM
    Sandbox->>Sandbox: cargo build --target wasm32-wasip1
    Sandbox-->>Builder: my_tool.wasm
    Builder->>Builder: Run test cases
    Builder->>Builder: Validate output
    Builder->>Registry: register_wasm(name, bytes, capabilities)
    Registry-->>User: "crypto_price tool is ready!"
```

### 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

<Info>
  The builder can iterate up to 10 times to fix compilation errors and test failures.
</Info>

## MCP Protocol

Model Context Protocol servers provide additional capabilities.

### MCP Architecture

```text theme={null}
┌─────────────────────────────────────────────────────┐
│                  IronClaw Core                      │
│                                                     │
│  ┌──────────────────────────────────────────────┐  │
│  │           MCP Client Manager              │  │
│  │                                              │  │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  │  │
│  │  │ Filesystem  │ PostgreSQL │  │  GitHub  │  │  │
│  │  │   MCP    │  │    MCP   │  │   MCP    │  │  │
│  │  └─────┬────┘  └─────┬────┘  └─────┬────┘  │  │
│  └────────┼─────────────┼─────────────┼───────┘  │
│           │             │             │          │
│           └─────────────┴─────────────┘          │
│                         │                        │
│                    Tool Registry                 │
└─────────────────────────────────────────────────┘
```

### MCP Server Configuration

<CodeGroup>
  ```json MCP Config theme={null}
  {
    "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://..."
        }
      }
    }
  }
  ```
</CodeGroup>

### MCP Tool Wrapping

MCP server tools are automatically wrapped as IronClaw tools:

```rust theme={null}
// 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")
```

<Warning>
  MCP servers run as **untrusted** processes. Do not grant them access to sensitive credentials.
</Warning>

## Tool Registry

Central registry managing all available tools.

<CodeGroup>
  ```rust Tool Registry theme={null}
  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,
  }
  ```
</CodeGroup>

### Protected Tool Names

Core tools cannot be shadowed:

```rust theme={null}
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
];
```

<Warning>
  Dynamically registered tools (WASM, MCP) cannot override protected names. This prevents malicious tools from replacing security-critical operations.
</Warning>

### Tool Discovery

```rust theme={null}
// 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:

<CodeGroup>
  ```rust Rate Limit Config theme={null}
  pub struct ToolRateLimitConfig {
      pub max_calls: u32,      // Max calls per window
      pub window_secs: u64,    // Window duration
      pub burst_size: Option<u32>, // Allow bursts
  }
  ```

  ```rust Example theme={null}
  impl Tool for CryptoPriceTool {
      fn rate_limit_config(&self) -> Option<ToolRateLimitConfig> {
          Some(ToolRateLimitConfig {
              max_calls: 60,
              window_secs: 60,
              burst_size: Some(10),
          })
      }
  }
  // 60 calls/minute, allow 10-call bursts
  ```
</CodeGroup>

## Approval System

Sensitive operations require user approval:

```rust theme={null}
pub enum ApprovalRequirement {
    NotRequired,
    Required { reason: String },
    ConditionallyRequired { condition: Box<dyn Fn(&Value) -> bool> },
}
```

**Example: Conditional Approval**

```rust theme={null}
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

<CardGroup cols={2}>
  <Card title="WASM Sandbox" icon="cube" href="/tools/wasm-sandbox">
    Deep dive into WASM security and capabilities
  </Card>

  <Card title="MCP Integration" icon="server" href="/tools/mcp-protocol">
    Connect Model Context Protocol servers
  </Card>

  <Card title="Building Tools" icon="hammer" href="/tools/building-tools">
    Create custom tools dynamically
  </Card>

  <Card title="Tool Examples" icon="code" href="/tools/examples">
    Real-world tool implementations
  </Card>
</CardGroup>
