Skip to content

feat(mcp): add account capability policies#914

Merged
steipete merged 1 commit into
mainfrom
feat/mcp-account-capability-policy
Jul 11, 2026
Merged

feat(mcp): add account capability policies#914
steipete merged 1 commit into
mainfrom
feat/mcp-account-capability-policy

Conversation

@steipete

Copy link
Copy Markdown
Collaborator

Summary

  • add an optional persistent MCP capability ceiling to config.json
  • support complete per-account policies using the existing MCP selectors
  • resolve and pin stored-account identities while keeping direct-token and ADC modes on the global policy
  • fail closed on unknown selectors, explicit empty lists, write widening, invalid unselected policies, and account-migration collisions
  • preserve legacy runtime flag behavior when no MCP policy is configured

Closes #913.

Proof

  • make ci
  • govulncheck ./... — zero callable vulnerabilities
  • actionlint
  • focused MCP/config/account-migration tests
  • source-blind behavior contract: all eight clauses passed, including legacy behavior, global/account selection, persistent narrow writes, runtime narrowing, root read-only, invalid config, and widening rejection
  • live authenticated MCP stdio gmail_search: typed read result with exit code 0
  • autoreview: clean, no accepted/actionable findings

Notes

  • no new dependencies or MCP tools
  • no shell or workflow files changed
  • full-repo ShellCheck still reports existing findings in untouched live-test scripts

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

Copy link
Copy Markdown

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: 1304bac12c

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


if newKey != "" {
newPolicy := accounts[newKey]
if oldPolicy.AllowWrite != newPolicy.AllowWrite || !slices.Equal(oldPolicy.AllowTools, newPolicy.AllowTools) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize MCP policies before comparing collisions

When subject identity migration finds both old and new account policy keys, this compares the raw AllowTools slices. MCP policies can be equivalent after normalization but encoded differently, such as omitted allow_tools vs ["read"] or ["read,docs.*"] vs ["read", "docs.*"]; in those cases migration is rejected as a collision even though the effective ceiling is identical, which blocks token/account email migration for an otherwise safe config. Normalize both policies before deciding the destination already conflicts.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. labels Jul 11, 2026
@clawsweeper

clawsweeper Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed July 11, 2026, 5:03 AM ET / 09:03 UTC.

Summary
The PR adds persistent global and per-account MCP capability ceilings, resolved-account pinning, account-policy migration, documentation, and focused tests.

Reproducibility: yes. at the source level: add a new write tool whose service or risk matches a stored broad selector, and the next policy evaluation includes it without any config change. The current registry loop and selector matcher establish this path directly.

Review metrics: 3 noteworthy metrics.

  • Patch scope: 10 files, +479/-3. The change spans runtime authorization, persisted configuration, account migration, documentation, and regression tests.
  • Policy scopes: 1 global policy plus complete per-account replacements. These stored policies become the durable source of truth for MCP tool registration.
  • Selector semantics: exact plus service, wildcard, risk, and all selectors. Broad selector forms can resolve to additional capabilities when the registry changes.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #913
Summary: This PR is the direct implementation candidate for the linked persistent MCP capability-policy issue.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦐 gold shrimp
Patch quality: 🦐 gold shrimp
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Make persistent write authorization exact or versioned and add a regression test showing newly registered matching write tools are not silently authorized.
  • Post redacted authenticated MCP stdio evidence showing account selection, the final exposed tool list, one permitted narrow write, runtime narrowing, and widening rejection.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR reports a live authenticated MCP stdio result, but no redacted transcript, terminal capture, logs, or linked artifact is available to verify the changed behavior; after adding proof, updating the PR body should trigger review, or a maintainer can request @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] A stored write policy such as docs.* can silently authorize a newly introduced matching write tool after users upgrade the binary.
  • [P1] The PR intentionally replaces the previously mandatory per-process --allow-write consent gate when a persistent policy authorizes writes.
  • [P1] The claimed authenticated behavior proof is not available in an inspectable, redacted artifact.

Maintainer options:

  1. Stabilize persistent write authorization (recommended)
    Require exact or versioned write capabilities, add upgrade-focused regression coverage, and post inspectable authenticated proof before merge.
  2. Own dynamic future-tool authorization
    Merge only after explicit maintainer acceptance and prominent documentation that broad stored selectors include future matching write tools.
  3. Pause the persistent policy feature
    Keep the PR open without landing until the durable authorization and per-process consent contract is settled.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Make persistent write authorization upgrade-stable by requiring exact write-tool names or explicit versioned reapproval, preserve broad read-only selectors, update documentation, and add focused upgrade regression tests.

Next step before merge

  • [P2] A maintainer must first choose the durable authorization and future-selector contract; the resulting exact-selector or versioning repair can then be implemented mechanically.

Maintainer decision needed

  • Question: What durable write-authorization contract should persistent MCP policies use across upgrades?
  • Rationale: The current patch both treats stored config as write consent and resolves broad selectors against an evolving registry, so maintainers must decide whether future matching writes are authorized automatically.
  • Likely owner: steipete — The current MCP/config history and authorship make this the clearest available owner for the permanent authorization contract.
  • Options:
    • Require exact persistent writes (recommended): Allow broad read selectors but require exact tool names for every persistently authorized write capability.
    • Accept dynamic selector expansion: Document that service, risk, and wildcard selectors intentionally authorize present and future matching write tools within baked safety ceilings.
    • Keep runtime write consent: Use stored config only as a non-widenable selector ceiling and continue requiring --allow-write for every write-enabled process.

