Skip to content

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

Description

@mcaldas

Summary

Add an optional, declarative MCP capability policy to config.json so operators can pin which MCP tools are exposed — globally and per account — without assembling long --allow-tool / --enable-commands-exact argument strings in every client config.

The default (no config) is unchanged: read-only, exactly like today. This is a governance/ergonomics layer for operators who run gog mcp across several accounts, not a way to widen the tool surface.

Motivation

gog mcp already has excellent runtime controls (--allow-tool, --allow-write, --enable-commands-exact, --disable-commands, --gmail-no-send, --readonly) plus baked safety profiles. In practice, two gaps remain for operators wiring MCP into clients like Claude Desktop:

  1. Per-account policy is awkward. A common need is "work account read-only, personal account may write" — today that means duplicating and hand-tuning flag strings across multiple mcpServers entries. The CLI has no per-account MCP policy, even though the config layer already models per-account safety for sending (gmail_no_send + no_send_accounts in internal/config/config.go).
  2. Selection isn't declarative or discoverable. Choosing a curated subset means a long --allow-tool read,tool_a,tool_b,... argv that's easy to get wrong and invisible to review.

This proposal reuses the existing gmail_no_send / no_send_accounts idiom — a global default plus a per-account override map — and extends it to MCP tool exposure.

Prior art / concerns this tries to respect

Proposed shape

A new optional mcp block in config.json (JSON5, so comments are fine):

{
  "mcp": {
    // Global default. Ships as "readonly" == current upstream behavior.
    "profile": "readonly",            // readonly | standard | power, or a user-defined name

    // Optional user-defined bundles (expand to tier + allow/deny).
    "profiles": {
      "standard": { "tiers": ["write"], "deny": ["<destructive tool names>"] }
    },

    // Optional per-tool overrides on top of the active profile.
    "tools": {
      "gmail_send": false
    },

    // Per-account overrides — mirrors no_send_accounts.
    "accounts": {
      "[email protected]":  { "profile": "power" },
      "[email protected]":      { "profile": "readonly" }
    }
  }
}

Resolution precedence (most specific wins), so nothing surprising:

CLI flags (--allow-write / --allow-send / --allow-tool)   [highest]
  > config: accounts.<active>.*
  > config: tools.*  (per-tool booleans)
  > config: profile  (named preset)
  > built-in default: readonly (== upstream)              [lowest]

Baked safety profiles remain the tamper-proof ceiling and are unaffected (still checked before any handler).

Non-goals

  • No generic exec / command bridge.
  • No new tools and no change to which tools are write-gated. The maintainer stays the sole curator of the tool set; this only lets operators select from / restrict it and set per-account defaults.
  • No change to default behavior (absent mcp block == today).

Alternatives considered

  • Flags only (status quo). Works, but can't express per-account defaults and forces long, error-prone argv duplicated across client entries.
  • A separate policy file. More moving parts; config.json already owns account-scoped policy (no_send_accounts), so extending it is the smaller, more idiomatic change.

Willing to implement

Happy to send a PR (config struct + resolver + gog mcp wiring + docs + tests) if the shape looks acceptable. Wanted to align on the design and confirm it's welcome before writing it, given this touches the MCP capability surface. Open to a narrower cut (e.g. per-account profile only, dropping the tools/profiles maps) if you'd prefer to start minimal.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low-risk cleanup, docs, polish, ergonomics, or speculative feature.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:needs-security-reviewClawSweeper marked this issue as needing security-sensitive review.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:securityThis issue is about security boundaries, credentials, authz, sandboxing, or sensitive data.issue-rating: 🌊 off-meta tidepoolIssue quality rating does not apply to this item.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions