Skip to content

feat: allow approved external MCP tools in root plan mode#24509

Merged
ibetitsmike merged 6 commits intomainfrom
mike/plan-mode-mcp-allow
Apr 21, 2026
Merged

feat: allow approved external MCP tools in root plan mode#24509
ibetitsmike merged 6 commits intomainfrom
mike/plan-mode-mcp-allow

Conversation

@ibetitsmike
Copy link
Copy Markdown
Collaborator

Summary

Allow root plan-mode chats to use MCP tools from external servers that an admin has explicitly approved for plan mode. Workspace MCP and plan-mode subagents remain blocked.

Problem

chatd.go excluded every MCP tool when isPlanModeTurn was true, so planning had no access to tools like docs search, ticketing, etc. Lifting that guard wholesale was unsafe: mcp_server_configs already has centralized admin governance, but workspace-local MCP (discovered from agent .mcp.json) does not, and subagents use a narrower trust boundary.

Fix

Add an admin-controlled per-server allow_in_plan_mode flag (default false) and gate plan-mode MCP access on it.

Backend / schema

  • New migration 000472_mcp_server_allow_in_plan_mode.{up,down}.sql and matching fixture update.
  • mcpserverconfigs.sql + generated code: persist and read the new column.
  • codersdk/mcp.go: thread the field through MCPServerConfig, Create*, and Update* request types.
  • coderd/mcp.go: validate, persist, and return the flag in get/list/create/update handlers.

chatd

  • coderd/x/chatd/chatd.go: pre-filter selected external MCP configs by AllowInPlanMode before calling mcpclient.ConnectAll on plan-mode root turns. Workspace MCP discovery is skipped entirely on plan-mode turns.
  • Single helper decides whether a tool is available in plan mode, used both at construction and for active-tool filtering (defense in depth). Plan-mode subagents, dynamic tools, provider-native tools, computer-use, and workspace MCP stay unchanged.
  • coderd/x/chatd/prompt.go: update the root plan-mode overlay text to match the new boundary.

UI

  • MCPServerAdminPanel.tsx: add an explicit toggle ("Allow all tools from this MCP server in root plan mode") next to the existing governance controls.
  • Regenerated site/src/api/typesGenerated.ts.

Docs

  • docs/ai-coder/agents/architecture.md: replace the blanket "MCP is unavailable in plan mode" note with the new root-only, external-only, admin-approved policy. Explicitly call out that workspace MCP and plan-mode subagents are still excluded.

Tests

  • Plan-mode visibility (approved vs non-approved external server).
  • Plan-mode invocation of an approved external MCP tool.
  • End-to-end plan-mode workflow that uses an approved MCP tool and then reaches propose_plan.
  • Regressions: workspace MCP still excluded in plan mode; plan-mode subagents still on the restricted tool boundary; existing tool allow/deny list filtering still applies.

Policy precedence

allow_in_plan_mode is an additional requirement on top of existing enabled, availability, chat-selected / forced server IDs, and tool allow/deny lists. It approves all tools on that server for root plan mode; a per-tool plan allowlist is deliberately deferred.

Follow-ups (explicitly out of scope)

  • Whether plan-mode subagents should inherit approved external MCP tools.
  • Workspace-local MCP safety model (agent-side .mcp.json schema vs. a coderd-managed workspace MCP config).

Validation

  • go vet ./coderd/x/chatd/...
  • go test ./coderd/x/chatd -run 'TestPlan.*|TestMCP.*' -count=1
  • go test ./coderd/x/chatd -count=1 -timeout 5m (full chatd suite)
  • make fmt (no diff)

Mux opened this PR on Mike's behalf.

…mode

Rebase merge note: resolved chatd conflicts against origin/main and renumbered the allow_in_plan_mode migration to 000472 to avoid the new 000471 chat explore mode migration on main.
@ibetitsmike
Copy link
Copy Markdown
Collaborator Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c6f0d7c1b8

ℹ️ 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".

Comment thread coderd/database/migrations/testdata/fixtures/000447_mcp_server_configs.up.sql Outdated
@ibetitsmike
Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

ℹ️ 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".

Copy link
Copy Markdown
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well-structured change. The three-layer defense-in-depth design (config pre-filter, tool post-filter, active-tool-name filter) is genuinely solid, and the security reviewers confirmed every boundary holds. The MCPToolIdentifier interface pattern structurally excludes workspace MCP tools without relying on name conventions. Test coverage is proportional: 780 lines of tests for 230 lines of production code, covering visibility, invocation, workflow completion, and regressions.

