{"record":{"id":"6ea332b87d842d15","repo":"abhigyanpatwari/GitNexus","slug":"unknown-tool-method","errorCode":null,"errorMessage":"Unknown tool: ${method}","messagePattern":"Unknown tool: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/mcp/local/local-backend.ts","lineNumber":2551,"sourceCode":"      case 'explore':\n        return this.context(repo, {\n          name: typeof p.name === 'string' ? p.name : undefined,\n          ...p,\n        });\n      case 'overview':\n        return this.overview(repo, p);\n      case 'route_map':\n        return this.routeMap(repo, p);\n      case 'shape_check':\n        return this.shapeCheck(repo, p);\n      case 'tool_map':\n        return this.toolMap(repo, p);\n      case 'api_impact':\n        return this.apiImpact(repo, p);\n      case 'trace':\n        return this.trace(repo, p);\n      default:\n        throw new Error(`Unknown tool: ${method}`);\n    }\n  }\n\n  // ─── Tool Implementations ────────────────────────────────────────\n\n  /** Check repository graph invariants that are suitable for CI gating. */\n  private async check(repo: RepoHandle, params?: { cycles?: boolean }): Promise<any> {\n    if (params?.cycles === false) {\n      return { error: 'No checks selected. Set \"cycles\" to true.' };\n    }\n    await this.ensureInitialized(repo);\n    const rowLimit = 100_001;\n    // determinism: probe — overflow guard, not a window. The one-past cap is compared for exact equality below\n    // and the whole result is REPLACED by an error, so a truncated page never reaches a caller.\n    const rows = await executeParameterized(\n      repo.lbugPath,\n      // A cycle here means \"these modules cannot be initialized in any order\".\n      // Only edges that force initialization count, so four kinds are excluded:","sourceCodeStart":2533,"sourceCodeEnd":2569,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/0d1aed942f0e8b5d3bac27519fff441aceea722d/gitnexus/src/mcp/local/local-backend.ts#L2533-L2569","documentation":"LocalBackend's tool dispatch switch (overview, route_map, shape_check, tool_map, api_impact, trace, ...) fell through to default: the method string does not name any tool this backend implements. It is a pure name mismatch — the request reached the right backend but asked for an unknown capability.","triggerScenarios":"An MCP client calling a tool name the installed GitNexus version does not implement: typos, tools renamed or not yet shipped in that version, or stale client configs written against different GitNexus docs. Also direct backend calls in tests with a wrong method string.","commonSituations":"Version skew between the MCP client config (or AI-agent instructions) and the installed gitnexus package; agents hallucinating tool names; tool families that moved namespaces (e.g. group_* tools folded into the repo parameter, cf. the group-tool variant); copy-pasted examples from newer docs on older installs.","solutions":["List the tools the backend actually serves (MCP tools/list, or the GitNexus MCP docs for your installed version) and correct the name.","Update gitnexus (`npm update -g gitnexus`) if the docs you followed are newer than your install.","Check for renames: removed group_query/group_contracts/group_status must be expressed as repo \"@<groupName>\" on impact/query/context or via MCP resources.","Fix typos in hand-rolled client code that builds method strings dynamically."],"exampleFix":"// before: unknown/renamed method\nawait backend.callTool('route-map', { repo: 'myrepo' });   // hyphen vs underscore\n\n// after: exact tool name from tools/list\nawait backend.callTool('route_map', { repo: 'myrepo' });\n// removed group tools → new form:\nawait callTool('query', { search_query: 'x', repo: '@mygroup' });","handlingStrategy":"validation","validationCode":"// Fetch the server's real tool list and validate before dispatch\nconst { tools } = await client.listTools();\nconst known = new Set(tools.map((t: { name: string }) => t.name));\n\nfunction assertKnownTool(method: string): void {\n  if (!known.has(method)) {\n    throw new Error(`Unknown tool \"${method}\". Available: ${[...known].sort().join(', ')}`);\n  }\n}","typeGuard":"const isKnownTool = (method: string, available: ReadonlySet<string>): method is string =>\n  available.has(method); // compile-time narrow via a branded tool-name type if you generate one","tryCatchPattern":"try {\n  return await backend.callTool(method, params);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Unknown tool:')) {\n    // reconcile against tools/list; surface available names instead of retrying blindly\n    const available = (await client.listTools()).tools.map((t: any) => t.name).join(', ');\n    throw new Error(`${err.message}. Server offers: ${available}`);\n  }\n  throw err;\n}","preventionTips":["Populate tool menus from MCP tools/list at runtime instead of hard-coded lists.","Pin docs and client configs to the installed gitnexus version.","Grep configs for removed/renamed tool names after upgrading gitnexus.","Validate dynamically built method strings against a whitelist before sending."],"tags":["mcp","tool-dispatch","unknown-tool","version-skew","typo"],"backgroundTag":"unknown-tool-name","analyzedSha":"0d1aed942f0e8b5d3bac27519fff441aceea722d","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}