Security
Needs attention: Persistent broad write selectors can silently expand after upgrades, and stored config becoming write consent requires explicit maintainer approval.

Review findings

  • [P1] Prevent broad policies from authorizing future writes — internal/cmd/mcp_policy.go:101-108
Review details

Best possible solution:

Make durable write authorization upgrade-stable by requiring exact write-tool identifiers or a versioned reapproval mechanism, while allowing broad selectors for read-only narrowing if desired.

Do we have a high-confidence way to reproduce the issue?

Yes at the source level: add a new write tool whose service or risk matches a stored broad selector, and the next policy evaluation includes it without any config change. The current registry loop and selector matcher establish this path directly.

Is this the best way to solve the issue?

No, not yet: the single fail-closed resolver and account pinning are sound foundations, but a durable authorization ceiling should not silently grow after upgrades unless maintainers explicitly choose and document that behavior.

Full review comments:

  • [P1] Prevent broad policies from authorizing future writes — internal/cmd/mcp_policy.go:101-108
    When allow_write is enabled, selectors such as docs.*, write, or all are re-evaluated against mcpAllTools() at every startup. Adding a new matching write tool in a later release therefore expands an existing stored authorization without any operator config change, which conflicts with this policy being a persistent ceiling; require exact write-tool names or an explicit versioned reapproval mechanism.
    Confidence: 0.94

Overall correctness: patch is incorrect
Overall confidence: 0.92

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against f69b2f87a33d.

Label changes

Label changes:

  • add P3: This is an optional operator-governance feature rather than a current urgent regression.
  • add merge-risk: 🚨 compatibility: An unchanged stored selector can resolve to additional tools after upgrading, changing an existing operator’s effective configuration.
  • add merge-risk: 🚨 security-boundary: Persistent configuration can authorize writes and broad selectors may silently include future matching write capabilities.
  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🦐 gold shrimp.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR reports a live authenticated MCP stdio result, but no redacted transcript, terminal capture, logs, or linked artifact is available to verify the changed behavior; after adding proof, updating the PR body should trigger review, or a maintainer can request @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Label justifications:

  • P3: This is an optional operator-governance feature rather than a current urgent regression.
  • merge-risk: 🚨 compatibility: An unchanged stored selector can resolve to additional tools after upgrading, changing an existing operator’s effective configuration.
  • merge-risk: 🚨 security-boundary: Persistent configuration can authorize writes and broad selectors may silently include future matching write capabilities.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR reports a live authenticated MCP stdio result, but no redacted transcript, terminal capture, logs, or linked artifact is available to verify the changed behavior; after adding proof, updating the PR body should trigger review, or a maintainer can request @clawsweeper re-review. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

Security concerns:

  • [high] Prevent silent expansion of persistent write policies — internal/cmd/mcp_policy.go:101
    Broad selectors are evaluated against the live registry on every startup, allowing future matching write tools to become authorized without a configuration change.
    Confidence: 0.94
  • [medium] Approve stored configuration as write consent — internal/cmd/mcp_policy.go:86
    The configured policy can expose explicitly selected write tools without the previously mandatory per-process --allow-write flag.
    Confidence: 1

What I checked:

  • Dynamic selector resolution: Stored selectors are evaluated against every tool returned by the live MCP registry at each startup, so service, risk, and wildcard selectors can resolve to newly added tools after an upgrade. (internal/cmd/mcp_policy.go:101, 1304bac12c46)
  • Persistent broad write policy: The documentation explicitly demonstrates allow_write with docs.*, which would include any future Docs write tool registered by the binary. (docs/mcp.md:125, 1304bac12c46)
  • Changed write-consent contract: A configured policy can expose its selected write tools without --allow-write, while current main documents that startup flag as always required. (internal/cmd/mcp_policy.go:86, 1304bac12c46)
  • Account identity binding: The PR reuses current account alias/default/single-token resolution and pins the selected stored account into RootFlags before child commands execute; direct-token and ADC modes remain on global policy. (internal/cmd/mcp.go:65, 1304bac12c46)
  • Feature provenance: The linked issue remains the canonical design request and previously asked maintainers to decide the persistent policy and ceiling semantics before implementation.
  • Current-area history: Bounded log and blame attribute the current MCP, account resolution, and config paths in this checkout to Peter Steinberger. (internal/cmd/mcp.go:1, 836378754862)

Likely related people:

  • steipete: Current-main history attributes the central MCP, account-resolution, and config paths to Peter Steinberger, who also authored this policy implementation. (role: MCP and account/config feature owner; confidence: high; commits: 836378754862, 1304bac12c46; files: internal/cmd/mcp.go, internal/cmd/account.go, internal/cmd/mcp_policy.go)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@steipete
steipete merged commit 5800e0e into main Jul 11, 2026
9 checks passed
@steipete
steipete deleted the feat/mcp-account-capability-policy branch July 11, 2026 09:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(mcp): config-driven capability policy (per-account, default-upstream)

1 participant