diff --git a/docs/features/tool-quarantine.md b/docs/features/tool-quarantine.md index a8b8078ed..f6b5329e2 100644 --- a/docs/features/tool-quarantine.md +++ b/docs/features/tool-quarantine.md @@ -205,7 +205,7 @@ curl -H "X-API-Key: your-key" \ 1. Open the MCPProxy dashboard 2. Click on a server in the server list 3. Navigate to the **Tools** tab in the server detail view -4. Review changed (and any residual pending) tools and click **Approve** or **Approve All** +4. Review pending and changed tools and click **Approve** or **Approve All** Each quarantined tool also offers a **Block** button (and the banner a **Block All**) next to Approve. Blocking rejects the tool: it leaves the quarantine list @@ -213,12 +213,14 @@ and is disabled in the tools list, so AI agents can neither see nor call it. Blocking is reversible — re-enable the tool later with its toggle in the tools list (or `mcpproxy tools enable `). -The server detail view's **Tool Quarantine** banner is shown only when a tool's -status is `changed` (a rug-pull). Once a change has surfaced, any residual -`pending` tools are listed alongside it so they can be cleared in the same pass. -Freshly-`pending` baseline tools do **not** raise the banner on their own: -approving the **server** (lifting the server-level Security Quarantine) promotes -its baseline `pending` tools to `approved`. While the server-level **Security +The server detail view's **Tool Quarantine** banner surfaces every `pending` +(new, never-approved) or `changed` (rug-pull) tool while the server itself is +**not** quarantined. Both are genuinely blocked by the backend until the +operator acts, and the server list page counts them (`pending_count + +changed_count`), so the banner and the count agree. The banner carries a short, +dismissible hint noting that pending tools come from tool-level quarantine and +can be auto-approved by setting `skip_quarantine: true` (per-server) or +`quarantine_enabled: false` (global). While the server-level **Security Quarantine** banner is showing, the Tool-Quarantine banner is suppressed entirely — the operator approves the server first, and the two banners never appear at once. diff --git a/frontend/src/utils/toolQuarantine.ts b/frontend/src/utils/toolQuarantine.ts index 42e0a39b8..b371e6f1d 100644 --- a/frontend/src/utils/toolQuarantine.ts +++ b/frontend/src/utils/toolQuarantine.ts @@ -2,28 +2,33 @@ import type { ToolApproval } from '@/types' /** * Selects the tools that warrant the per-server Tool-Quarantine banner / list - * (Spec 032, parent MCP-2081, MCP-2101). + * (Spec 032, parent MCP-2916, MCP-2917). * - * Trust model (confirmed on MCP-2081): when an operator approves a *server* - * (lifting the server-level Security Quarantine), the backend promotes that - * server's baseline `pending` tools to `approved`. A freshly-`pending` baseline - * tool is therefore NOT a reason to nag the operator with a tool-level banner — - * only a `changed` tool (a rug-pull) is. + * On a live, NON-quarantined server a `pending` (new, never-approved) tool is + * genuinely blocked by the backend (`checkToolApprovals` → `BlockedTools`) and + * the Servers page already counts it (`pending_count + changed_count`). The + * banner must therefore surface both `pending` and `changed` tools so the + * operator can approve them; banner and count must agree. Pending tools come + * from tool-level quarantine and can be auto-approved by setting + * `skip_quarantine: true` (per-server) or `quarantine_enabled: false` (global). * * Rules: * - While the server is quarantined, suppress the tool banner entirely. The * server-level Security Quarantine banner already covers it and the operator * must approve the server first — never show two banners at once. - * - Otherwise the banner keys off `status === 'changed'`. Only once a change - * has surfaced do we also include any residual `pending` tools so the - * operator can clear them in the same approval pass. + * - Otherwise surface every tool that is `pending` (awaiting first approval) or + * `changed` (a rug-pull), since both are blocked until the operator acts. + * + * Note: this intentionally reverses the MCP-2101 "don't nag on a pending + * baseline" behavior for non-quarantined servers. That trust model assumed + * approving the server would promote pending→approved, but a server can be + * non-quarantined (e.g. `skip_quarantine`) while its tools stay pending and + * blocked, leaving the operator no way to approve them. */ export function selectQuarantinedTools( toolApprovals: ToolApproval[], serverQuarantined: boolean, ): ToolApproval[] { if (serverQuarantined) return [] - const hasChanged = toolApprovals.some((t) => t.status === 'changed') - if (!hasChanged) return [] return toolApprovals.filter((t) => t.status === 'changed' || t.status === 'pending') } diff --git a/frontend/src/views/ServerDetail.vue b/frontend/src/views/ServerDetail.vue index e037a0bdb..d04e7f332 100644 --- a/frontend/src/views/ServerDetail.vue +++ b/frontend/src/views/ServerDetail.vue @@ -340,6 +340,26 @@
{{ quarantinedTools.length }} tool(s) require approval before they can be used by AI agents.
+ +
+ + Pending tools come from tool-level quarantine. To approve them automatically, set + skip_quarantine: true for this server or + quarantine_enabled: false globally. + + +