OpenClaw Tool Search: Compact Tool Catalogs for Agents

Learn how OpenClaw Tool Search streamlines locating and invoking tools from large catalogs. This page is for developers using the OpenClaw agent runtime who need efficient tool management.

Read this when

  • You want OpenClaw agents to use a large tool catalog without adding every tool schema to the prompt
  • You want OpenClaw tools, MCP tools, and client tools exposed through one compact runtime surface
  • You are implementing or debugging tool discovery for OpenClaw runs

Tool Search is an experimental feature of the OpenClaw agent runtime. It offers agents a single, streamlined method for locating and invoking tools from extensive catalogs. This proves valuable when a run exposes numerous tools, yet the model likely only requires a handful.

This page covers OpenClaw Tool Search. It should not be confused with the Codex-native tool search or dynamic-tools interface. The stable Codex harness surfaces, which include native code mode, tool search, deferred dynamic tools, and nested tool calls, operate independently of tools.toolSearch.

For the standard OpenClaw runtime that provides a QuickJS-WASI exec/wait interface instead of Tool Search controls, refer to Code Mode.

When activated for OpenClaw runs, the model automatically gets a constrained listing of available trusted tool names and their descriptions. By default, it also receives one tool_search_code tool, along with any direct-only tools whose structured outputs cannot traverse the compact bridge. The code tool executes a brief JavaScript body within an isolated Node subprocess using an openclaw.tools bridge:

const hits = await openclaw.tools.search("create a GitHub issue");
const tool = await openclaw.tools.describe(hits[0].id);
return await openclaw.tools.call(tool.id, {
  title: "Crash on startup",
  body: "Steps to reproduce...",
});

The catalog may include catalog-eligible OpenClaw tools, plugin tools, MCP tools, and client-provided tools. The directory gives the model insight into which trusted capabilities it can find without exposing every cataloged schema upfront. It also notes that policy-approved MCP and client tools might be discoverable. Their untrusted names and descriptions are not placed in the system prompt. Rather, the model searches compact descriptors, requests details on one selected tool when the precise schema is needed, and invokes that tool via OpenClaw. Direct-only tools stay visible to the model and are excluded from the catalog.

Codex harness runs do not get these experimental OpenClaw Tool Search controls. OpenClaw passes product capabilities to Codex as dynamic tools, while Codex manages the stable native code mode, native tool search, deferred dynamic tools, and nested tool calls.

How a turn runs

During planning, the OpenClaw embedded runner constructs the effective catalog for the run:

  1. Resolve the active tool policy for the agent, profile, sandbox, and session.
  2. Enumerate eligible OpenClaw and plugin tools.
  3. Enumerate eligible MCP tools via the session MCP runtime.
  4. Add eligible client tools provided for the current run.
  5. Keep core coding primitives and direct-only tools model-visible, and index compact descriptors for the remaining catalog-eligible tools.
  6. Add a deterministic, bounded, policy-filtered capability directory to the cache-stable system-prompt prefix.
  7. Expose the OpenClaw code bridge, the structured fallback tools, or the compact directory surface alongside those stable, directly callable tools.

At execution time, every real tool call returns to OpenClaw. The isolated Node runtime does not hold plugin implementations, MCP client objects, or secrets. openclaw.tools.call(...) crosses the bridge back into the Gateway, where the standard policy, approval, hook, logging, and result handling continue to apply.

Modes

tools.toolSearch offers three model-facing modes:

  • code: presents tool_search_code, the default compact JavaScript bridge, together with the capability directory and direct-only tools.
  • tools: presents tool_search, tool_describe, and tool_call as plain structured tools for providers that should not receive code, alongside the capability directory and direct-only tools.
  • directory: presents tool_search, tool_describe, and tool_call plus a bounded, cache-stable prompt directory. Core coding primitives, direct-only tools, and tools required by the run's delivery policy remain visible; other schemas stay deferred.

All modes rely on the same policy-filtered catalog and standard OpenClaw execution path. Tools marked catalogMode: "direct-only" remain outside that catalog and stay model-visible. If the current runtime cannot start the isolated Node code-mode child process, the default code mode falls back to tools before catalog compaction. In directory mode, client-provided tools remain directly visible for the current run, while OpenClaw tools, plugin tools, and MCP tools can be compacted behind the directory catalog. A direct call to an exact hidden directory name is hydrated from that same authorized catalog before execution.

All modes are experimental. For small OpenClaw tool catalogs, direct tool exposure is preferred, and for Codex harness runs, the Codex-native stable surfaces are preferred.

There is no separate source-selection config. When Tool Search is enabled, the catalog includes catalog-eligible OpenClaw, MCP, and client tools after normal policy filtering; direct-only tools are retained separately.

Why this exists

Large catalogs are beneficial but costly. Sending every tool schema to the model enlarges the request, slows planning, and raises the chance of accidental tool selection.

