Skip to content

feat: MCP permission model + unified policy enforcement + settings UI (Phase 4) - #129

Open
Blankll wants to merge 5 commits into
masterfrom
feat/mcp-permissions-ui
Open

feat: MCP permission model + unified policy enforcement + settings UI (Phase 4)#129
Blankll wants to merge 5 commits into
masterfrom
feat/mcp-permissions-ui

Conversation

@Blankll

@Blankll Blankll commented Aug 2, 2026

Copy link
Copy Markdown
Member

Summary

Mirror of dockit #473 with sqlkit deltas (port 9121, db_type key, pages.settings.mcp.* i18n namespace).

Phase 4 of the Data Studio MCP permission model for dockit: server-side policy enforcement in the MCP bridge AND the built-in agent loop, plus the permission settings UI.

Changes

1. Bridge: McpPolicy enforcement + flat /tools (mcp_bridge.rs)

  • Bump data-studio-agent → rev 49f89a4 (PolicyAction + confirm_destructive)
  • McpConfig.policy field (serde default, backward compatible with existing mcp-config.json)
  • Pure check_policy() gate: allowlist → read-only override → confirm_destructive → mode; /invoke 403 with clear message
  • invoke_with_policy() extracted for testability (no AppHandle needed in unit tests)
  • /tools returns flat [{name, description, inputSchema, metadata:{riskLevel, requiredPermission}}] filtered by policy (was OpenAI-shaped + unfiltered)
  • get_mcp_status returns policy; save_mcp_config accepts policy arg (preserves existing when omitted)

2. Built-in agent loop: server-side Deny (agent_adapters.rs)

  • run_agent_loop builds a should_deny closure from McpPolicy (mcp-config.json) and passes it to the crate loop
  • Policy-denied tools get status denied + error result, never reach execution or the confirmation dialog — no frontend round-trip
  • The MCP bridge and built-in loop now enforce the same policy (single policy, two enforcers); previously the built-in loop had zero server-side enforcement

3. Settings UI (mcp-bridge.vue)

  • Permission Mode RadioGroup — Read Only / Data Read-Write / Full Access
  • Confirm Destructive Switch — gated on Full Access
  • Connection Allowlist checkbox list (from connection store)
  • Per-connection Read-only switch list
  • snake_case policy round-trip via save_mcp_config
  • 15 new setting.mcp.* i18n keys (enUS + zhCN)

Architecture (three layers)

Layer What Where
L1 Tool risk (RiskLevel) capability registry (static)
L2 Server policy (McpPolicy.decide()) MCP bridge + built-in loop (both enforce Deny)
L3 Client session policy (Ask/Auto) frontend — unchanged

Permission model

Mode Safe Elevated Destructive
ReadOnly
DataReadWrite
FullAccess ✅ (requires confirm_destructive=true)

Allowlist (empty = all) + per-connection read-only override layer on top.

Verification

  • cargo test — 324 passed
  • cargo check clean; clippy/fmt no new issues on changed files
  • tsc --noEmit / lint:check / build green (UI)

Part of geek-fun/data-studio-agent#9 / #10. Companion PR: data-studio-agent #20 (crate), sqlkit #129.

Blankll added 3 commits August 2, 2026 22:40
- bump data-studio-agent to feat/mcp-permissions (confirm_destructive)
- McpConfig.policy field (serde default, backward compatible)
- pure check_policy() gates /invoke: mode → allowlist → read-only override → confirm_destructive
- invoke_with_policy() extracted for testability
- /tools returns flat [{name, description, inputSchema, metadata:{riskLevel, requiredPermission}}] filtered by policy
- get_mcp_status returns policy; save_mcp_config accepts policy arg (preserves existing on None)
…connection overrides

- Permission Mode RadioGroup (ReadOnly/DataReadWrite/FullAccess)
- Confirm Destructive Switch (gated on FullAccess)
- Connection allowlist Checkbox list (from connectionStore)
- Per-connection read-only Switch list
- snake_case policy round-trip via save_mcp_config
- i18n: 15 new pages.settings.mcp.* keys (en/zh)
- bump data-studio-agent to 49f89a4 (PolicyAction + should_deny param)
- run_agent_loop passes should_deny closure: loads McpPolicy from mcp-config,
  denies tools where policy.allows(risk, conn_id) is false
- Deny short-circuits before confirmation await (no frontend round-trip)
@Blankll Blankll changed the title feat: MCP permission model enforcement + settings UI (Phase 4) feat: MCP permission model + unified policy enforcement + settings UI (Phase 4) Aug 2, 2026
Blankll added 2 commits August 3, 2026 00:44
… UX, confirm_destructive defaults

- agent_adapters: deny DB capabilities when allowlist set but connection_id
  omitted (fallback connection would bypass the allowlist); AppLocal tools exempt
- mcp-bridge.vue: default confirmDestructive true (match Rust default)
- onModeChange no longer resets confirm_destructive when leaving FullAccess
- allowlist: explicit enable switch — empty state shows disabled checkboxes
…dback

- bump data-studio-agent to 6fae4e5 (default DataReadWrite, McpAction)
- tests updated for DataReadWrite default (rejects Destructive)
- UI: Font Weight card-style permission mode (single row + desc),
  Port + Auto-start in one card, Confirm Destructive inside mode card
  (shown only for FullAccess, defaults on)
- Connection Access merged scrollable table with per-connection
  Read/Write/Delete actions (McpAction)
- Restart Bridge: phase feedback (shutting-down/starting), spinner,
  disabled during restart, 60s timeout, success/error toasts
- i18n: new keys (en/zh)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant