From eec1f84b8db9feb50c0e4bdf261088c92342660f Mon Sep 17 00:00:00 2001 From: Josh Stein Date: Wed, 6 May 2026 15:10:13 -0700 Subject: [PATCH] fix(mcp): exit serve process on stdin-close/SIGTERM MCP stdio server was keeping the bun process alive indefinitely after the client disconnected. Over days this accumulated 20+ orphaned gbrain serve processes, all holding the PGLite directory open. Since PGLite is single-writer, this caused write-lock contention that made email-sync fail its 15s per-put timeout: 114 puts x 15s = 28.5min runs with 0 emails written. Now listens for stdin end/close, transport close, and SIGTERM/SIGINT/ SIGHUP; calls engine.disconnect() and exits cleanly. Root cause for the no-gbrain-run-in-50h alert. --- src/mcp/server.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/mcp/server.ts b/src/mcp/server.ts index e0d4eb794..3724ade7a 100644 --- a/src/mcp/server.ts +++ b/src/mcp/server.ts @@ -32,6 +32,26 @@ export async function startMcpServer(engine: BrainEngine) { const transport = new StdioServerTransport(); await server.connect(transport); + + // Exit cleanly when MCP client disconnects (stdin EOF) or on signals. + // Without this, orphaned serve processes accumulate and contend for the + // PGLite write lock, causing ingest jobs (email-sync) to time out. + let shuttingDown = false; + const shutdown = (reason: string, code = 0) => { + if (shuttingDown) return; + shuttingDown = true; + process.stderr.write(`[gbrain-serve] shutdown: ${reason}\n`); + Promise.resolve(engine.disconnect?.()) + .catch(() => {}) + .finally(() => process.exit(code)); + }; + process.stdin.on('end', () => shutdown('stdin end')); + process.stdin.on('close', () => shutdown('stdin close')); + // @ts-ignore — SDK exposes onclose on transport + transport.onclose = () => shutdown('transport close'); + process.on('SIGTERM', () => shutdown('SIGTERM')); + process.on('SIGINT', () => shutdown('SIGINT')); + process.on('SIGHUP', () => shutdown('SIGHUP')); } // Backward compat: used by `gbrain call` command (trusted local path).