fix(concierge): recognize plugin-delivered management MCP in RCA#2970 online gate #156
Reference in New Issue
Block a user
Delete Branch "fix/concierge-online-gate-plugin-mcp"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem (SSM-proven on staging 2026-06-19)
A fresh SaaS concierge boots cleanly on the
workspace-template-claude-codeimage, installs themolecule-platformplugin, and wires the management MCP into/configs/.claude/settings.json(runtime #149). Yet CP marks itfailed:Root cause
mcp_server_present()only checked the legacy/opt/molecule-mcp-serverbinary baked into the retired platform-agent image. The concierge is now theclaude-code + plugincomposition, so the file is absent → runtime self-reportsmcp_server_present=false→ the RCA #2970 fail-closed gate (workspace-server/internal/handlers/registry.go) refuses online-marking →create_workspacenever reachable. The e2e then auto-skips its assertion (green-but-unproven).Fix
Make the signal delivery- and runtime-agnostic:
mcp_server_present()returns true when the baked binary exists ORsettings.jsonwires themolecule-platformmcpServer. Absence of both stays fail-closed. Mirrors the platform model — platform-ness is a composition (org key + management MCP plugin) on an ordinary runtime, not a special image.Tests
plugin-wired settings ⇒ true; other-MCP-only / malformed / missing ⇒ false; binary-alone still true; name-matches-plugin guard. Existing register/heartbeat payload tests unchanged.
Follow-ups (separate)
E2E_REQUIRE_LIVE=1after this lands + image re-pins.system-prompt.md(non-blocking boot WARN).🤖 Generated with Claude Code
APPROVE — Correctness review. Verified mcp_server_present() now returns true for the claude-code+plugin concierge via /configs/.claude/settings.json mcpServers['molecule-platform'], matching the exact path/key the executor (_load_settings_mcp) and plugin installer use. JSON parsing is defensive (missing/unreadable/malformed/non-dict all → False, fail-closed). Tests cover the new branch + non-dict guards + binary-only + payload shape. No regression to register/heartbeat payload.
APPROVE — Security/fail-closed review. Adversarial read confirms the gate stays fail-closed on every degenerate input; no exception escapes. Self-reporting true grants nothing without the server-side org-root entitlement + org-key injection (the real boundary), now documented in-code. Broadened signal is load-bearing (the actual config the executor consumes), not cosmetic.
New commits pushed, approval review dismissed automatically according to repository settings
New commits pushed, approval review dismissed automatically according to repository settings
APPROVE (re-confirm on head
400dcb97after SSOT-pointer doc commit). Correctness unchanged; plugin-delivered MCP detection + fail-closed guards + tests verified. unit-tests 676 passed.APPROVE (re-confirm on head
400dcb97). Fail-closed preserved on all degenerate inputs; real boundary remains server-side org-root entitlement, now documented + pointed at the SSOT contract.