---
title: "Tools"
description: "Trait-based tool dispatch, MCP server integration, and built-in tool categories."
icon: "wrench"
---

Meerkat's tool system is trait-based. You implement `AgentToolDispatcher`, and the engine handles dispatch, parallel execution, and result injection. MCP servers are first-class -- register them and their tools appear alongside your custom tools with no code changes.

## Mental model

At the concept level, tools answer one question: **how does the agent act on the world?**

The important conceptual layers are:

- custom tools you own
- built-in tools Meerkat can compose
- MCP-provided external tools
- runtime visibility/scoping rules

The Rust trait example below is an implementation detail of that model, not the model itself.

## Custom tools

Implement the `AgentToolDispatcher` trait:

```rust
struct MathTools;

#[async_trait]
impl AgentToolDispatcher for MathTools {
    fn tools(&self) -> Arc<[Arc<ToolDef>]> {
        vec![Arc::new(ToolDef::new(
            "add",
            "Add two numbers",
            json!({
                "type": "object",
                "properties": {
                    "a": {"type": "number"},
                    "b": {"type": "number"}
                },
                "required": ["a", "b"]
            }),
        ))].into()
    }

    async fn dispatch(&self, call: ToolCallView<'_>) -> Result<ToolDispatchOutcome, ToolError> {
        match call.name {
            "add" => {
                let args: AddArgs = call.parse_args()
                    .map_err(|e| ToolError::invalid_arguments(call.name, e.to_string()))?;
                Ok(ToolResult::new(call.id.to_string(), format!("{}", args.a + args.b), false).into())
            }
            _ => Err(ToolError::not_found(call.name)),
        }
    }
}
```

`ToolCallView` is a zero-allocation borrowed view (`{ id: &str, name: &str, args: &RawValue }`). When the model requests multiple tool calls, Meerkat dispatches them in parallel.

## MCP servers

Register any MCP server and its tools automatically appear in the agent's tool set:

```bash
rkat mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem /tmp
rkat mcp add api --transport http --url https://mcp.example.com/api
```

Config is stored in `.rkat/mcp.toml` (project) or `~/.rkat/mcp.toml` (user). Supports stdio, streamable HTTP, and SSE transports. See the [MCP reference](/api/mcp) for full details.

## Built-in tools

Meerkat ships with tool categories you enable per-agent. Nothing is on by default -- you choose what your agent can do.

| Category | Tools | Enable with |
|----------|-------|-------------|
| Builtins | `task_create`, `task_list`, `task_get`, `task_update`, `datetime`, `apply_patch`, `view_image`, `generate_image`, `blob_save_file`, `blob_load_file`, `blob_inspect` | `enable_builtins` |
| Shell | `shell`, `shell_jobs`, `shell_job_status`, `shell_job_cancel` | `enable_shell` |
| Memory | `memory_search` | `enable_memory` |
| Scheduler | `meerkat_schedule_*` | `enable_schedule` |
| WorkGraph | `workgraph_*` | `enable_workgraph` |
| Comms | `send_message`, `send_request`, `send_response`, `peers` | `enable_comms` |
| Mob orchestration | `mob_*`, `meerkat_*` | `enable_mob` |

Shell tools support allow/deny list security policies. Runtime tool visibility can also be shaped with mob overlays and turn-boundary tool-scope updates. See the [built-in tools reference](/reference/builtin-tools) for parameter details.

For nontrivial Meerkat-owned tool families, companion skills provide the agent
instruction manual. Tool descriptions stay short and schema-oriented; skills
such as `workgraph-workflow`, `schedule-workflow`, `task-workflow`, and
`shell-patterns` explain the operating posture for the tool family.

## Tool scoping

Tool visibility can change during a session without restarting the agent. Changes are **staged** then **atomically applied** at the turn boundary — the LLM never sees a tool list change mid-stream.

**External filters.** Callers can stage an allow-list or deny-list filter programmatically through `ToolScopeHandle`. This is distinct from MCP server lifecycle management.

**Per-turn overlays.** Mob flow steps can restrict tools for a single turn via `TurnToolOverlay` (allow + deny). The overlay is ephemeral — it's cleared after the turn completes.

**Live MCP mutation.** MCP servers can be added or removed from a running session. Additions connect the server and register its tools; removals drain in-flight calls before finalizing. Both are staged and applied at the next turn boundary.

**Composition rule:** Most-restrictive wins. Multiple allow-lists intersect, multiple deny-lists union, and deny always beats allow. The conversation records a typed `tool_config` system notice when the tool set changes, and a `tool_config_changed` event is emitted to the event stream.

### Live MCP controls

MCP servers can be added, removed, or reloaded on a running session via JSON-RPC, REST, MCP-server tools, or SDK helpers:

