diff --git a/CHANGELOG.md b/CHANGELOG.md index 8680c23..3113c05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Fixes +- Running `codegraph serve --mcp` by hand no longer just hangs in silence. That command is the MCP server your AI agent starts for itself — not a step you run directly — and in a terminal it used to sit there waiting for input that never comes, looking broken. It now recognizes when a person runs it and explains what to do instead (`codegraph status`, `codegraph daemon`), and it's been dropped from the command listing so it stops looking like something you need to launch. - Cross-file static method calls like `ClassName.staticMethod()` now resolve correctly. CodeGraph was linking the call to the *class* instead of the method (and recording it as a construction), so `callers` and `impact` for a static method came back empty — a real blind spot in TypeScript and JavaScript codebases that lean on static utility classes (Python and other languages with the same call shape benefit too). The call now links to the method itself. Thanks @contextFlow-lab. (#825) - `codegraph affected` now accepts `./`-prefixed and absolute file paths, not just bare project-relative ones. Passing `./src/x.ts` or an absolute path — common when the file list comes from another tool — used to silently match nothing and report no affected tests. Thanks @contextFlow-lab. (#825) - The CodeGraph MCP server no longer risks getting stuck at 100% CPU after an unexpected internal error. Previously such an error was logged but the process was left running in a broken state, where it could spin a CPU core indefinitely and had to be killed by hand. The server now logs the error and exits cleanly, so a fresh one starts on the next request. Thanks @songhlc. (#850) diff --git a/README.md b/README.md index 7961715..354af24 100644 --- a/README.md +++ b/README.md @@ -485,7 +485,6 @@ codegraph callers # Find what calls a function/method (--limit, codegraph callees # Find what a function/method calls (--limit, --json) codegraph impact # Analyze what code is affected by changing a symbol (--depth, --json) codegraph affected [files...] # Find test files affected by changes (see below) -codegraph serve --mcp # Start MCP server codegraph daemon # Manage background daemons — pick one to stop (alias: daemons) codegraph telemetry [on|off] # Show or change anonymous usage telemetry codegraph upgrade [version] # Update to the latest release (--check, --force) @@ -723,7 +722,7 @@ Framework routing is validated the same way, on a canonical app per framework: E - **You're on an old (pre-0.9) install.** Reinstall to get the bundled runtime — `curl -fsSL https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.sh | sh` (macOS/Linux), `irm https://raw.githubusercontent.com/colbymchenry/codegraph/main/install.ps1 | iex` (Windows), or `npm i -g @colbymchenry/codegraph@latest`. - **`codegraph status` shows `Journal:` other than `wal`** — WAL couldn't be enabled on this filesystem (common on network shares and WSL2 `/mnt`), so reads can block on writes. Move the project (with its `.codegraph/` folder) onto a local disk. -**MCP server not connecting** — Ensure the project is initialized/indexed, verify the path in your MCP config, and check that `codegraph serve --mcp` works from the command line. +**MCP server not connecting** — Your agent starts the server itself, so you don't launch it by hand. Make sure the project is initialized and indexed (`codegraph status`) and that the path in your MCP config is correct. If it still won't connect, re-run `codegraph install` to rewrite the config. **Missing symbols** — The MCP server auto-syncs on save (wait a couple seconds). Run `codegraph sync` manually if needed. Check that the file's language is supported and isn't inside a `.gitignore`d or default-excluded directory (e.g. `node_modules`, `dist`). diff --git a/__tests__/cli-version.test.ts b/__tests__/cli-version.test.ts index 2f4df0b..7a72fed 100644 --- a/__tests__/cli-version.test.ts +++ b/__tests__/cli-version.test.ts @@ -48,6 +48,13 @@ describe('codegraph version affordances', () => { expect(out).toContain('Commands:'); }); + it('hides the internal `serve` command from --help', () => { + // `serve --mcp` is the stdio entry point an AI agent launches for itself, + // not a human command — it must not appear in the listing. (It stays fully + // invocable; the mcp-initialize suite covers that the agent path works.) + expect(run(['--help'])).not.toMatch(/^\s+serve\b/m); + }); + it('a trailing `-v` is still the subcommand\'s --verbose, not the version intercept', () => { // A fresh temp dir outside any indexed project: `index -v` parses `-v` as // the index command's --verbose, then short-circuits at "not initialized" diff --git a/src/bin/codegraph.ts b/src/bin/codegraph.ts index e043ef0..12facd5 100644 --- a/src/bin/codegraph.ts +++ b/src/bin/codegraph.ts @@ -1349,7 +1349,12 @@ program * codegraph serve */ program - .command('serve') + // Hidden from `--help`: this is the stdio entry point an AI agent launches + // for itself (the installer wires `args: ['serve','--mcp']` into every + // agent's MCP config), not a command a human runs. It still works when + // invoked — hiding only removes it from the listing. See the interactive-TTY + // guard below, which explains this to anyone who runs it by hand. + .command('serve', { hidden: true }) .description('Start CodeGraph as an MCP server for AI assistants') .option('-p, --path ', 'Project path (optional for MCP mode, uses rootUri from client)') .option('--mcp', 'Run as MCP server (stdio transport)') @@ -1365,6 +1370,22 @@ program try { if (options.mcp) { + // `serve --mcp` is the stdio MCP server an AI agent launches for itself, + // not a command to run by hand. A human in a terminal would otherwise + // see it hang waiting for JSON-RPC on stdin, which reads as broken. If + // stdin is an interactive TTY, explain instead of hanging. The agent's + // pipe and the detached daemon both have a non-TTY stdin, so this only + // ever fires for a person who typed it. + if (process.stdin.isTTY && !process.env.CODEGRAPH_DAEMON_INTERNAL) { + console.error(chalk.bold('\nCodeGraph MCP server\n')); + console.error("This is the MCP server your AI agent (Claude Code, Cursor, Codex, opencode, …)"); + console.error("starts automatically — you don't run it yourself."); + console.error(`\nIt's already wired up by ${chalk.cyan('codegraph install')}. To check on things:`); + console.error(` ${chalk.cyan('codegraph status')} ${chalk.dim('— is this project indexed and healthy?')}`); + console.error(` ${chalk.cyan('codegraph daemon')} ${chalk.dim('— list or stop background MCP servers')}`); + console.error(chalk.dim('\n(Running it directly only does something when an MCP client drives it over stdin.)')); + return; + } // Start MCP server - it handles initialization lazily based on rootUri from client const { MCPServer } = await import('../mcp/index'); const server = new MCPServer(projectPath);