LearnNewsExamplesServices
Frontmatter
id10186
titleMCP concurrency audit + single-writer enforcement
stateClosed
labels
epicaiarchitecture
assignees[]
createdAtApr 22, 2026, 8:08 PM
updatedAtMay 22, 2026, 10:10 PM
githubUrlhttps://github.com/neomjs/neo/issues/10186
authorneo-gemini-pro
commentsCount8
parentIssue10139
subIssues
10187 Diagnose MCP concurrency with lsof/fuser
10188 Add boot-time sibling-PID logging to memory-core Server.mjs
10189 ADR for shared caching substrate for Memory Core
10190 Implement chosen shared caching substrate for Memory Core
10199 diagnoseMcpConcurrency UX polish: Windows fail-fast + per-PID file collection
10206 feat(memory-core): add harness classification to boot-time sibling-PID logging
10209 test(github-workflow): implement contract-scan test for config completeness
10222 Remove Memory Core Band-Aids and Polish Cache Coherence
10230 upsertNode must lazy-load from SQLite before cache decision
10241 Investigate bindAgentIdentity boot-time race — node-visible-at-61s-unbound-at-3s
10249 bindAgentIdentity drops return value — GraphService.getNode Promise is not awaited (#10241 follow-up)
subIssuesCompleted11
subIssuesTotal11
blockedBy[x] 10184 Identity binding stays null post-#10182 — enable debug logging + diagnose
blocking[]
closedAtMay 22, 2026, 10:10 PM

MCP concurrency audit + single-writer enforcement

Closed v13.0.0/archive-v13-0-0-chunk-5 epicaiarchitecture
neo-gemini-pro
neo-gemini-pro commented on Apr 22, 2026, 8:08 PM

Architectural Context

The multi-agent substrate currently relies on a per-process singleton (GraphService) for its in-memory cache, combined with a shared SQLite WAL database file (memory-core-graph.sqlite). Because Claude Desktop, Claude Code (across multiple worktrees), and the Antigravity IDE (with its twin language servers) all spawn independent sets of MCP servers, we have up to 20 Node processes querying and mutating the same SQLite file. While SQLite handles storage concurrency gracefully, the in-memory cache lacks cross-process invalidation.

When Process A seeds a node, Process B's vicinityLoadedNodes cache has no knowledge of it. This cross-harness cache divergence has led to issues such as identity-binding failures at boot (#10184), and serves as an unpredictable amplifier for system instability.

Implementation Scope

Diagnostic Phase:

  • Add a diagnoseMcpConcurrency.mjs script under ai/scripts/ using lsof/fuser to list all processes holding memory-core-graph.sqlite open (including count, PIDs, and parent harnesses).
  • Add a boot-time self-check in ai/mcp/server/memory-core/Server.mjs (initAsync) to log the PID of sibling processes holding the same SQLite file. Use the logger (which natively honors debug mode).

Architectural Phase:

  • Produce an ADR / decision doc evaluating moving the identity-binding cache out of per-process singleton state and into a shared substrate.
  • Implement the chosen shared caching layer (options: Chroma vector collection, SQLite-backed shared cache invalidated on write, or a daemon-mediated IPC primitive) based on the ADR decision.

Verification

  • Running diagnoseMcpConcurrency.mjs with Claude Desktop + Claude Code + Antigravity all active should report N≥2 Node processes holding the SQLite file open.
  • Testing A→seed / B→read divergence should show consistent state across multiple processes post-architecture fix.

Out of Scope

  • Fixing Antigravity's twin-language-server upstream bug (already documented separately).
  • PR #10185 band-aid (already landed).
  • Changing the SQLite WAL pragma.

Avoided Traps & Antipatterns

  • Treating single-process logic as the fix: Do not assume a within-process retry loop (like PR #10185) fixes the systemic cross-process cache divergence. The structural fix must address cross-process cache invalidation.
  • Overengineering the diagnostic tool: The diagnoseMcpConcurrency.mjs script should only read state; it must not attempt to automatically kill or manage external processes (especially Claude processes).

Handoff Retrieval Hints

Query the Memory Core semantic layer (not a single session) for context:

  • query_raw_memories(query="cross-harness MCP singleton cache divergence")
  • query_raw_memories(query="GraphService vicinityLoadedNodes identity binding")
  • query_summaries(query="MCP concurrency Claude Code Antigravity")

Known contributing sessions (partial, restart-fragmented):

  • fe1cd4d0-e667-45cf-bd02-7fb79a13a64f (PR #10185 review cycles)
  • ef6a0efb-bde9-43c3-b08b-812472398b68 (post-restart re-review)
  • ae546a40-2133-482f-85a6-779fdf6757b2 (cross-harness diagnostic)
  • 90dc2e65-962b-419f-91af-55dea55e5d3d (PR #10185 self-heal origin)

Commit range anchor: PR #10185 merged (commit range: check git log --grep="#10185"). Plan file: /Users/tobiasuhlig/.claude/plans/just-restarted-claude-code-moonlit-boot.md

tobiu referenced in commit 73dfaf6 - "fix(ai): extend focus seed default to Codex (#10662) (#10663) on May 3, 2026, 10:00 PM