fix: Revert memory MCP to per-session stdio (fix Cowork regression) - #14
Merged
Conversation
The v0.10.0 switch to a single shared HTTP server on 127.0.0.1:8765 broke the memory vault in Claude Cowork, whose remote sandbox has nothing listening on the host's loopback port. Per-session stdio spawns the server in-process wherever the session runs (including the Cowork sandbox), so memory works there again. Point plugin.json's memory MCP back at the hooks/mcp-memory.sh stdio launcher (the v0.8.0 command/args form). Replace test-plugin-http-config.sh with test-plugin-stdio-config.sh, asserting the stdio command config and that no legacy type/url/headers keys remain. The shared-HTTP code is retained but no longer wired — a complete but reversible revert.
With the shared-server supervisor no longer running, nothing maintains the memory index. Restore out-of-band reclamation on the per-session stdio launcher, reusing hooks/lib/memory-vacuum.sh rather than the old inline copy. Add memory_vacuum_locked: a non-blocking atomic-mkdir lock around the gated memory_vacuum, so among concurrently starting launchers exactly one attempts the VACUUM and the rest skip immediately. Staleness is PID-liveness (a crashed launcher's lock is stolen once), mirroring memory-server-up.sh. A VACUUM that still contends with a live sibling server's writes skips safely via memory_vacuum's existing SQLite busy timeout — the honest multi-session tradeoff of per-session stdio. mcp-memory.sh sources the lib and calls memory_vacuum_locked; the supervisor keeps calling the unlocked memory_vacuum (it holds the spawn lock in a no-server-alive window). Tests cover the free / live-held / stale-stolen paths.
With the transport reverted to per-session stdio, the shared HTTP server is a phantom nobody connects to. Stop auto-starting it — reversibly, keeping every script in the tree: - hooks.json: drop the memory-server-up.sh SessionStart hook so the lazy-start supervisor never fires. - session-warmup.sh: remove the shared-server health-check block (and its now-dead memory-probe.sh source + MCP_SERVER_NAME). Under stdio nothing listens on the loopback port, so memory_probe returned DOWN_NONE every startup and printed a phantom "Memory server starting" notice; the MCP host's own connect error is the real signal now. A breadcrumb documents re-enable. memory-server-up.sh / -spawn.sh / -down.sh and memory-probe.sh stay in hooks/ (their tests still pass); re-enabling restores the hooks.json line, the warmup block, and the http transport. A test asserts the phantom notices no longer appear at startup.
The memory-status skill + script reported shared-HTTP health (probe, port, bearer token, start/stop, server.log tail) — all inert under per-session stdio, where the MCP host spawns the server in-process per session with no listener. Rewrite both to report what actually determines whether stdio memory works: resolved vault/cache, launcher presence, whether the server binary is installed, and index/last-VACUUM facts. start/stop now print an explanatory note (the host owns the per-session lifecycle) and fall through to status. Add a smoke test (hooks/test-memory-status.sh) asserting the stdio report, launcher presence, absence of HTTP/port/token vocabulary, and exit 0.
Repoint the prose docs from shared-HTTP-as-current to per-session-stdio-as-
current, keeping the HTTP path documented as an optional, disabled mode:
- README: rewrite the "Shared memory server" subsection as "Memory server
transport" — stdio (current, works in Cowork) + a step-by-step "Re-enabling
the shared HTTP server (optional)" recipe. Drop the shared-server SessionStart
hook row and the warmup health-check mention; trim the cache layout to the
stdio artifacts; annotate memory_port / WORKBENCH_MEMORY_{PORT,TOKEN} as inert
under stdio; replace the "first session may lack memory" limitation (an
HTTP/token artifact, now gone) with the multi-session index-contention tradeoff.
- setup skill: gate Step 2b (bearer token + settings.json) as "shared HTTP
server only — skip under stdio"; mark memory_port as HTTP-only; soften the
restart reminder (stdio config is re-read next session, no restart/token dance);
fix the plugin-update and token-security notes.
mikebronner
marked this pull request as ready for review
July 11, 2026 21:29
mikebronner
added a commit
that referenced
this pull request
Jul 26, 2026
…HTTP server. PR #14 reverted the memory MCP to per-session stdio but never updated memory-recall.sh, which still curled a shared HTTP server on port 8765 directly. The supervisor that manages that server was unwired by the same revert, so nothing should have been listening — except an 18-day-old orphan from the old shared-server model was still alive, silently keeping recall "working" by accident while every session's every prompt funneled through one unmonitored 2.4GB process. Kill the orphan (done separately, out of band) and switch memory-recall.sh to `markdown-vault-mcp search --json`, a genuine one-shot CLI subcommand — confirmed via lsof to bind no port and leave nothing running. Trades a warm daemon's ~25ms response for a one-shot process's ~1s, in exchange for zero shared state and no daemon left to go unsupervised again.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The v0.10.0 switch from per-session stdio to a single shared HTTP server on
127.0.0.1:8765broke the memory vault in Claude Cowork: Cowork runs in a remote sandbox where nothing listens on that loopback port, so it can't reach the vault. Under the old stdio model each session spawned its own server in-process (in whatever environment it ran, including the Cowork sandbox), so memory worked there.This reverts the memory MCP to per-session stdio everywhere. The Mac knowingly re-accepts the multi-session index-write concurrency tradeoff the HTTP server was introduced to solve. The revert is complete but reversible — the shared-server implementation stays in the tree; only its invocation stops.
Acceptance bar: the memory vault works in both Claude Cowork (remote sandbox — needs the in-session stdio server) and terminal Claude Code.
Changes (in progress)
plugin.jsonmemory MCP → stdiocommand/argslauncher formhooks/lib/memory-vacuum.sh)memory-statusskill+script,setupskill)Test Plan
hooks/test-*.shsuite green (offline; fake-server fixture)bash -nclean on hooks/libs/scriptsFixes the Cowork memory regression introduced in v0.10.0.