feat(mcp): share one serve --mcp per project across MCP clients (#411)
One shared, detached daemon per project root: every `codegraph serve --mcp` is a thin stdio<->socket proxy (Unix socket / Windows named pipe) to it, so N agents in one repo share a single file watcher, SQLite connection, and tree-sitter warm-up instead of N copies. The daemon outlives any single session and reaps via client-refcount + idle timeout; `CODEGRAPH_NO_DAEMON=1` opts out. Hardened during review: detached-process lifecycle (preserves the #277 watchdog via the proxy; the daemon no longer orphans on host SIGKILL), atomic lockfile + pid-verified stale-clear (no double-daemon on concurrent startup), realpath root canonicalization. Validated on macOS, Linux (Docker - 3x fewer inotify watches for 3 agents), and Windows (named pipes); A/B confirms byte-identical tool output vs direct mode. Closes #411. Co-Authored-By: Colby McHenry <me@colbymchenry.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Colby McHenry
Claude Opus 4.7
parent
2721165604
commit
995da54430
@@ -103,7 +103,12 @@ describe.skipIf(process.platform === 'win32')('MCP PPID watchdog (#277)', () =>
|
||||
stdinHolder.unref();
|
||||
const child = spawn(process.execPath, [${JSON.stringify(BIN)}, 'serve', '--mcp'], {
|
||||
stdio: [stdinHolder.stdout, 'ignore', stderrFd],
|
||||
env: { ...process.env, CODEGRAPH_PPID_POLL_MS: '200' },
|
||||
// Pin to direct (in-process) mode: this test targets the in-process
|
||||
// server's PPID watchdog (#277). The detached-daemon/proxy watchdog is
|
||||
// covered separately in mcp-daemon.test.ts ("daemon survives the first
|
||||
// client dying"). Without this the spawned process becomes a proxy and
|
||||
// also spawns a detached daemon that would outlive the test.
|
||||
env: { ...process.env, CODEGRAPH_PPID_POLL_MS: '200', CODEGRAPH_NO_DAEMON: '1' },
|
||||
detached: true,
|
||||
});
|
||||
child.unref();
|
||||
|
||||
Reference in New Issue
Block a user