musistudio/claude-code-router · error · Error
Unknown browser automation tool: ${name}
Error message
Unknown browser automation tool: ${name} What it means
Thrown by runTool's switch default branch when the tools/call name does not match any implemented browser automation tool. The MCP server dispatches on a fixed set of tool names; anything else reaches the default case and is rejected rather than silently ignored.
Source
Thrown at packages/electron/src/main/browser-automation-mcp.ts:1094
{
deltaX: readNumber(args.deltaX) ?? 0,
deltaY: readNumber(args.deltaY) ?? 700
}
);
case "browser_wait_for":
await this.ensureBrowserOpen();
return await waitForPageCondition(
builtInBrowserService.getAutomationWebContents(readString(args.tabId)),
{
selector: readString(args.selector),
text: readString(args.text),
timeoutMs: clampInteger(readNumber(args.timeoutMs) ?? defaultWaitTimeoutMs, 100, 120000),
urlIncludes: readString(args.urlIncludes),
urlMatches: readString(args.urlMatches)
}
);
default:
throw new Error(`Unknown browser automation tool: ${name}`);
}
}
private async ensureBrowserOpen(): Promise<BuiltInBrowserState> {
await builtInBrowserService.openHidden(await loadAppConfig());
return builtInBrowserService.getAutomationState();
}
private async ensureBrowserVisible(): Promise<BuiltInBrowserState> {
await builtInBrowserService.open(await loadAppConfig());
return builtInBrowserService.getAutomationState();
}
private async openSession(args: Record<string, unknown>): Promise<unknown> {
let state = await this.ensureBrowserOpen();
const url = readString(args.url);
const requestedTabId = readString(args.tabId);
const previousActiveTabId = state.activeTabId;View on GitHub (pinned to 99f24806c6)
Solutions
- List available tools first via the MCP tools/list method and use an exact name from the result.
- Check for typos and the exact tool naming (browser_ prefix, snake_case).
- Align client and server versions so advertised tools match implemented ones.
Example fix
// before
await call("browser_tab_activte", { tabId });
// after
const tools = await listTools();
await call("browser_tab_activate", { tabId }); Defensive patterns
Strategy: validation
Validate before calling
const { tools } = await mcp.listTools();
const known = new Set(tools.map((t) => t.name));
if (!known.has(name)) throw new Error(`Unknown tool ${name}; available: ${[...known].join(", ")}`);
await call(name, args); Try / catch
try { await call(name, args); } catch (e) { if (e instanceof Error && e.message.includes("Unknown browser automation tool")) { /* re-list tools, correct name or skip */ } throw e; } Prevention
- Drive tool choice from tools/list output
- Pin client/server versions
- For LLM agents, constrain tool selection to the advertised list
When it happens
Trigger: Calling tools/call with a name like 'browser_click', 'navigate_page', or a typo such as 'browser_tab_activte'; also calling a tool that exists in a newer/older server version than the caller targets.
Common situations: Version skew between client tool list and server implementation; LLM-generated tool names that hallucinate plausible-but-nonexistent tools; typos in hand-written automation scripts.
Related errors
- browser_tab_activate requires tabId or session.
- browser_tab_close requires tabId or session.
- browser_navigate could not resolve an active tab.
- Chrome login import job was not found: ${jobId}
- Browser tab was not found: ${tabId}
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/3de19657d001c298.
Report an issue: GitHub.