Require Allowlist Entry on an MCP Server's First Tool Call

The trust dialog Claude Code shows is per-session; this makes first-use trust a durable, file-based decision instead — a brand-new MCP server's very first tool call is denied until its name is added to a persistent allowlist, so trusting it once doesn't happen by reflex.

MCP & Config Safety Event: PreToolUse Claude Code Open source · Free

1. Save this as the hook script

#!/usr/bin/env python3
"""PreToolUse hook — denies an MCP server's first tool call unless it's
already in a persistent allowlist file. Wire to matcher "mcp__.*"."""
import json, re, sys
from pathlib import Path

data = json.load(sys.stdin)
tool_name = data.get("tool_name", "")

if not tool_name.startswith("mcp__"):
    sys.exit(0)

server = tool_name.split("__")[1] if len(tool_name.split("__")) > 1 else ""
allowlist_path = Path(data.get("cwd", ".")) / ".claude" / "mcp_server_allowlist.txt"
allowed = set(allowlist_path.read_text().splitlines()) if allowlist_path.exists() else set()

if server not in allowed:
    print(f"BLOCKED: MCP server '{server}' is not in {allowlist_path}. "
          f"Add it on its own line once reviewed, then retry.", file=sys.stderr)
    sys.exit(2)

sys.exit(0)

Save to a path inside your project, e.g. .claude/hooks/require-allowlist-first-use-mcp-server.sh, then chmod +x it.

2. Wire it into .claude/settings.json

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__.*",
        "hooks": [
          {"type": "command", "command": "python3 .claude/hooks/require-allowlist-first-use-mcp-server.py"}
        ]
      }
    ]
  }
}

Before you use this

A hook runs with your local shell's permissions — review the script above before adding it, the same way you'd review any script you didn't write yourself. See our guide on hook security risks for the specific CVEs this category of feature has already produced.

Related hooks

← All hooks
FEEDBACK