Tool Search alters the shape:

  • direct tools: the model sees every selected schema before the first token
  • Tool Search code mode: the model sees one compact code tool, a bounded capability directory, a short API contract, and any direct-only tools
  • Tool Search tools mode: the model sees three compact structured fallback tools, the same capability directory, and any direct-only tools
  • Tool Search directory mode: the model sees a bounded directory plus search/describe/call controls, policy-required direct tools, and any direct-only tools
  • during the turn: the model can load remaining schemas as needed

Direct tool exposure remains the proper default for small catalogs. Tool Search is ideal when a single run can encounter many tools, particularly from MCP servers or client-provided app tools.

The capability directory is sorted by tool name, capped at 18,000 characters, and derived from the already policy-filtered catalog. OpenClaw reuses the rendered directory for an unchanged catalog snapshot and positions it above the system-prompt cache boundary. User messages, per-turn tool guesses, session identifiers, and untrusted MCP or client metadata do not enter the directory. This preserves prompt KV-cache reuse for repeated turns. When the authorized catalog changes, OpenClaw generates a new directory for the new snapshot.

API

openclaw.tools.search(query, options?)

Searches the effective catalog for the current run.

Queries must be in English. Ranking uses lexical matching (Okapi BM25 over tool names, descriptions, and first-party parameter names and descriptions), with light English stemming so scheduling reaches a tool described as Schedule a recurring task, and a small intent expansion so look up the price reaches one described as Search the web. Tool names and descriptions are in English, so a query in another language will usually match nothing. It is not rejected, since a catalog may legitimately describe a tool in another script, but it is also no longer answered with an arbitrary slice of the catalog presented as if it were ranked, which is what the previous scorer did whenever a query produced no usable terms. Both tool_search and the code-mode bridge state this requirement in their model-facing descriptions.

Untrusted parameter schemas are never indexed. MCP and client tools are matched on name and description only, which is the same boundary that defers their input signatures as input: "unknown".

Results are compact and safe to put back into prompt context. Each hit includes a bounded TypeScript-style input signature, such as { id: string; mode?: "drip" | "flood" }, so the model can skip describe when that signature is sufficient. A trusted OpenClaw core or plugin tool may also include a compact output hint, such as Array<{ id: string; paid: boolean }>. MCP and client output-schema claims are not promoted into this trusted hint. Their untrusted input schemas are also deferred as input: "unknown"; use describe before calling them. Open, oversized, or otherwise partial output schemas omit the hint and remain available through describe instead.

const hits = await openclaw.tools.search("calendar event", { limit: 5 });

openclaw.tools.describe(id)

Loads full metadata for one search result, including the exact input schema and the trusted full outputSchema when the tool declares one.

const calendarCreate = await openclaw.tools.describe("mcp:calendar:create_event");

openclaw.tools.call(id, args)

Calls a selected tool through OpenClaw and returns the raw { tool, result } envelope. JSON-returning tools normally place their value in result.details. OpenClaw validates a trusted core or plugin tool's declared input schema before execution. Missing required arguments, incorrect types, and forbidden properties return actionable tool errors instead of executing the tool; misspelled properties include a suggested parameter when available. If a trusted tool also declares outputSchema, OpenClaw compiles that schema before execution and validates final details after normal tool hooks before returning the catalog call. MCP and client-owned schemas remain deferred to their owning execution boundary.

In structured mode, tool_call also fixes flattened target arguments coming from local models. Fields such as id and name are preserved, and ambiguous tool selectors get rejected rather than triggering the wrong tool. When a target field matches another cataloged tool, place the target arguments under args.

await openclaw.tools.call(calendarCreate.id, {
  summary: "Planning",
  start: "2026-05-09T14:00:00Z",
});

Tool authors specify output contracts through the tool's outputSchema property. This describes AgentToolResult.details, not the rendered content blocks. Either include every non-throwing variant, or leave it out when results are unstable. Refer to Code Mode output contracts and Tool plugins for details.

The structured fallback mode makes the same operations available as tools:

  • tool_search
  • tool_describe
  • tool_call

tool_search handles both the existing single-query format and a batch of independent queries:

{
  "query": "today's calendar events",
  "limit": 3
}
{
  "queries": [
    { "query": "today's calendar events", "limit": 3 },
    { "query": "Slack messages needing attention", "limit": 3 }
  ]
}

Single-query calls still return the compact candidate array directly. For batch calls, the response is { results: [{ query, candidates }] } in request order. Every query applies the same effective catalog, ranking, filtering, and per-query limit as a standard search, and a candidate can show up in multiple result groups. Descriptions get compacted before output. If the whole batch goes over the 4,000-character response budget, lower-ranked candidates are dropped and the response includes truncated: true. A result group that lost candidates also includes truncated: true, so an empty truncated group cannot be confused with a query that produced no matches. When a per-query limit is omitted, searchDefaultLimit is used. Across one batch, the effective limits may request at most 50 candidates total. A batch accepts up to 16 queries, each limited to 512 characters and 512 UTF-8 bytes for the serialized query list. Invalid batches fail as a single request, while a valid query with no matches returns an empty candidates array.

Directory mode exposes:

  • tool_search
  • tool_describe
  • tool_call