One P1 blocks merge (DEREM-3, below). Two P3s worth addressing. Four nits, all optional.

P1 [DEREM-3] coderd/database/migrations/testdata/fixtures/000447_mcp_server_configs.up.sql:10 -- The 447 fixture now references allow_in_plan_mode, but that column is introduced in migration 472. When TestMigrateUpWithFixtures replays migrations with fixtures, this INSERT runs at version 447 against a schema that lacks the column, producing a "column allow_in_plan_mode does not exist" error. This is likely the root cause of the CI failures (test-go-pg, test-go-pg-17, test-go-race-pg). Fix: remove allow_in_plan_mode and its value from this fixture. If fixture coverage for the new column is needed, add a separate 000472_mcp_server_allow_in_plan_mode.up.sql fixture that ALTERs the existing row.

"Two functions that both claim to resolve 'which tools are active in plan mode' now produce different results for the same inputs." -- Razor

Severity counts: 1 P1, 2 P3, 4 Nit.


coderd/x/chatd/chatd.go:4551

P3 [DEREM-4] allowedPlanToolNames is dead code on every production path after this PR. appendDynamicTools (line 4974) returns early for plan mode before reaching allowedBehaviorToolNames, so this function is never called at runtime. The live plan-mode gate is now activeToolNamesForTurn, which includes approved MCP tools via toolAllowedForTurn.

The two functions answer the same question ("which tools are active in plan mode?") but give different answers: allowedPlanToolNames returns builtins only, activeToolNamesForTurn returns builtins + approved MCP. They share builtinPlanToolAllowed, so the builtin allowlist can't drift, but a future editor re-introducing a call to allowedBehaviorToolNames in plan mode would silently exclude MCP tools. TestAllowedPlanToolNames would pass while production diverges.

Could we remove allowedPlanToolNames and simplify allowedBehaviorToolNames to handle only the explore-subagent dispatch? If unit coverage of the builtin switch is desired, test builtinPlanToolAllowed directly. (Meruem P3, Hisoka P3, Mafuuu P3, Ryosuke P3, Chopper P3, Gon P3, Razor P3, Knov P4, Pariston Note, Kite Note)

🤖

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/x/chatd/chatd.go
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/chatd.go Outdated
Comment thread coderd/x/chatd/prompt.go
Comment thread site/src/pages/AgentsPage/components/MCPServerAdminPanel.tsx
@ibetitsmike ibetitsmike requested a review from mafredri April 18, 2026 13:35
@ibetitsmike
Copy link
Copy Markdown
Collaborator Author

@codex review

Copy link
Copy Markdown
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 of 7 findings from R1 were addressed. Nice work on the fixture fix, the unit test for filterExternalMCPConfigsForTurn, and all four nits.

Further review is blocked until the following finding is addressed or acknowledged:

DEREM-4 (P3) chatd.go:4551 -- allowedPlanToolNames is dead code on every production path. appendDynamicTools returns early for plan mode before reaching allowedBehaviorToolNames, so the plan-mode branch is never executed. The live gate is activeToolNamesForTurn. The two functions answer "which tools are active in plan mode?" with different answers: builtins-only vs builtins + approved MCP. 10 reviewers flagged this independently.

Options: remove the dead function, add a comment explaining why it's kept, or push back if you disagree with the finding.

🤖 This review was automatically generated with Coder Agents.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

ℹ️ 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".

@ibetitsmike ibetitsmike requested a review from mafredri April 18, 2026 14:16
@ibetitsmike
Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

ℹ️ 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".

@ibetitsmike
Copy link
Copy Markdown
Collaborator Author

Addressed DEREM-4 on ad4c2c2fc5 by removing the dead allowedPlanToolNames path and narrowing allowedBehaviorToolNames to the non-plan dynamic-tool path that still uses it.

Mux worked on behalf of Mike.

@ibetitsmike ibetitsmike requested review from mafredri and removed request for mafredri April 19, 2026 12:05
Copy link
Copy Markdown
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Status: APPROVED

All 8 findings from R1 are resolved. The DEREM-4 fix (removing dead allowedPlanToolNames, narrowing allowedBehaviorToolNames) is clean: no orphaned references, tests updated, comments accurate.