```json
{"jsonrpc":"2.0","id":1,"method":"mcp/add","params":{
  "session_id":"...",
  "server_config":{"name":"my-tools","command":"npx","args":["-y","@my/server"]},
  "persisted":false
}}
```

| RPC Method | Effect |
|------------|--------|
| `mcp/add` | Connect a new MCP server, register its tools |
| `mcp/remove` | Drain in-flight calls, disconnect server, remove tools |
| `mcp/reload` | Reconnect one or all servers (picks up config changes) |

All mutations are staged and applied at the next turn boundary. Set `persisted: true` to write the change to disk config so it survives restart. See the [RPC reference](/api/rpc#mcp-methods) for full parameter details.

### Surface availability

| Surface | Live MCP | External tool filter |
|---------|----------|---------------------|
| JSON-RPC | `mcp/add`, `mcp/remove`, `mcp/reload` | Via in-process `ToolScopeHandle` on the session runtime |
| CLI | `rkat mcp add/remove/list/get` edits project/user config; start or resume a session to load it | No standalone public CLI filter surface today |
| REST | `POST /sessions/{id}/mcp/add`, `remove`, `reload` | No standalone public REST filter surface today |
| MCP server | `meerkat_mcp_add`, `meerkat_mcp_remove`, `meerkat_mcp_reload` | No standalone public MCP filter surface today |

See the [built-in tools reference](/reference/builtin-tools) for the mechanical details of factory flags and per-build overrides.

## Multimodal tool results

Tools can return rich content beyond plain text. The injected runtime shape is `ToolResult.content: Vec<ContentBlock>`, with helper constructors for text-only or multimodal output.

- **`ToolResult::new(...)`** -- the standard text-only path. The string becomes a single text content block.
- **`ToolResult::with_blocks(...)`** -- returns one or more content blocks directly, including images and video.
- Built-in tools that expose richer output may internally use `ToolOutput::Blocks(...)`, but the persisted/runtime-facing result shape is still `ToolResult.content`.

`ContentBlock` currently has three variants:

- `ContentBlock::Text { text }` -- plain text content.
- `ContentBlock::Image { media_type, ... }` -- inline or blob-backed image content.
- `ContentBlock::Video { media_type, duration_ms, ... }` -- inline video content.

The built-in `view_image` tool reads an image file from disk and returns a result containing image content blocks. It supports PNG, JPEG, GIF, WebP, and SVG formats up to 5 MB. The tool is automatically hidden from models that lack vision support via capability-aware tool visibility.

The built-in `generate_image` tool is session-owned runtime dispatch. It lets a model request generated or edited images through universal fields plus provider-owned `provider_params`. Generated image bytes are stored as blobs and committed as `AssistantBlock::Image` transcript blocks, so every surface reads the same `image_id`/`blob_ref` history and fetches bytes through `blob/get` or model-facing `blob_save_file`.

The blob file bridge tools are registered only when the session has a blob store. `blob_save_file` writes decoded blob bytes to a file inside the project root, `blob_load_file` reads a project file into the blob store, and `blob_inspect` returns blob metadata without raw payload bytes. They do not expose blob listing or deletion.

Custom tools can return multimodal content by returning `ToolResult::with_blocks(...)` with the appropriate content blocks.

## Image generation

`generate_image` is a session-owned builtin for creating or editing assistant images. It is registered when builtins are enabled and the runtime-backed surface supplies the image-generation machine, provider executor, planner, and blob store. CLI sessions wire this automatically; the default `--tools safe` preset includes builtins.

The tool accepts a typed request under `request`, routes it to OpenAI or Gemini image backends, stores generated image bytes in the realm blob store, and returns structured `ImageGenerationToolResult` JSON with durable `images[].blob_ref` values. A model can then call `blob_save_file` to materialize that blob as a project file, for example `top-news-infographic.png`.

For setup, provider parameters, result fields, and troubleshooting, see [Image generation](/guides/image-generation).

## Composition

Tools from different sources (custom, MCP, built-in) are composed into a single dispatcher. The agent sees one flat tool list regardless of where each tool comes from. Hooks can observe tool calls before and after execution, and guardrails can deny unsafe calls before dispatch.

## Mob tools (`meerkat-mob-mcp`)

Mob tools (`mob_*`) are provided by the `meerkat-mob-mcp` dispatcher and composed
through the late-bound `SessionBuildOptions.mob_tools` factory slot.

- CLI `run` composes this dispatcher when the `full` tool preset is selected (`--tools full` or `--yolo`).
- `rkat mob ...` remains the explicit direct lifecycle surface.
- Other session-driven surfaces can grant the same agent-side `mob_*` capability
  by installing `AgentMobToolSurfaceFactory` into their session build path.
- Public host APIs should not re-export that raw dispatcher. They use typed
  control planes instead: `mob/*` on RPC/SDK surfaces and `meerkat_mob_*` on
  public MCP surfaces.
