Single-process stdio MCP session — the pre-issue-#411 code path.
(reason: string)
| 308 | |
| 309 | /** Single-process stdio MCP session — the pre-issue-#411 code path. */ |
| 310 | private async startDirect(reason: string): Promise<void> { |
| 311 | if (reason && process.env.CODEGRAPH_MCP_DEBUG) { |
| 312 | process.stderr.write(`[CodeGraph MCP] Direct mode: ${reason}.\n`); |
| 313 | } |
| 314 | this.engine = new MCPEngine(); |
| 315 | const transport = new StdioTransport(); |
| 316 | this.session = new MCPSession(transport, this.engine, { |
| 317 | explicitProjectPath: this.projectPath, |
| 318 | }); |
| 319 | |
| 320 | if (this.projectPath) { |
| 321 | // Background init so the initialize response stays fast (#172). |
| 322 | void this.engine.ensureInitialized(this.projectPath); |
| 323 | } |
| 324 | |
| 325 | this.session.start(); |
| 326 | |
| 327 | // Detect parent-process death — same logic as pre-refactor. When stdin |
| 328 | // closes we go through StdioTransport's `process.exit(0)` already, but |
| 329 | // SIGKILL of the parent doesn't reliably close stdin on Linux (#277). |
| 330 | // Also treat a stdin `'error'` (a socket-backed stdin can fail with |
| 331 | // ECONNRESET/hangup instead of a clean close) as shutdown, and destroy the |
| 332 | // stream so a hung fd can't busy-spin the event loop (#799). |
| 333 | treatStdinFailureAsShutdown(() => this.stop()); |
| 334 | // Backstop for a launch abandoned during startup (#1185): launcher killed |
| 335 | // before EARLY_PPID could see it + host holding our pipes open. A server |
| 336 | // that never receives a byte of MCP traffic isn't serving anyone. Armed |
| 337 | // after session.start() attached the real stdin consumer. |
| 338 | armStartupHandshakeTimeout(() => { |
| 339 | process.stderr.write( |
| 340 | '[CodeGraph MCP] No MCP traffic since startup; assuming an abandoned launch and shutting down (#1185). ' + |
| 341 | 'Tune with CODEGRAPH_STARTUP_HANDSHAKE_TIMEOUT_MS (0 disables).\n' |
| 342 | ); |
| 343 | this.stop(); |
| 344 | }); |
| 345 | |
| 346 | this.mode = 'direct'; |
| 347 | this.installSignalHandlers(); |
| 348 | this.installPpidWatchdog(); |
| 349 | this.livenessWatchdog = installMainThreadWatchdog(); |
| 350 | } |
| 351 | |
| 352 | /** |
| 353 | * Run as the detached shared daemon (process spawned with |
no test coverage detected