R3 panel (Mafuuu, Meruem, Bisky, Kite, Razor) found no new issues. Razor verified 8 PR claims against the implementation; all hold. Bisky confirmed the test suite is thorough across unit, integration, and e2e layers. Kite verified the four-layer trust boundary and ran the full test set. The defense-in-depth architecture is intact.

CI is pending (21 passed, 2 pending at setup). No findings.

"One function, two enforcement layers, no drift." -- Kite

🤖 This review was automatically generated with Coder Agents.

@mafredri mafredri dismissed their stale review April 20, 2026 08:11

Resolved in follow-up review.

@ibetitsmike ibetitsmike requested a review from mafredri April 20, 2026 11:06
@ibetitsmike
Copy link
Copy Markdown
Collaborator Author

@codex review

@ibetitsmike
Copy link
Copy Markdown
Collaborator Author

Mux working on behalf of Mike.
Merged origin/main to resolve the PR conflict, reran local validation, re-requested mafredri, and requested a fresh Codex review for the new head SHA.

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

ℹ️ 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".

Copy link
Copy Markdown
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Status: APPROVED

Re-reviewed after merge of main. Netero and panel (Mafuuu, Kite, Meruem) found no new issues. All 8 R1 findings remain resolved. The merge introduced no conflicts in the PR's code; the defense-in-depth architecture is intact.

CI is pending (11 passed, 11 pending at setup). No findings across 4 rounds.

🤖 This review was automatically generated with Coder Agents.

@ibetitsmike ibetitsmike requested a review from mafredri April 20, 2026 11:54
Copy link
Copy Markdown
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No changes since R4 (same head SHA a3fe03b). All 8 R1 findings remain resolved. Panels in R3 and R4 found 0 new issues on this exact diff. CI progressing (21 passed, 2 pending). Prior approval stands; nothing to re-review.

🤖 This review was automatically generated with Coder Agents.

@ibetitsmike ibetitsmike requested a review from mafredri April 20, 2026 12:27
@ibetitsmike
Copy link
Copy Markdown
Collaborator Author

Mux working on behalf of Mike.

Ran the post-idle PR check on head a3fe03b39f1d836991fc92f6c121c663edf88475. No new actionable review threads, CI failures, or merge conflicts were found. Re-requested mafredri review. Codex review remains satisfied on this head.

Copy link
Copy Markdown
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Status: APPROVED

R6 re-review on unchanged code (same head SHA since R4). Netero and panel (Mafuuu, Kite, Chopper) found 0 new issues. All 8 R1 findings remain resolved. Four consecutive clean panel rounds (R3, R4, R5, R6). CI steady (21 passed, 2 pending).

This PR is ready for human merge.

🤖 This review was automatically generated with Coder Agents.

@ibetitsmike ibetitsmike requested a review from mafredri April 20, 2026 13:03
@ibetitsmike
Copy link
Copy Markdown
Collaborator Author

Mux working on behalf of Mike.

Re-ran the idle PR check on head a3fe03b39f1d836991fc92f6c121c663edf88475. There are no new actionable review threads, merge conflicts, or CI failures. I re-requested mafredri, and Codex already responded on this head. The required check is passing. The only remaining GitHub-side items are Chromatic UI Tests and UI Review, which are still pending baseline acceptance.

Copy link
Copy Markdown
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Status: APPROVED

R7: unchanged head (a3fe03b). Netero + panel (Mafuuu, Meruem, Kite) found 0 issues. Five consecutive clean panel rounds. All 8 R1 findings resolved. CI steady. Ready for human merge.

🤖 This review was automatically generated with Coder Agents.

@ibetitsmike ibetitsmike requested a review from mafredri April 20, 2026 13:40
Copy link
Copy Markdown
Member

@mafredri mafredri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Status: APPROVED

R8: unchanged head (a3fe03b). Netero + panel (Mafuuu, Kite, Razor) found 0 issues. Six consecutive clean panel rounds. All 8 R1 findings resolved. CI steady. Ready for human merge.

🤖 This review was automatically generated with Coder Agents.

@ibetitsmike ibetitsmike marked this pull request as ready for review April 21, 2026 10:25
@ibetitsmike ibetitsmike merged commit 9d0469f into main Apr 21, 2026
36 checks passed
@ibetitsmike ibetitsmike deleted the mike/plan-mode-mcp-allow branch April 21, 2026 10:26
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants