{
  "schema_version": 1,
  "id": "verify-mcp-allowlist",
  "track": "coding",
  "name": "Verify MCP Allowlist",
  "version": "0.6.1",
  "sha256": "50570fb79e7a8a61896c3cd88b36e4b5dc3418d826c51cefd7de0891ea31f7a7",
  "sha256_v1": "c6e14966b3935c9d3df64766851fbe631de6171e438c564e17fe3a4a4deb5e65",
  "keyword": "block",
  "word": "blocks",
  "says": "refuses a matched shell command before it runs. Blocks on an agent's file writes and at turn end",
  "description": "Gates MCP servers against .chock/mcp-allowlist.json, empty by default (name, launcher with exact args, or url host). Shell guard refuses `<agent> mcp add` and shell writes of MCP configs or the allowlist unless listed. Script gate (commit, tool use, turn end) reads 13 client configs: a server off the list, or with other command, args or url host, refuses; unpinned or shell launchers, http, literal credentials, old versions only warn. Misses: aliases, scripts, gitignored files, other clients.",
  "misses": "aliases, scripts, gitignored files, other clients.",
  "where": [
    "command",
    "write",
    "turn-end"
  ],
  "groups": [],
  "eval_cases": 116,
  "eval_executed": 116,
  "latest": {
    "version": "0.6.1",
    "date": "2026-10-26",
    "change": "Lint, no behaviour change: the printf argument count of the whole-text form is a named constant."
  },
  "agent_labels": {
    "claude-code": {
      "keyword": "block",
      "says": "refuses a matched shell command before it runs. Blocks on an agent's file writes and at turn end"
    },
    "cursor": {
      "keyword": "block",
      "says": "refuses a matched shell command before it runs. Blocks on an agent's file writes and at turn end"
    },
    "codex": {
      "keyword": "block",
      "says": "refuses a matched shell command before it runs. Blocks on an agent's file writes and at turn end. If the hook errors, the action goes through (not witnessed; the vendor's row is only partly live-run)"
    },
    "copilot": {
      "keyword": "block",
      "says": "refuses a matched shell command before it runs. Blocks at turn end only. It does not check a file write when it happens. If the hook errors, the action goes through (not witnessed; the vendor's row is only partly live-run)"
    },
    "devin": {
      "keyword": "block",
      "says": "refuses a matched shell command before it runs. Blocks at turn end only. It does not check a file write when it happens. If the hook errors, the action goes through (vendor docs only, not witnessed)"
    },
    "grok": {
      "keyword": "ungraded",
      "says": "Not graded yet for Grok"
    },
    "goose": {
      "keyword": "ungraded",
      "says": "Not graded yet for goose"
    },
    "antigravity": {
      "keyword": "ungraded",
      "says": "Not graded yet for Antigravity"
    },
    "openhands": {
      "keyword": "ungraded",
      "says": "Not graded yet for OpenHands"
    },
    "kimi-code": {
      "keyword": "ungraded",
      "says": "Not graded yet for Kimi Code"
    },
    "factory-droid": {
      "keyword": "ungraded",
      "says": "Not graded yet for Factory Droid"
    }
  },
  "source_url": "https://github.com/open-coder-ai/chock-catalog/tree/1e60d211c1bb767152c6ab0167932da06ab3a10f/base/verify-mcp-allowlist",
  "enforces": "enforced-at-commit",
  "examples": [
    {
      "word": "Refused",
      "prompt": "An agent writes .mcp.json naming a server that is not on the allowlist.",
      "command": "tee .mcp.json <<'EOF'\n{\"mcpServers\": {\"evil\": {\"command\": \"npx\", \"args\": [\"-y\", \"evil-mcp-server@1.0.0\"]}}}\nEOF"
    },
    {
      "word": "Allowed",
      "prompt": "An agent reads the MCP config and the allowlist.",
      "command": "cat .mcp.json .chock/mcp-allowlist.json"
    }
  ]
}
