Related to #556, which was closed without a confirmed root cause on Linux.
Environment
- OS: Linux (Ubuntu, kernel 6.17)
- Claude Code: 2.1.141
- context-mode: 1.0.131
- Node: 20.20.2 (nvm)
- Bun: 1.3.13
Symptoms
The MCP server connects successfully at session startup (243ms), but crashes with SIGSEGV the first time any ctx_* tool is invoked, roughly 10–12 seconds later. The skill falls back to CLI. Subsequent tool calls in the same session fail with "dynamic tool unavailable" because the server is dead.
Root cause
The plugin loader invokes start.mjs via node (per .claude-plugin/plugin.json's "command": "node"). On Linux, better-sqlite3's native addon segfaults under node's V8 — it requires bun's runtime environment. The doctor's SQLite check passes because it runs under bun; the actual server process doesn't.
Confirmed via a thin wrapper around start.mjs that logs the child process exit signal:
stdin data 306b ← initialize
stdin data 202b ← notifications/initialized
stdin data 177b ← first tool call arrives
child exit code=null sig=SIGSEGV ← 343ms later
Workaround
Backup the original and replace start.mjs with a wrapper that spawns start.real.mjs using bun:
#!/usr/bin/env node
import { spawn } from 'child_process';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
const __dirname = dirname(fileURLToPath(import.meta.url));
const child = spawn(process.env.HOME + '/.bun/bin/bun', [join(__dirname, 'start.real.mjs')], {
stdio: ['pipe', 'inherit', 'inherit'],
env: process.env,
});
process.stdin.on('data', (chunk) => { if (!child.stdin.destroyed) child.stdin.write(chunk); });
process.stdin.on('end', () => {});
const _k = setInterval(() => {}, 2147483647);
child.on('exit', (code) => { clearInterval(_k); process.exit(code ?? 0); });
With bun spawning the real server, ctx_doctor and other tools work correctly.
Suggested fix
The plugin manifest could specify bun as the command (with a node fallback), or start.mjs could detect the active runtime and re-exec itself under bun if it was invoked via node.
Note: this is separate from #559 (zombie processes after upgrade), though both surfaced during the same debugging session.
Related to #556, which was closed without a confirmed root cause on Linux.
Environment
Symptoms
The MCP server connects successfully at session startup (243ms), but crashes with SIGSEGV the first time any
ctx_*tool is invoked, roughly 10–12 seconds later. The skill falls back to CLI. Subsequent tool calls in the same session fail with "dynamic tool unavailable" because the server is dead.Root cause
The plugin loader invokes
start.mjsvianode(per.claude-plugin/plugin.json's"command": "node"). On Linux,better-sqlite3's native addon segfaults under node's V8 — it requires bun's runtime environment. The doctor's SQLite check passes because it runs under bun; the actual server process doesn't.Confirmed via a thin wrapper around
start.mjsthat logs the child process exit signal:Workaround
Backup the original and replace
start.mjswith a wrapper that spawnsstart.real.mjsusing bun:With bun spawning the real server,
ctx_doctorand other tools work correctly.Suggested fix
The plugin manifest could specify
bunas the command (with a node fallback), orstart.mjscould detect the active runtime and re-exec itself under bun if it was invoked via node.Note: this is separate from #559 (zombie processes after upgrade), though both surfaced during the same debugging session.