{"record":{"id":"962c16eab9789d72","repo":"CherryHQ/cherry-studio","slug":"tool-not-found","errorCode":null,"errorMessage":"Tool not found","messagePattern":"Tool not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"src/main/ai/mcp/servers/browser/server.ts","lineNumber":41,"sourceCode":"      {\n        capabilities: {\n          resources: {},\n          tools: {}\n        }\n      }\n    )\n\n    this.mcpServer.server.setRequestHandler(ListToolsRequestSchema, async () => {\n      return {\n        tools: toolDefinitions\n      }\n    })\n\n    this.mcpServer.server.setRequestHandler(CallToolRequestSchema, async (request) => {\n      const { name, arguments: args } = request.params\n      const handler = toolHandlers[name]\n      if (!handler) {\n        throw new Error('Tool not found')\n      }\n      return handler(this.controller, args)\n    })\n\n    // Clean up browser controller when the MCP server connection closes\n    // (triggered by McpRuntimeService.onStop() → client.close())\n    this.server.onclose = () => {\n      void this.controller.dispose()\n    }\n  }\n}\n\nexport default BrowserServer\n","sourceCodeStart":23,"sourceCodeEnd":55,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/mcp/servers/browser/server.ts#L23-L55","documentation":"In BrowserServer's CallToolRequestSchema handler, the requested tool name is looked up in toolHandlers; if absent, it throws 'Tool not found'. Only the names exported from ./tools/registry (toolHandlers keys) are callable.","triggerScenarios":"An MCP client calls a tool name that is not registered — typo in the tool name, an LLM hallucinating a tool, a stale client that predates a tool rename, or a tool that was conditionally excluded from toolDefinitions.","commonSituations":"LLM invents a tool like 'click_element' that isn't in the registry; client caches an old tool list after an upgrade; casing mismatch (Navigate vs navigate).","solutions":["Re-fetch the tool list via ListTools and only call names that appear in toolDefinitions.","Verify exact tool name spelling and casing against registry.ts exports.","If a tool seems missing, confirm it isn't gated/conditionally registered in ./tools/registry."],"exampleFix":"// before\nconst handler = toolHandlers[name]\nif (!handler) {\n  throw new Error('Tool not found')\n}\n\n// after — return an MCP error result with the available tools for self-correction\nconst handler = toolHandlers[name]\nif (!handler) {\n  return {\n    content: [{ type: 'text', text: `Unknown tool: ${name}. Available: ${Object.keys(toolHandlers).join(', ')}` }],\n    isError: true\n  }\n}","handlingStrategy":"validation","validationCode":"// Only call tool names that the server actually advertises\nfunction assertToolKnown(name, toolHandlers) {\n  if (!Object.prototype.hasOwnProperty.call(toolHandlers, name)) {\n    throw new Error(`Unknown tool: ${name}. Available: ${Object.keys(toolHandlers).join(', ')}`)\n  }\n}","typeGuard":"function isRegisteredTool(name: string, handlers: Record<string, unknown>): name is string {\n  return Object.prototype.hasOwnProperty.call(handlers, name)\n}","tryCatchPattern":"const handler = toolHandlers[name]\nif (!handler) {\n  return { content: [{ type: 'text', text: `Unknown tool: ${name}. Available: ${Object.keys(toolHandlers).join(', ')}` }], isError: true }\n}","preventionTips":["Re-fetch ListTools and only call advertised names.","Verify exact spelling and casing.","Route calls to the correct server."],"tags":["mcp","browser-tool","validation","rpc"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}