fix(experiments): pin agent panes to a marcus-only MCP via --strict-mcp-config#702
Conversation
…cp-config
Worker and project-creator panes inherited every globally-registered MCP
server (Gmail, Drive, Calendar, Docker, ...). That large tool surface put
claude into deferred-tool mode, so the mcp__marcus__* tools were not directly
callable and had to be loaded via ToolSearch first. Smaller models (haiku)
mishandled that and tried to invoke Marcus through nonexistent shell CLIs
("mcp call ...", "claude mcp invoke ...") instead of calling the tool, so
they never registered -> in_flight stayed 0 -> the run spawn-thrashed and
tore down with nothing built.
Launch panes with --strict-mcp-config and a marcus-only --mcp-config so the
~16 Marcus tools are directly callable. The old `claude mcp add marcus`
snippet becomes a no-op: under --strict-mcp-config ~/.claude.json is ignored,
and this also removes parallel panes racing to write that file.
Validated end-to-end: a haiku worker registered -> request_next_task (claimed)
-> get_task_context -> wrote code + TDD tests -> log_decision + log_artifact
-> reported 0->100% progress -> committed, with npm test 20/20 passing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @lwgray's task —— View job PR Review in Progress
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7f405067b0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| marcus_only_mcp = ( | ||
| r'"{\"mcpServers\":{\"marcus\":' | ||
| r'{\"type\":\"http\",\"url\":\"$MARCUS_MCP_URL\"}}}"' | ||
| ) |
There was a problem hiding this comment.
Force Marcus MCP tools to load upfront
In current Claude Code, --strict-mcp-config only narrows which MCP servers are loaded; it does not make those tools directly visible. I checked the Claude Code MCP docs, which say Tool Search is enabled by default and defers MCP tools unless the server config sets alwaysLoad: true (https://code.claude.com/docs/en/mcp#exempt-a-server-from-deferral), so this inline config still leaves mcp__marcus__* behind ToolSearch in the small-model scenario this patch is meant to fix. Add "alwaysLoad": true to the Marcus server config, or disable Tool Search for the pane, so registration/progress tools are actually callable upfront.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Great catch — confirmed and fixed in a60fdeb.
You're right that --strict-mcp-config only narrows which servers load; it doesn't undefer their tools. I A/B'd it with a haiku worker (stream-json, prompt "call mcp__marcus__ping"):
- marcus-only (this PR as originally filed):
ToolSearch→Bash→mcp__marcus__ping— still deferred, still flails - marcus-only +
"alwaysLoad": true:mcp__marcus__ping— direct call, no ToolSearch
So the original marcus-only config only worked because cutting to a single server made the ToolSearch step recoverable for the small model — fragile, exactly as you flag. Added "alwaysLoad": true to the inline config so the ~16 Marcus tools load upfront and are directly callable. Thanks!
…Load) --strict-mcp-config only narrows which MCP servers load; it does not make their tools directly visible. Tool Search is on by default and defers MCP tools unless the server config sets "alwaysLoad": true, so the marcus-only config still left mcp__marcus__* behind ToolSearch — the exact step a small worker model fumbles. A/B check (haiku, stream-json, prompt "call mcp__marcus__ping"): marcus-only -> ToolSearch, Bash, mcp__marcus__ping marcus-only + alwaysLoad -> mcp__marcus__ping (direct, no ToolSearch) Add "alwaysLoad": true to the inline marcus config so the ~16 tools load upfront and are directly callable. Thanks to the Codex review on PR #702 for catching this. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @lwgray's task —— View job PR Code Review Complete ✅Reviewing this PR for:
Review SummaryThis is an excellent fix that addresses a critical failure mode in the Marcus multi-agent system. The solution is architecturally sound, well-implemented, and properly documented. The addition of Problem Analysis ✅The PR correctly identifies that inheriting all globally-registered MCP servers (Gmail, Drive, Calendar, Docker, etc.) pushes Claude into deferred-tool mode, where Code Quality ✅Strengths:
File: Technical Implementation ✅The fix adds two critical flags to the Claude command: --strict-mcp-config --mcp-config "{\"mcpServers\":{\"marcus\":{\"type\":\"http\",\"url\":\"$MARCUS_MCP_URL\",\"alwaysLoad\":true}}}"This approach:
Addressing Codex Feedback: The addition of Architecture Alignment ✅This change perfectly preserves the Multi-Agent System invariants:
The fix operates at the coordination infrastructure level (ensuring tools are accessible) rather than controlling agent behavior. Security & Performance ✅Security:
Performance:
Edge Cases & Error Handling ✅Considered scenarios:
Test Coverage Assessment
|
The claude register snippet is now a no-op marker — marcus is pinned per-pane via --strict-mcp-config + alwaysLoad, not `claude mcp add` writing ~/.claude.json. Update the two tests that asserted the old `claude mcp add marcus -t http` contract to assert the new one: the snippet performs no global add, and the agent command carries the marcus-only --mcp-config with alwaysLoad. Codex/gemini register tests are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @lwgray's task —— View job PR Code Review Complete ✅Reviewing this PR for:
Review SummaryThis is an excellent fix that addresses a critical failure mode in the Marcus multi-agent system. The solution is architecturally sound, well-implemented, and properly documented. The addition of Problem Analysis ✅The PR correctly identifies that inheriting all globally-registered MCP servers (Gmail, Drive, Calendar, Docker, etc.) pushes Claude into deferred-tool mode, where Code Quality ✅Strengths:
File: Technical Implementation ✅The fix adds two critical flags to the Claude command: --strict-mcp-config --mcp-config "{\"mcpServers\":{\"marcus\":{\"type\":\"http\",\"url\":\"$MARCUS_MCP_URL\",\"alwaysLoad\":true}}}"This approach:
Addressing Codex Feedback: The addition of Architecture Alignment ✅This change perfectly preserves the Multi-Agent System invariants:
The fix operates at the coordination infrastructure level (ensuring tools are accessible) rather than controlling agent behavior. Security & Performance ✅Security:
Performance:
Edge Cases & Error Handling ✅Considered scenarios:
Test Coverage Assessment
|

