Skip to content

feat(mcp): append-drift mid-session reconnect (refs #110)#117

Merged
esengine merged 1 commit intomainfrom
feat/mcp-reconnect-append
May 2, 2026
Merged

feat(mcp): append-drift mid-session reconnect (refs #110)#117
esengine merged 1 commit intomainfrom
feat/mcp-reconnect-append

Conversation

@esengine
Copy link
Copy Markdown
Owner

@esengine esengine commented May 2, 2026

Refs #110.

What

/mcp reconnect <name> (and r in browser) now accept append-drift mid-session — when the reconnected server has new tools at the end of its list, register them in the registry and addTool the prefix instead of refusing.

Drift kinds the reconnect handles:

kind behaviour cache impact
identity swap host's client ~95% hit (no prefix change)
append swap + register new tools + addTool to prefix ~95% hit (new chunks land in cache too) — verified in #113 spike
edit refuse, "restart Reasonix to apply" unchanged from #115
reorder refuse, "restart Reasonix to apply" unchanged
remove refuse, "restart Reasonix to drop them" unchanged

Touch

Registry refactor:

  • src/mcp/registry.ts — extracted registerSingleMcpTool(mcpTool, env) + new BridgeEnv type (resolved bridge environment captured at first-bridge time). bridgeMcpTools return shape gains env.

State plumbing:

  • src/cli/ui/slash/types.tsMcpServerSummary gains bridgeEnv: BridgeEnv.
  • src/cli/commands/chat.tsx — captures bridge.env on the summary.

Reconnect surface:

  • src/mcp/reconnect.ts — accepts identity (always) + append (opt-in via accept: ["identity", "append"]). On append, returns addedTools.
  • src/cli/ui/mcp-append.ts (new) — applyMcpAppend(loop, target, addedTools) does the prefix + registry + summary mutations.
  • src/cli/ui/mcp-reconnect-kickoff.ts — gains optional applyAppend callback. When set, opts into the append flow; when missing, behaviour is unchanged from feat(mcp): /mcp reconnect <name> for identity drift (closes part of #110) #115.
  • src/cli/ui/slash/handlers/mcp.ts + src/cli/ui/McpBrowser.tsx + src/cli/ui/App.tsx — both surfaces wire applyMcpAppend through.

Tests:

  • tests/mcp-append.test.ts — 4 cases (registry registration, fingerprint invalidation, summary refresh, defensive skip on unnamed tools).

What's still in #110

Edit / reorder / remove mid-session — each needs new ImmutablePrefix API (replaceTool / removeTool) plus a cache-reset announcement card. Edge cases that the spike showed are catastrophic for cache anyway, so refusing them with a clear "restart" message is the right default for now. Will file follow-up issues if real demand surfaces.

Test plan

  • npm run verify passes (1782 tests, +4 new)
  • applyMcpAppend mutates loop.tools + loop.prefix + summary.report correctly
  • Fingerprint invalidates on append (so DeepSeek's cache key shifts only at the appended chunk, not from the start)
  • Eyeball: launch with an MCP server, manually edit its tool list to add a new tool, restart THAT server (not Reasonix), then /mcp reconnect <name>, confirm the new tool shows up in /mcp browser without a Reasonix restart

Stage E2 of the C2b follow-ups: when /mcp reconnect finds the server
added new tools at the END of its tool list, register them
mid-session and addTool the prefix instead of refusing.

Drift kinds the reconnect now accepts:

- identity → free swap, ~95% cache hit (was already shipped in #115)
- append → register new tools, ~95% cache hit (the new chunks land
  in cache too, per benchmarks/spike-mcp-reconnect data)
- edit / reorder / remove → still refused with "restart Reasonix"

Touch:

- src/mcp/registry.ts — extract `registerSingleMcpTool(mcpTool, env)`
  + new `BridgeEnv` type (resolved bridge environment captured at
  first-bridge time). bridgeMcpTools' return shape gains `env` so
  reconnect can re-use the same options.
- src/cli/ui/slash/types.ts — McpServerSummary gains `bridgeEnv:
  BridgeEnv` so the append handler has everything it needs to
  register a new tool without redoing the whole bridge.
- src/cli/commands/chat.tsx — captures bridge.env onto the summary.
- src/mcp/reconnect.ts — accepts identity (always) plus append (if
  caller passes accept: ["identity", "append"]). On append, returns
  addedTools so the caller can register them. Identity is forced-
  accepted regardless of `accept` because it's free.
- src/cli/ui/mcp-append.ts (new) — `applyMcpAppend(loop, target,
  addedTools)` calls registerSingleMcpTool + prefix.addTool +
  refreshes target.report. Accepted-tools-only counting handles the
  unnamed-tool defensive case.
- src/cli/ui/mcp-reconnect-kickoff.ts — gains optional `applyAppend`
  callback. When set, opts the reconnect into ["identity",
  "append"]; when missing, behaviour is unchanged from #115.
- src/cli/ui/slash/handlers/mcp.ts + src/cli/ui/McpBrowser.tsx +
  src/cli/ui/App.tsx — both surfaces wire applyMcpAppend through.
- tests/mcp-append.test.ts (new) — 4 cases: registry registration,
  fingerprint invalidation, summary refresh, defensive skip on
  unnamed tools.

Closes most of #110. Edit / reorder / remove mid-session remain as
follow-up issues — each requires new ImmutablePrefix API
(replaceTool / removeTool) + cache-reset announcement.
@esengine esengine merged commit c7298fe into main May 2, 2026
1 check passed
@esengine esengine deleted the feat/mcp-reconnect-append branch May 2, 2026 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant