Tool Handling
Control which tools Claude can use and intercept tool executions at runtime.
Allow List
Only permit specific tools:
const result = await claude.ask("Analyze the codebase", {
toolHandler: {
allowed: ["Read", "Glob", "Grep"],
},
});Any tool not in the list is automatically denied.
Block List
Block specific tools while allowing everything else:
const result = await claude.ask("Refactor utils", {
toolHandler: {
blocked: ["Bash", "Write"],
},
});Custom Handler
Intercept each tool use with a callback:
const result = await claude.ask("Fix the bug", {
toolHandler: {
onToolUse: async (tool) => {
console.log(`Claude wants to use ${tool.toolName}`);
if (tool.toolName === "Edit") {
return "approve";
}
if (tool.toolName === "Bash") {
return "deny";
}
// Provide a custom result instead of running the tool
return { result: "mocked file contents" };
},
},
});The handler receives a TToolUseEvent and must return one of:
"approve"- let the tool execute"deny"- block the tool{ result: string }- skip execution, send this as the (successful) tool result{ result: string, isError: true }- same, but mark the result as an error so the model treats it as a tool-side failure and can react (retry, fall back, apologize) instead of treating it as success
toolHandler: {
onToolUse: async (tool) => {
if (tool.toolName === "Bash" && isDestructive(tool.input)) {
return { result: "Destructive shell commands are disabled in this sandbox.", isError: true };
}
return "approve";
},
},Error Recovery
If onToolUse throws, the stream rejects with the thrown error. Provide onError to log, recover, or force a decision:
const result = await claude.ask("Fix the bug", {
toolHandler: {
onToolUse: async (tool) => {
return await riskyPolicyCheck(tool);
},
onError: (err, tool) => {
logger.warn(`policy check failed for ${tool.toolName}`, err);
return "deny";
},
},
});onError returns the same decision shape as onToolUse. If it also throws, the error propagates.
Precedence
When multiple options are set, they're evaluated in this order:
blocked- if the tool is blocked, deny immediatelyallowed- if an allow list exists and the tool isn't in it, denyonToolUse- call the custom handler- Default - approve
Built-in Tools
claude-wire exports a set of known built-in Claude Code tools:
import { BUILT_IN_TOOLS, isBuiltInTool } from "@pivanov/claude-wire";
console.log(BUILT_IN_TOOLS); // Set { "Read", "Write", "Edit", "Bash", ... }
console.log(isBuiltInTool("Read")); // true
console.log(isBuiltInTool("my-mcp-tool")); // falseWARNING
BUILT_IN_TOOLS is a best-effort snapshot and may not include tools added in newer Claude Code versions. For the authoritative list, check the tools array in the session_meta event from a live session.