MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / ToolHandler

Class ToolHandler

src/mcp/tools.ts:1316–7055  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

1314 * Other projects are opened on-demand and cached for performance.
1315 */
1316export class ToolHandler {
1317 // Cache of opened CodeGraph instances for cross-project queries
1318 private projectCache: Map<string, CodeGraph> = new Map();
1319 // The directory the server last searched for a default project. Surfaced in
1320 // the "not initialized" error so users can see why detection missed.
1321 private defaultProjectHint: string | null = null;
1322 // Indexed sub-projects the engine's bounded down-scan saw below the search
1323 // base when no default project resolved (#1607). Listed in the "not
1324 // initialized" error so the fact is reachable through the protocol, not just
1325 // the host's stderr capture. Engine-maintained (initial resolve + throttled
1326 // retry) — tool calls themselves never scan.
1327 private knownSubprojects: string[] = [];
1328 private knownSubprojectsBase: string | null = null;
1329 // Per-start-path cache of the git worktree/index mismatch (issue #155). The
1330 // mismatch is a fixed property of (where the request came from → which
1331 // .codegraph/ it resolves to), so the up-to-two `git rev-parse` spawns run
1332 // once and every later tool call reuses the result — never shelling out to
1333 // git on the hot path. `undefined` = not computed yet; `null` = no mismatch.
1334 private worktreeMismatchCache: Map<string, WorktreeIndexMismatch | null> = new Map();
1335 // Gate that the MCP engine pokes after `cg.open()` so the first tool call
1336 // blocks on the post-open filesystem reconcile (catch-up sync). Without
1337 // this, a tool call that races past `catchUpSync()` serves rows for files
1338 // that were deleted (or edited) while no MCP server was running — and the
1339 // per-file staleness banner can't help, because `getPendingFiles()` is
1340 // populated by the watcher, not by catch-up. The wait is time-boxed
1341 // (see {@link resolveCatchUpGateTimeoutMs}) so a minutes-long reconcile on a
1342 // huge repo can't hang the first call (#905); cleared on first await so
1343 // subsequent calls don't pay any cost.
1344 private catchUpGate: Promise<void> | null = null;
1345 // Optional worker-thread pool for off-loop read-tool dispatch (daemon mode).
1346 // When set + healthy, the heavy read tools run on a worker so the daemon's
1347 // main loop stays free for the MCP transport under concurrent load. Null in
1348 // direct/in-process mode (one client, no concurrency to parallelize).
1349 private queryPool: QueryPool | null = null;
1350
1351 constructor(private cg: CodeGraph | null) {}
1352
1353 /**
1354 * Engine-only: attach (or detach with null) the worker-thread query pool. The
1355 * shared daemon sets this once its default project is open; the workers each
1356 * hold their own WAL read connection and run {@link executeReadTool}. A
1357 * worker's own ToolHandler never has a pool, so there is no nested off-loading.
1358 */
1359 setQueryPool(pool: QueryPool | null): void {
1360 this.queryPool = pool;
1361 }
1362
1363 /**
1364 * Update the default CodeGraph instance (e.g. after lazy initialization)
1365 */
1366 setDefaultCodeGraph(cg: CodeGraph): void {
1367 this.cg = cg;
1368 }
1369
1370 /**
1371 * Engine-only: register the catch-up sync promise so the next `execute()`
1372 * call awaits it before serving. The handler swallows rejections (the
1373 * engine logs them) so a sync failure never propagates as a tool error;

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected