📝 Bug Description
The engram mcp stdio server fails its lifecycle handshake against Claude Code's MCP client. After initialize succeeds, Claude Code sends SIGINT to the server process 2-5 seconds later, clears its connection cache "for reconnection", and never reconnects for the rest of the session. The mem_* tools declared by the server never become reachable to the model.
This was originally reported against gentle-ai in Gentleman-Programming/gentle-ai#1019. The gentle-ai-side hardening landed in Gentleman-Programming/gentle-ai#1608 (tagged lifecycle regression test, gentle-ai doctor version gate with a dormant threshold). The actual lifecycle fix needs to live here, in the engram binary.
The investigation (see Gentleman-Programming/gentle-ai#1608 runbook and the upstream investigation in the PR diff at openspec/changes/debug-1019-engram-mcp-sigint/exploration.md) points to the engram MCP server failing to send the notifications/initialized notification after the initialize handshake. Per the MCP spec, the server must send this notification. Claude Code's stdio MCP client has a timeout (~2-5s) for this lifecycle step; when it never arrives, the client terminates the server process.
A reference MCP lifecycle implementation that DOES emit the notification lives in gentle-ai/internal/components/communitytool/pi_codegraph.go:550-574. For comparison, that reference sends the notification immediately after reading the initialize response and before any subsequent request.
🔄 Steps to Reproduce
Reproduced by the user in #1019 (Gentleman-Programming/gentle-ai):
- Have
engram@engram enabled as a Claude Code plugin (enabledPlugins in ~/.claude/settings.json, installed via the gentle-ai/Engram marketplace, binary via Linuxbrew: /home/linuxbrew/.linuxbrew/bin/engram, engram v1.17.0).
- Start a new Claude Code session in any project (
claude in a fresh terminal).
- Immediately after the SessionStart hook fires, inspect
~/.cache/claude-cli-nodejs/<project>/mcp-logs-plugin-engram-engram/<latest>.jsonl.
- Try calling any
mem_* tool, or search for it via ToolSearch with query select:mem_save or mcp__plugin_engram_engram.
✅ Expected Behavior
The engram MCP connection stays alive for the duration of the session (as it does for other plugins/MCP servers, and as it used to for engram itself in older sessions — see Additional Context), and the mem_* tools declared by the server (mem_save, mem_search, mem_context, mem_session_summary, mem_get_observation, mem_save_prompt as always-loaded; the rest as ToolSearch-deferred) are actually reachable by the model.
❌ Actual Behavior
Every session start produces this exact pattern in mcp-logs-plugin-engram-engram/*.jsonl:
{"debug":"Starting connection with timeout of 30000ms", ...}
{"debug":"Successfully connected (transport: stdio) in ~190ms", ...}
{"debug":"Server instructions truncated from 2539 to 2048 chars", ...}
{"debug":"Connection established with capabilities: {\"hasTools\":true,...}", ...}
{"debug":"Sending SIGINT to MCP server process", ...} ← 2-5s later, no tool ever called
{"debug":"UNKNOWN connection closed after Ns (cleanly)", ...}
{"debug":"Cleared connection cache for reconnection", ...}
{"debug":"MCP server process exited cleanly", ...}
No further connection attempt is logged for the rest of the session. ToolSearch with queries like select:mem_save or mcp__plugin_engram_engram returns "No matching deferred tools found".
Manual verification that the binary itself responds to raw JSON-RPC outside Claude Code (run by the user in #1019):
$ printf '{"jsonrpc":"2.0","id":1,"method":"initialize",...}\n{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}\n' | engram mcp --tools=agent
{"jsonrpc":"2.0","id":1,"result":{...,"serverInfo":{"name":"engram","version":"0.1.0"},...}}
{"jsonrpc":"2.0","id":2,"result":{"tools":[... 18 valid tool definitions ...]}}
This proves the binary can complete the initialize + tools/list exchange. The manual test does NOT verify that the server emits notifications/initialized after initialize, which is the suspected gap.
🖥️ Environment
Operating System: Linux (Arch/Manjaro) — specifically CachyOS
Engram Version: v1.17.0 (per the reporter; verify with engram version — note: gentle-ai currently invokes engram version without double-dash per internal/components/engram/verify.go:31-37)
Agent / Client
Claude Code (CLI v2.1.201, up to date), registered via enabledPlugins["engram@engram"] in ~/.claude/settings.json
📋 Relevant Logs
Full mcp-logs-plugin-engram-engram/*.jsonl from the reporter:
{"debug":"Starting connection with timeout of 30000ms","timestamp":"2026-07-05T10:02:44.340Z","sessionId":"4f3f9430-...","cwd":"/home/ginopc/Desarrollo/Billetera"}
{"debug":"Successfully connected (transport: stdio) in 191ms","timestamp":"2026-07-05T10:02:44.528Z", ...}
{"debug":"Server instructions truncated from 2539 to 2048 chars","timestamp":"2026-07-05T10:02:44.529Z", ...}
{"debug":"Connection established with capabilities: {\"hasTools\":true,\"hasPrompts\":false,\"hasResources\":false,\"hasResourceSubscribe\":false,\"serverVersion\":{\"name\":\"engram\",\"version\":\"0.1.0\"}}","timestamp":"2026-07-05T10:02:44.529Z", ...}
{"debug":"Sending SIGINT to MCP server process","timestamp":"2026-07-05T10:02:48.884Z", ...}
{"debug":"UNKNOWN connection closed after 4s (cleanly)","timestamp":"2026-07-05T10:02:48.890Z", ...}
{"debug":"Cleared connection cache for reconnection","timestamp":"2026-07-05T10:02:48.896Z", ...}
{"debug":"MCP server process exited cleanly","timestamp":"2026-07-05T10:02:48.938Z", ...}
💡 Additional Context
Symptom onset. The reporter has healthy logs from before ~2026-07-03 showing the server connecting once and staying alive for the full session (hours, dozens of successful mem_save/mem_search/mem_update calls), with SIGINT only appearing once at genuine session end and no "Cleared connection cache for reconnection" line. That line only appears in the broken pattern. The reporter could not identify what changed on their side around that date.
Ruled out by the reporter. Outdated Claude Code CLI (already on latest 2.1.201), duplicate MCP registration (no engram entry exists in the project's .mcp.json, in ~/.claude.json mcpServers, or in ~/.claude/settings.json mcpServers — only via the plugin's own .mcp.json with enabledPlugins["engram@engram"] = true), and a corrupt/misbehaving binary (the manual JSON-RPC test above proves it responds correctly).
Reproduces across multiple projects on the same machine (confirmed in at least 2 separate project directories), and persists across a full process restart of Claude Code (not just /clear — closing the terminal entirely and relaunching claude in a new terminal reproduces the exact same failure).
gentle-ai-side companion work (for maintainer cross-reference; do not duplicate):
Gentleman-Programming/gentle-ai#1019 — original report (high priority, approved).
Gentleman-Programming/gentle-ai#1608 — gentle-ai-side hardening (tagged stdio lifecycle test behind //go:build engram_lifecycle, gentle-ai doctor version gate with dormant MinEngramVersionForHealthyLifecycle = "0.0.0", runbook at docs/engram-mcp-lifecycle.md). That PR documents this fix belongs in gentleman-programming/engram and includes the upstream investigation in openspec/changes/debug-1019-engram-mcp-sigint/exploration.md.
Suspected fix direction (not yet confirmed without binary-side instrumentation): add the notifications/initialized notification emit to the MCP server handshake path in cmd/engram/main.go (the mcp subcommand), mirroring the lifecycle in gentle-ai/internal/components/communitytool/pi_codegraph.go:550-574. Optionally also implement periodic ping response and a SIGHUP reload handler (see Gentleman-Programming/engram#206 for a related but distinct feature request about SIGHUP DB reload).
Open data requests for binary maintainers:
- Does the
engram mcp server emit notifications/initialized after initialize? (Recipe: add a temporary stderr log line in cmd/engram/main.go immediately after writing the initialize response.)
- Does the server respond to
ping requests from Claude Code's MCP client?
- Does the bug reproduce when the user deletes
~/.claude/mcp/engram.json and re-runs gentle-ai to force a fresh registration?
- Does Claude Code itself have a behavior change around 2026-07-03 that could be sending
SIGINT prematurely even for correctly-behaving servers?
status:approvedbefore a PR can be opened📝 Bug Description
The
engram mcpstdio server fails its lifecycle handshake against Claude Code's MCP client. Afterinitializesucceeds, Claude Code sendsSIGINTto the server process 2-5 seconds later, clears its connection cache "for reconnection", and never reconnects for the rest of the session. Themem_*tools declared by the server never become reachable to the model.This was originally reported against gentle-ai in
Gentleman-Programming/gentle-ai#1019. The gentle-ai-side hardening landed inGentleman-Programming/gentle-ai#1608(tagged lifecycle regression test,gentle-ai doctorversion gate with a dormant threshold). The actual lifecycle fix needs to live here, in theengrambinary.The investigation (see
Gentleman-Programming/gentle-ai#1608runbook and the upstream investigation in the PR diff atopenspec/changes/debug-1019-engram-mcp-sigint/exploration.md) points to theengramMCP server failing to send thenotifications/initializednotification after theinitializehandshake. Per the MCP spec, the server must send this notification. Claude Code's stdio MCP client has a timeout (~2-5s) for this lifecycle step; when it never arrives, the client terminates the server process.A reference MCP lifecycle implementation that DOES emit the notification lives in
gentle-ai/internal/components/communitytool/pi_codegraph.go:550-574. For comparison, that reference sends the notification immediately after reading theinitializeresponse and before any subsequent request.🔄 Steps to Reproduce
Reproduced by the user in #1019 (Gentleman-Programming/gentle-ai):
engram@engramenabled as a Claude Code plugin (enabledPluginsin~/.claude/settings.json, installed via thegentle-ai/Engram marketplace, binary via Linuxbrew:/home/linuxbrew/.linuxbrew/bin/engram, engram v1.17.0).claudein a fresh terminal).~/.cache/claude-cli-nodejs/<project>/mcp-logs-plugin-engram-engram/<latest>.jsonl.mem_*tool, or search for it viaToolSearchwith queryselect:mem_saveormcp__plugin_engram_engram.✅ Expected Behavior
The
engramMCP connection stays alive for the duration of the session (as it does for other plugins/MCP servers, and as it used to forengramitself in older sessions — see Additional Context), and themem_*tools declared by the server (mem_save,mem_search,mem_context,mem_session_summary,mem_get_observation,mem_save_promptas always-loaded; the rest as ToolSearch-deferred) are actually reachable by the model.❌ Actual Behavior
Every session start produces this exact pattern in
mcp-logs-plugin-engram-engram/*.jsonl:No further connection attempt is logged for the rest of the session.
ToolSearchwith queries likeselect:mem_saveormcp__plugin_engram_engramreturns "No matching deferred tools found".Manual verification that the binary itself responds to raw JSON-RPC outside Claude Code (run by the user in #1019):
This proves the binary can complete the
initialize+tools/listexchange. The manual test does NOT verify that the server emitsnotifications/initializedafterinitialize, which is the suspected gap.🖥️ Environment
Operating System: Linux (Arch/Manjaro) — specifically CachyOS
Engram Version: v1.17.0 (per the reporter; verify with
engram version— note: gentle-ai currently invokesengram versionwithout double-dash perinternal/components/engram/verify.go:31-37)Agent / Client
Claude Code (CLI v2.1.201, up to date), registered via
enabledPlugins["engram@engram"]in~/.claude/settings.json📋 Relevant Logs
Full
mcp-logs-plugin-engram-engram/*.jsonlfrom the reporter:💡 Additional Context
Symptom onset. The reporter has healthy logs from before ~2026-07-03 showing the server connecting once and staying alive for the full session (hours, dozens of successful
mem_save/mem_search/mem_updatecalls), withSIGINTonly appearing once at genuine session end and no "Cleared connection cache for reconnection" line. That line only appears in the broken pattern. The reporter could not identify what changed on their side around that date.Ruled out by the reporter. Outdated Claude Code CLI (already on latest 2.1.201), duplicate MCP registration (no
engramentry exists in the project's.mcp.json, in~/.claude.jsonmcpServers, or in~/.claude/settings.jsonmcpServers— only via the plugin's own.mcp.jsonwithenabledPlugins["engram@engram"] = true), and a corrupt/misbehaving binary (the manual JSON-RPC test above proves it responds correctly).Reproduces across multiple projects on the same machine (confirmed in at least 2 separate project directories), and persists across a full process restart of Claude Code (not just
/clear— closing the terminal entirely and relaunchingclaudein a new terminal reproduces the exact same failure).gentle-ai-side companion work (for maintainer cross-reference; do not duplicate):
Gentleman-Programming/gentle-ai#1019— original report (high priority, approved).Gentleman-Programming/gentle-ai#1608— gentle-ai-side hardening (tagged stdio lifecycle test behind//go:build engram_lifecycle,gentle-ai doctorversion gate with dormantMinEngramVersionForHealthyLifecycle = "0.0.0", runbook atdocs/engram-mcp-lifecycle.md). That PR documents this fix belongs ingentleman-programming/engramand includes the upstream investigation inopenspec/changes/debug-1019-engram-mcp-sigint/exploration.md.Suspected fix direction (not yet confirmed without binary-side instrumentation): add the
notifications/initializednotification emit to the MCP server handshake path incmd/engram/main.go(themcpsubcommand), mirroring the lifecycle ingentle-ai/internal/components/communitytool/pi_codegraph.go:550-574. Optionally also implement periodicpingresponse and aSIGHUPreload handler (seeGentleman-Programming/engram#206for a related but distinct feature request about SIGHUP DB reload).Open data requests for binary maintainers:
engram mcpserver emitnotifications/initializedafterinitialize? (Recipe: add a temporary stderr log line incmd/engram/main.goimmediately after writing theinitializeresponse.)pingrequests from Claude Code's MCP client?~/.claude/mcp/engram.jsonand re-runsgentle-aito force a fresh registration?SIGINTprematurely even for correctly-behaving servers?