Skip to content

feat: add tool-level quarantine with rug pull detection#328

Merged
Dumbris merged 14 commits intomainfrom
032-tool-quarantine
Mar 10, 2026
Merged

feat: add tool-level quarantine with rug pull detection#328
Dumbris merged 14 commits intomainfrom
032-tool-quarantine

Conversation

@Dumbris
Copy link
Member

@Dumbris Dumbris commented Mar 10, 2026

Summary

  • Extend server-level quarantine to individual tool granularity using SHA-256 description hashing
  • Detect tool description changes (rug pull attacks) and block affected tools while other tools on the same server continue working
  • New ToolApprovalRecord model with state machine: pending -> approved -> changed -> approved
  • REST API endpoints: inspect tools, approve (individual/bulk), diff view, export descriptions
  • CLI commands: mcpproxy upstream inspect <server> and mcpproxy upstream approve <server>
  • MCP tool: extended quarantine_security with inspect_tools, approve_tool, approve_all_tools operations
  • Web UI: quarantine panel in ServerDetail with approve buttons and inline diff
  • Activity logging: all quarantine events (blocked, approved, changed) with full description text
  • Config: quarantine_enabled (global, default true) and skip_quarantine (per-server)
  • Hashes always calculated even when quarantine disabled (for future security features)
  • Cleanup: tool approval records properly removed when server is deleted

Test plan

  • Storage CRUD: save, get, list, delete tool approvals with status transitions
  • Hash calculation: deterministic SHA-256 of name|description|schema
  • State machine: pending -> approved -> changed -> approved lifecycle
  • Execution blocking: pending/changed tools blocked, approved tools pass through
  • Quarantine disabled: hashes stored but tools not blocked
  • Per-server skip: skip_quarantine config respected
  • REST API: 11 handler tests covering approve, diff, export, error cases
  • Config: quarantine_enabled defaults to true, explicit false works
  • Server removal: tool approval records cleaned up
  • Build verification: personal and server editions compile clean
  • Race detector: all tests pass with -race

claude added 13 commits March 10, 2026 09:50
Add tool-level quarantine storage layer:
- ToolApprovalRecord model with status (pending/approved/changed),
  hash tracking, and description diff fields
- BBolt CRUD operations: Save, Get, List (by server), Delete, DeleteAll
- Storage Manager wrapper methods with proper locking
- Comprehensive tests covering roundtrips, filtering, status transitions
- Config.QuarantineEnabled (*bool): defaults to true when nil (secure by
  default), explicit false disables tool-level quarantine globally
- ServerConfig.SkipQuarantine (bool): per-server opt-out from tool-level
  quarantine while still tracking hashes
- Helper methods: IsQuarantineEnabled() and IsQuarantineSkipped()
- Tests for default values, explicit overrides, and JSON serialization
Core tool quarantine engine:
- calculateToolApprovalHash: stable SHA-256 hash of tool name,
  description, and schema for rug-pull detection
- checkToolApprovals: checks discovered tools against stored approval
  records, creates pending records for new tools, detects changes
- ApproveTools/ApproveAllTools: approve pending/changed tools
- Integration into applyDifferentialToolUpdate: blocked tools are
  filtered from indexing and removed from index if previously indexed
- Respects quarantine_enabled (global) and skip_quarantine (per-server)
  config flags -- hashes are always tracked even when not enforcing
- Activity events emitted for tool discovery, changes, and approvals
- Existing tool invalidation tests updated to disable quarantine
In handleCallToolVariant, after server-level quarantine check:
- Look up ToolApprovalRecord for the requested tool
- If status is "pending": block with structured JSON explaining it is
  a new unapproved tool, include description and approval instructions
- If status is "changed": block with previous/current descriptions
  showing what changed, include approval instructions
- Respects quarantine_enabled and skip_quarantine config flags
- Emits activity policy decision events for blocked calls
- New ActivityTypeToolQuarantineChange activity type for tool-level
  quarantine state changes (discovered, changed, approved)
- handleToolQuarantineChange handler in ActivityService persists
  tool quarantine events with full metadata (descriptions, hashes)
- Added to ValidActivityTypes for filter support
Add ServerController interface methods for tool-level quarantine:
- ListToolApprovals, ApproveTools, ApproveAllTools, GetToolApproval

Add REST API routes under /api/v1/servers/{id}/:
- POST /tools/approve - approve specific tools or all tools
- GET /tools/{tool}/diff - view description/schema changes
- GET /tools/export - export tool descriptions (JSON or text)

Add Runtime delegation methods and mock controller stubs.
Add 11 handler tests covering all endpoints and error paths.
Add 'mcpproxy upstream inspect <server>' to view tool approval status
with table/JSON/YAML output and --tool flag for detailed diff view.

Add 'mcpproxy upstream approve <server> [tools...]' to approve pending
or changed tools, with approve-all when no tool names given.

Add cliclient methods: GetToolApprovals, GetToolDiff, ApproveTools.
Add Server delegation methods for ServerController interface.
Add ToolApproval type and API methods (getToolApprovals, getToolDiff,
approveTools) to frontend services.

Add quarantine panel in ServerDetail Tools tab showing pending/changed
tools with approve individual/all buttons and inline diff view for
changed tool descriptions.
Add inspect_tools, approve_tool, and approve_all_tools operations
to the quarantine_security MCP tool, enabling AI agents to inspect
tool approval status and approve individual or all pending/changed
tools via the MCP protocol.
SkipQuarantine is a runtime-only config field (Spec 032) that does
not need BBolt persistence. Add it to the SaveServerSync field
coverage test's exclusion list alongside Shared.
Add tool-level quarantine to Security Model, CLI commands, Built-in
Tools, HTTP API endpoints, and Key Implementation Details sections.
Prevents orphaned ToolApprovalRecords from accumulating in the
tool_approvals BBolt bucket when an upstream server is deleted.
Follows the same pattern as ClearOAuthState cleanup.
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Mar 10, 2026

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: f00c04a
Status: ✅  Deploy successful!
Preview URL: https://eae4b6de.mcpproxy-docs.pages.dev
Branch Preview URL: https://032-tool-quarantine.mcpproxy-docs.pages.dev

View logs

@github-actions
Copy link

github-actions bot commented Mar 10, 2026

📦 Build Artifacts

Workflow Run: View Run
Branch: 032-tool-quarantine

Available Artifacts

  • archive-darwin-amd64 (24 MB)
  • archive-darwin-arm64 (21 MB)
  • archive-linux-amd64 (13 MB)
  • archive-linux-arm64 (11 MB)
  • archive-windows-amd64 (24 MB)
  • archive-windows-arm64 (21 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (26 MB)
  • installer-dmg-darwin-arm64 (24 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 22897566983 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

- Convert if/else chain to switch statement in handleInspectToolApprovals
  to fix staticcheck QF1003 lint error
- Disable tool-level quarantine in E2E test environment since existing
  tests don't test this feature (quarantine-specific tests have their
  own setup). Without this, new tools from mock servers were blocked as
  "pending" approval, causing 4 E2E test failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Dumbris Dumbris merged commit 6e2862b into main Mar 10, 2026
40 checks passed
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.

2 participants