Fail-closed Cedar policy gate + Ed25519 signed receipts for agent tool calls. Denies on any error.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent — or use 1-click editor setup below.
💡 Paste into ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
Fail-closed Cedar policy gate plus signed receipts for AI agent tool calls.
protect-mcp is a gate that sits in front of an AI agent's tool calls. It evaluates
each call against a Cedar policy (the same language
AWS uses for IAM), blocks what breaks the rules before it runs, and signs an
offline-verifiable Ed25519 receipt of every decision. It runs locally, sends no
telemetry of your decisions anywhere, and is MIT licensed.
would_deny: true, so a failure is never silent.serve --enforce and doctor run a startup
self-test and refuse to arm the gate unless they can show that a known-forbidden
action is actually denied. A gate that cannot prove it denies does not start.@veritasacta/verify.
No vendor trust required: the math does not care who runs it.For Claude Desktop, run a dry-run config patch first, then apply it:
The dashboard binds to 127.0.0.1, reads only local log/receipt files, and does
not upload anything. Use npx protect-mcp connect only if you explicitly want a
hosted ScopeBlind dashboard.
If you would rather call the gate as tools than wire the Claude Code hooks, run it as an MCP server:
It speaks MCP over stdio and exposes four read-only tools, the whole loop:
evaluate_action: decide a proposed tool call against an inline Cedar policy, fail-closed (any policy error is DENY). Returns { allowed, decision, reason, policy_digest }.sign_decision: turn a decision into an Ed25519 signed receipt (a denial signs a gateway_restraint, an allow a decision_receipt). Returns the receipt and its public key; generates an ephemeral key if you do not supply one.verify_receipt: verify a signed receipt offline against a public key. Returns { valid, error, type, kid, issuer }.self_test: prove it, no inputs. A known-forbidden action is denied, then a signed receipt round-trips and a tampered copy fails.Point any MCP host at it, for example Claude Desktop:
Receipts are byte-compatible with the ones the gate signs at runtime, so a
receipt minted here verifies with @veritasacta/verify
and the browser verifier just the same.
protect-mcp dashboard is the operator view for moving from visibility to
enforcement:
Require approval,
Block, or Observe. Restart the wrapper after reviewing changes.For live desktop fallback approvals, start the dashboard with the local gateway approval endpoint and nonce printed by the wrapper:
Approve forwards to the live local gateway when those flags are present.
Deny, Edit, and Take over are recorded locally as approval-resolution
records; use them as the operator instruction and rerun the tool when needed.
Local self-signed receipts stay free and offline-verifiable. The paid boundary is independent evidence that ScopeBlind saw a receipt digest at a time, under an org identity, without receiving the raw prompt, tool payload, output, private key, or raw receipt.
The local preview is deliberately labeled local-preview-not-independent.
Hosted mode anchors only receipt hashes, request ids, org public keys, and
billing metadata. It does not upload raw receipts or sensitive context.
protect-mcp killer-demo generates a complete three-minute sales/demo pack:
It creates mock filesystem, GitHub, email, and PMS activity; shows risky calls in shadow mode; applies a policy pack; requires approval for a sensitive PMS booking; executes through the gateway; writes a signed receipt; proves the original receipt verifies; proves a tampered receipt fails; and creates a selective disclosure package that hides sensitive context while showing the minimum proof.
Open the generated DEMO-RUNBOOK.md first. Then run the printed dashboard
command to walk a customer through the exact sequence.
Commitment-mode receipts can carry a committed_fields_root instead of exposing
every field in cleartext. Later, the holder can disclose selected fields only:
The verifier checks the parent receipt hash, Ed25519 signature, commitment root, and each disclosed field's Merkle proof. It then explains which fields were disclosed and which committed fields remain hidden. This is salted commitment disclosure, not full zero-knowledge, but it makes the privacy claim concrete: auditors can verify selected facts without receiving the full tool payload or sensitive desk context.
You can prove a CLAIM over your record without revealing it. Mint a signed, position-blind attestation over the whole record that discloses only per-decision categories (a receipt digest, the verdict, capability tags), never your tool inputs, outputs, or data:
Anyone verifies it offline, seeing only the categories, never the content:
The verifier recomputes a Merkle root over the disclosed set and recomputes the
predicate independently, so the issuer cannot lie about the claim given the
disclosure. Add --anchor to record the claim's digest in the public,
append-only ScopeBlind transparency log, so a counterparty who does not trust you
can confirm the disclosed set is complete and was not quietly re-cut (only the
hash is sent; the record stays local):
This is an accountable, position-blind attestation, not full zero-knowledge: it reveals the shape, not the content.
Watch the two-minute film at legate.scopeblind.com/record, then replay it against your own copy:
Drop the generated demo-tampered.jsonl into the record page to watch a
post-signing edit get caught. sample refuses to touch an existing record, so
run it in an empty folder. When you are ready for the real thing, wire the gate
below and the same commands run against your agent's own record.
One-shot evaluation, the way a PreToolUse hook calls it. Exit code 2 means deny (the tool is blocked); exit 0 means allow:
A missing or unloadable policy denies (exit 2) unless you explicitly pass
--fail-on-missing-policy false.
protect-mcp init-hooks writes a .claude/settings.json for you. To wire the
gate by hand, the two verbs you need are evaluate (PreToolUse, blocks on exit 2)
and sign (PostToolUse, records a receipt). Pin the version so a Claude Code
session always runs the gate you tested:
evaluate exits 2 on deny so Claude Code blocks the tool call, and 0 on allow.
sign is best-effort: it appends an Ed25519-signed receipt when a key is
configured, and if no signer is available it records an honest unsigned line
("signed": false) rather than failing the tool.
The same fail-closed gate runs as a tool hook in any agent that supports them. Add
--format <host> so the verb reads that host's hook payload from stdin and denies
in its contract:
Pair each with sign --format <host> on the post-tool event for receipts. The
important case is Hermes, which ignores hook exit codes and reads the verdict
from stdout, so --format hermes denies via {"decision":"block"} rather than
exit 2 (a raw exit-2 would silently fail open there). Without --format, the
verbs read --tool/--input flags exactly as in the Claude Code section above.
Cedar policies live in a directory you point at with --cedar. A forbid rule
denies, a permit rule allows. To match against a value in the tool input, use
the .contains() idiom:
Hazard: do NOT write
context.command in ["rm", "dd"]to match a string against a list.inis for entity hierarchies, not string membership. Cedar treats the expression as a type error and silently discards the wholeforbidrule, which (under a fail-open gate) leaves a residualpermitstanding. This is the exact defect behind the advisory below. Use[...].contains(context.command)instead. From 0.7.0 the gate denies on that error rather than permitting, and a CI tripwire test fails the build if the pattern is reintroduced into a shipped policy. See GHSA-hm46-7j72-rpv9.
Most teams should not write Cedar from scratch on day one. Install a starter pack, run in shadow mode, inspect receipts, then tighten or enforce:
Built-in packs:
filesystem-safe: destructive file actions and secret-like path reads.git-safe: force pushes, hard resets, destructive cleanup, repo deletion.email-safe: allow drafting, block unattended sends.database-safe: read-oriented DB posture, block write/admin SQL.cloud-spend-safe: obvious cloud spend creation and infrastructure destruction.secrets-safe: common file, env, shell, and cloud secret exfiltration.finance-mandate-safe: restricted-list and concentration breaches in booking flows.Receipts are signed and verifiable offline by anyone with the public key. No network, no vendor, no trust in ScopeBlind:
npx protect-mcp bundle --output audit.json exports a self-contained,
offline-verifiable audit bundle of your receipts plus the public signing key.
protect-mcp 0.7.0 fails closed by design. On any policy-evaluation error, a
missing engine, or a policy that errored at evaluation, the decision is DENY,
not allow. serve --enforce and doctor run a boot self-test that proves the
gate denies a known-forbidden vector before it is trusted, and refuse to arm if
it cannot.
Affected versions: 0.5.x and 0.6.x. Those lines fail open (they return ALLOW
on evaluation error) and do not evaluate Cedar correctly against the pinned
engine, so a forbid rule could fail to block. Upgrade to >= 0.7.0.
Details and remediation: GHSA-hm46-7j72-rpv9. To report a vulnerability, see SECURITY.md.
| Command | Description |
|---|---|
serve | Start the HTTP hook server for Claude Code (port 9377). --enforce runs the restraint self-test first; --cedar <dir> and --policy <path> select the policy. |
init | Generate an Ed25519 keypair (keys/gateway.json), a config template, and a sample policy. |
sample | Seed a clearly-labeled sample record (8 decisions: one blocked call, two payments; kid sample-demo) plus a tampered copy, so record, claim, verify-claim, and anchor-record are replayable from scratch before wiring an agent. Refuses to touch an existing record; --force overrides. |
policy | See and change the Cedar policy from the terminal: policy list (permit / forbid / default-deny per tool, with how often the gate allowed or denied it), policy show, policy allow <tool>, policy deny <tool>, policy path. A running serve hot-reloads on the change. |
wrap | Print a protected MCP command or patch Claude Desktop MCP servers. Dry-run by default; use --write to update Claude Desktop config. |
dashboard | Start a local-only dashboard on 127.0.0.1 showing tool inventory, risk, policy coverage, exact-action approvals, receipt chains, and audit export. |
recommend | Draft a reviewable JSON policy from observed local calls. Dry-run by default; use --write to create protect-mcp.recommended.json. |
registry | Create an org identity, anchor receipt digests, and write a static verifier page. Hosted mode uploads digests only. |
record | Open a local, searchable viewer over your receipts (--live streams as the agent runs): Ed25519 signatures verified in your browser against your gateway key, capability tags, a provenance tree, and one-click signed export. All local, nothing uploaded. |
claim | Mint a signed, position-blind attestation of a predicate over the record (--no <cap> incl. --no payment, --only <c1,c2>, --no-verdict <verdict>, --count <verdict>, --payment-under <cap>), disclosing only decision categories. Add --anchor to record the claim digest in the public transparency log; enrolled keys anchor as a named org. |
anchor-record | Checkpoint the record's Merkle root + count + time range into the public log (heartbeat-friendly: skips when unchanged). A later claim whose commitment matches an anchored checkpoint is provably over the complete record as of that checkpoint. |
verify-claim | Verify a claim pack offline: signature, recomputed Merkle root, independently recomputed predicate, and the anchor sidecar when present (binds the anchored envelope to this exact claim, then confirms the public log holds it). --check-anchor requires the anchor; --offline skips the log hop. |
killer-demo | Generate a complete shadow-mode to policy to approval to signed-receipt demo pack. |
verify-disclosure | Verify a scopeblind.selective_disclosure.v0 package and explain disclosed versus hidden fields. |
policy-packs | List, inspect, and install starter Cedar policy packs. |
evaluate | Evaluate one tool call against a Cedar policy (PreToolUse gate). Exit 2 = deny (fail-closed), exit 0 = allow. |
sign | Sign one tool call into a receipt (PostToolUse). Best-effort: records an honest unsigned line if no key. |
simulate | Dry-run a policy against a recorded decision log to see what it would have blocked. |
demo | Start a built-in demo server wrapped with the gate, to see receipts instantly. |
doctor | Check your setup (keys, policies, Cedar engine, verifier) and run the restraint self-test. |
bundle | Export an offline-verifiable audit bundle of receipts plus the public key. |
report | Generate a compliance report (Markdown or JSON) from the decision log and receipts. |
Run npx protect-mcp --help for the full flag reference.
MIT licensed. Built by ScopeBlind.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/protect-mcp)<a href="https://allmcps.com/mcp/protect-mcp"><img src="https://allmcps.com/api/badge/protect-mcp?style=directory" alt="Protect Mcp on AllMCPs" /></a>