Core file and shell primitives, client-provided tools, direct-only tools, and policy-required delivery tools remain directly visible. Other authorized tool schemas stay deferred instead of shifting with each user prompt. MCP tools cannot impersonate a directly visible core or policy-required delivery tool. When the bounded directory omits entries, use tool_search to locate them and tool_describe to fetch their full schemas. If the model asks for an exact hidden directory tool name directly, OpenClaw resolves it from the authorized catalog before normal execution. Client tool names in directory mode must not clash with OpenClaw, plugin, or MCP tool names, since exact deferred dispatch relies on those names.

Runtime boundary

The code bridge runs in a short-lived Node subprocess. That subprocess launches with Node permission mode on, an empty environment, no filesystem or network grants, and no child-process or worker grants. OpenClaw applies a parent-process wall-clock timeout and terminates the subprocess when it expires, including after async continuations. When the child settles, whether through a fatal exit or a final result, outstanding bridged tool calls are canceled. Failed exits wait for stderr to drain before rendering a bounded diagnostic. The error separately reports bytes discarded from the 64 KiB retained tail and bytes omitted from its final text preview.

The runtime exposes only:

  • console.log, console.warn, and console.error
  • openclaw.tools.search
  • openclaw.tools.describe
  • openclaw.tools.call

Final calls still follow normal OpenClaw behavior:

  • tool allow and deny policies
  • per-agent and per-sandbox tool restrictions
  • channel/runtime tool policy
  • approval hooks
  • plugin before_tool_call hooks
  • session identity, logs, and telemetry

Config

Enable Tool Search for OpenClaw runs with the default code bridge:

openclaw config set tools.toolSearch true

Equivalent JSON:

{
  tools: {
    toolSearch: true,
  },
}

Use the structured fallback tools instead for OpenClaw runs:

{
  tools: {
    toolSearch: {
      mode: "tools",
    },
  },
}

Use the compact directory surface instead for OpenClaw runs:

{
  tools: {
    toolSearch: {
      mode: "directory",
    },
  },
}

Tune code-mode timeout and search result limits (values shown are the defaults):

{
  tools: {
    toolSearch: {
      mode: "code",
      codeTimeoutMs: 10000,
      searchDefaultLimit: 8,
      maxSearchLimit: 20,
    },
  },
}

The runtime clamps codeTimeoutMs to 1000-60000, maxSearchLimit to 1-50, and searchDefaultLimit to 1..maxSearchLimit.

Disable it:

{
  tools: {
    toolSearch: false,
  },
}

Prompt and telemetry

Code mode attaches a telemetry object to every tool_search_code result:

  • catalogSize: number of catalog entries the runtime resolved
  • sources: catalog entry counts split into openclaw, mcp, and client
  • counterScope: opaque identifier for the counter lifetime; it stays stable when tools are appended or prompt policy narrows the catalog, and changes when the catalog is replaced or restored
  • searchCount, describeCount, callCount: running totals for the catalog session, carried across calls rather than reset per call

tools and directory mode do not produce a telemetry object; their tool_search, tool_describe, and tool_call results contain only the catalog data relevant to that operation. OpenClaw keeps no record of serialized tool or prompt byte counts. The E2E scenario calculates provider payload bytes separately from the mock provider lane, not from the runtime.

No matter the mode, completed target calls persist as bounded, redacted display activity in session history without introducing synthetic model turns for replay. Search, describe, and call results include each tool's id and source. As a result, session logs still provide answers to:

  • how many tool schemas the model encountered initially
  • how many search and describe operations were executed
  • which final tool was invoked
  • whether the outcome came from OpenClaw, MCP, or a client tool

E2E validation

The QA Lab gateway scenario validates all three paths using the OpenClaw runtime:

pnpm openclaw qa suite --provider-mode mock-openai --scenario tool-search-gateway-e2e

It sets up a temporary fake plugin with a large tool catalog, launches the mock OpenAI provider, and then executes the Gateway in direct, code-mode Tool Search, and structured Tool Search modes. It compares provider request payloads for direct and code mode, then checks session logs and tool flow across all three lanes.

The regression confirms:

  1. Direct mode can invoke the fake plugin tool.
  2. Tool Search can invoke the same fake plugin tool.
  3. Direct mode exposes the fake plugin tool schemas directly to the provider.
  4. Tool Search exposes only the compact bridge plus any direct-only tools.
  5. The Tool Search request payload is smaller for the large fake catalog.
  6. Session logs show the expected tool-call counts and bridged call telemetry.
  7. Structured mode resolves two queries with one tool_search call before the selected plugin tool runs through tool_call.

Failure behavior

Tool Search should fail closed:

  • if a tool is absent from the effective policy, search should not return it
  • if a selected tool becomes unavailable, tool_call should fail
  • if policy or approval blocks execution, the call result should report that block instead of bypassing it
  • if the code bridge cannot create an isolated runtime, use mode: "tools" or disable Tool Search for that deployment
2,555 words · updated Sep 1, 2026