feat(core#3082): loaded_mcp_tools producer in the heartbeat #158
Reference in New Issue
Block a user
Delete Branch "feat/3082-loaded-mcp-tools-producer"
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?
The platform online/degraded gate wants to verify the management MCP's tools are actually LIVE in the model's tool list, not just declared.
mcp_server_present()only proves declaration; the runtime never reported the loaded tool list, so the gate fail-closed on the absent list and every concierge read asdegraded(and flapped online/degraded as the recovery path raced it).Producer:
Pairs with molecule-ai-workspace-template-claude-code feat/3082-capture-loaded-mcp-tools (the executor capture) and the molecule-core SSOT (mcp_server_name=molecule-platform) so reported ids (mcp__molecule-platform__create_workspace) match the gate.
Tests: holder semantics + heartbeat payload includes loaded_mcp_tools when set (15 pass locally; the heartbeat-payload test needs full runtime deps -> CI).
Generated with Claude Code.
REQUEST_CHANGES on current head
f31157d.Blocking finding: CI is red in
ci / unit-tests. The new implementation replaces module-localmcp_server_presentimports inmolecule_runtime.main/heartbeatwithidentity_gate_payload, buttests/test_platform_agent_identity.pystill monkeypatchesmolecule_runtime.main.mcp_server_present. That symbol no longer exists, so two tests error at fixture setup before validating the new payload behavior. Update those tests to patchidentity_gate_payloador patch the source helpers used by it, and keep coverage for both register and heartbeat payloads.5-axis: correctness: the design is right for the RCA —
loaded_mcp_toolsis omitted until a live turn reports a list, preserving fail-closed behavior for absent producer, and an empty list remains a meaningful post-turn signal. Robustness: thread lock and defensive copy are good; any subset is safe because the control-plane gate can still fail closed when required tools are missing. Security: no new secret exposure. Performance: tiny in-memory holder and heartbeat JSON field only. Readability: comments explain declaration vs loaded-tool proof well.Status: not merge-ready and not 2-genuine/green until unit tests pass.
REQUEST_CHANGES on current head
f31157de.Blocking finding: CI is not green. fails in because the PR removed the module-local binding from (now importing ), but the existing test fixture still monkeypatches . The failure is deterministic: in two tests. Update the tests/patch target to the new contract or keep a compatible module-local binding if that is intentional.
5-axis: correctness: the loaded_mcp_tools holder is directionally right and fail-closed pre-first-turn by omitting the field. Robustness: lock/copy semantics and empty-list vs None behavior are good. Security: no secrets or auth changes. Performance: tiny heartbeat payload and lock overhead. Readability: comments clearly explain declared-vs-loaded semantics. But required unit tests are red, so this cannot merge and #160 should remain ordered behind the fixed runtime producer.
Clarifying CR2 REQUEST_CHANGES 12980 with exact identifiers (the verdict remains REQUEST_CHANGES):
Blocking finding:
ci / unit-tests (pull_request)fails intests/test_platform_agent_identity.pybecause the PR removed the module-localmcp_server_presentbinding frommolecule_runtime.mainwhile the existing fixture still monkeypatchesmolecule_runtime.main.mcp_server_present. The deterministic error isAttributeError: module 'molecule_runtime.main' has no attribute 'mcp_server_present'. Update the tests/patch target to the newidentity_gate_payloadcontract, or keep a compatible module-local binding if that is intentional.APPROVED on current head
ee0a8e5.5-axis: correctness: RC 12977 is fixed. The tests now patch the source
molecule_runtime.platform_agent_identity.mcp_server_present, and bothmain.register_with_platformandHeartbeatLoopcallidentity_gate_payload(), so the patch flows through the real production call path instead of stale per-module bindings. Theloaded_mcp_toolsproducer remains correct: absent until first observed turn (field omitted, fail-closed), empty list is a meaningful post-turn signal, and non-empty lists are reported to the heartbeat/register payload. Robustness: lock + defensive copy prevent accidental mutation; any subset is safe because the control-plane gate can still fail closed if required tools are missing. Security: reports tool ids only, no secrets/content. Performance: negligible in-memory holder plus small JSON field. Readability: comments and tests clearly document the fail-closed semantics and the fixture refactor.CI: current
ci / unit-testsis green. This completes the runtime side of the Concierge degraded/bounce root-fix chain once paired with the already-merged template changes.APPROVED on current head
ee0a8e5.5-axis review:
Correctness: RC is addressed. main/heartbeat now build payloads via identity_gate_payload(), and the test fixture patches the source platform_agent_identity.mcp_server_present, which flows through both call sites without restoring stale per-module mcp_server_present bindings. loaded_mcp_tools remains fail-closed pre-first-turn by omitting the field and reports an empty list as a meaningful "turn ran, no MCP tools" signal.
Robustness: lock/copy semantics protect holder state; None clears state intentionally; heartbeat/register payload construction is centralized.
Security: no auth or secret changes; only tool-id strings are reported.
Performance: tiny lock/list copy and small heartbeat payload field.
Readability: comments explain declared vs loaded semantics and the tests now exercise the real source-level path instead of over-mocking call sites.