Problem
Worker and project-creator panes launched
claudewhile inheriting every globally-registered MCP server (Gmail, Drive, Calendar, Docker, … + marcus). That large tool surface pushes Claude into deferred-tool mode, wheremcp__marcus__*tools aren't directly available and must be loaded viaToolSearchfirst.Smaller worker models (haiku) mishandle that step — instead of calling the tool, they try to reach Marcus through shell CLIs that don't exist:
So the agent never registers →
in_flightstays0→ the runner keeps spawning → the spawn-thrash watchdog tears the session down with nothing built. (This presented as the misleading "likely BLOCKED dependency gating" teardown.)Fix
Launch every pane with
--strict-mcp-configand a marcus-only--mcp-config, so the session has only the ~16 Marcus tools — under the deferral threshold — and they're directly callable:The old
claude mcp add marcussnippet becomes a no-op:--strict-mcp-configignores~/.claude.jsonanyway, and dropping it removes parallel panes racing to write that file.Applies to both worker and project-creator panes (both route through
build_agent_command).Validation
Ran one worker by hand against a live board with this exact config and watched the full stream-json trace:
register_agent→request_next_task(claimed) →get_task_context→ wrotegameState.js+ TDD tests →log_decision("Public API surface") +log_artifact×4 →report_task_progress0→25→50→75→100 → committed.npm test: 20 passed, 0 failed.Note
This very likely also resolves the spawn-thrash teardown as a side effect: once an agent actually claims,
in_flight≥ 1 andcompute_spawn_count→ 0, so the detector holds instead of ticking. Hardening the detector with a real progress signal (claims/in_progress/heartbeats) is a follow-up.🤖 Generated with Claude Code