docs/tools/tool-search.md
Tool Search is an experimental OpenClaw agent runtime feature. It gives agents one compact way to discover and call large tool catalogs. It is useful when the run has many available tools but the model is likely to need only a few of them.
This page documents OpenClaw Tool Search. It is not the Codex-native tool
search or dynamic-tools surface. Codex-native code mode, tool search, deferred
dynamic tools, and nested tool calls are stable Codex harness surfaces and do
not depend on tools.toolSearch.
When enabled for OpenClaw runs, the model receives one tool_search_code tool
by default. That tool runs a short JavaScript body in an isolated Node
subprocess with 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 can include OpenClaw tools, plugin tools, MCP tools, and client-provided tools. The model does not see every full schema up front. Instead, it searches compact descriptors, describes one selected tool when it needs the exact schema, and calls that tool through OpenClaw.
Codex harness runs do not receive these experimental OpenClaw Tool Search controls. OpenClaw passes product capabilities to Codex as dynamic tools, and Codex owns the stable native code mode, native tool search, deferred dynamic tools, and nested tool calls.
At planning time the OpenClaw embedded runner builds the effective catalog for the run:
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
normal policy, approval, hook, logging, and result handling still apply.
tools.toolSearch has three model-facing modes:
code: exposes tool_search_code, the default compact JavaScript bridge.tools: exposes tool_search, tool_describe, and tool_call as plain
structured tools for providers that should not receive code.directory: exposes tool_search, tool_describe, and tool_call plus a
bounded prompt directory of available tool names and descriptions for
providers that should see tool names without every full schema. OpenClaw can
also expose a small bounded set of likely or required tool schemas directly
for the current turn.All modes use the same policy-filtered catalog and normal OpenClaw execution
path. If the current runtime cannot launch the isolated Node code-mode child
process, the default code mode falls back to tools before catalog
compaction. In directory mode, client-provided tools stay 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. Prefer direct tool exposure for small OpenClaw tool catalogs, and prefer the Codex-native stable surfaces for Codex harness runs.
There is no separate source-selection config. When Tool Search is enabled, the catalog includes eligible OpenClaw, MCP, and client tools after normal policy filtering.
Large catalogs are useful but expensive. Sending every tool schema to the model makes the request larger, slows planning, and increases accidental tool selection.
Tool Search changes the shape:
Direct tool exposure is still the right default for small catalogs. Tool Search is best when one run can see many tools, especially from MCP servers or client-provided app tools.
openclaw.tools.search(query, options?)
Searches the effective catalog for the current run. Results are compact and safe to put back into prompt context.
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.
const calendarCreate = await openclaw.tools.describe("mcp:calendar:create_event");
openclaw.tools.call(id, args)
Calls a selected tool through OpenClaw.
await openclaw.tools.call(calendarCreate.id, {
summary: "Planning",
start: "2026-05-09T14:00:00Z",
});
The structured fallback mode exposes the same operations as tools:
tool_searchtool_describetool_callDirectory mode exposes:
tool_searchtool_describetool_callIt also keeps client-provided tools directly visible and may expose a small
bounded set of likely or required catalog tool schemas directly for the current
turn. If the bounded directory omits entries, use tool_search to find them. If
the model requests an exact hidden directory tool name directly, OpenClaw
hydrates it from the authorized catalog before normal execution.
Directory-mode client tool names must not collide with OpenClaw, plugin, or MCP
tool names because exact deferred dispatch uses those names.
The code bridge runs in a short-lived Node subprocess. The subprocess starts with Node permission mode enabled, an empty environment, no filesystem or network grants, and no child-process or worker grants. OpenClaw enforces a parent-process wall-clock timeout and kills the subprocess on timeout, including after async continuations.
The runtime exposes only:
console.log, console.warn, and console.erroropenclaw.tools.searchopenclaw.tools.describeopenclaw.tools.callNormal OpenClaw behavior still applies to final calls:
before_tool_call hooksEnable 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:
{
tools: {
toolSearch: {
mode: "code",
codeTimeoutMs: 10000,
searchDefaultLimit: 8,
maxSearchLimit: 20,
},
},
}
Disable it:
{
tools: {
toolSearch: false,
},
}
Tool Search records enough telemetry to compare it with direct tool exposure:
Session logs should make it possible to answer:
The gateway E2E runner proves both paths with the OpenClaw runtime:
node --import tsx scripts/tool-search-gateway-e2e.ts
It creates a temporary fake plugin with a large tool catalog, starts the mock OpenAI provider, starts a Gateway once in direct mode and once with Tool Search enabled, then compares provider request payloads and session logs.
The regression proves:
Tool Search should fail closed:
tool_call should failmode: "tools" or
disable Tool Search for that deployment