protect-mcp

by scopeblind

Not rated
GitHub

About

Security gateway for MCP servers — per-tool policies, Ed25519-signed receipts, human approval gates, and Cedar WASM policy engine.

Details

Author
scopeblind
Categories
Developer Tools, Security, Infrastructure, API

Quickstart: install to first useful proof

# 1. Generate an Ed25519 keypair, config template, and sample policy. npx protect-mcp init # 2. Wrap any MCP server in shadow mode. Nothing is blocked yet; calls are logged. npx protect-mcp wrap -- node your-mcp-server.js # 3. Inspect the local-only dashboard: tool inventory, risk, approvals, receipts. npx protect-mcp dashboard --open # 4. Draft a reviewable policy from observed calls. npx protect-mcp recommend --write # 5. When reviewed, restart the wrapper in enforce mode with that policy. npx protect-mcp --policy protect-mcp.recommended.json --enforce -- node your-mcp-server.js

For Claude Desktop, run a dry-run config patch first, then apply it:

npx protect-mcp wrap --claude-desktop npx protect-mcp wrap --claude-desktop --write npx protect-mcp dashboard --open

The dashboard binds to127.0.0.1, reads only local log/receipt files, and does not upload anything. Usenpx protect-mcp connectonly 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 agateway_restraint, an allow adecision_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:

{ "mcpServers": { "protect-mcp": { "command": "npx", "args": ](https://www.npmjs.com/package/@veritasacta/verify)["-y", "protect-mcp", "mcp"] } } }

Receipts are byte-compatible with the ones the gate signs at runtime, so a receipt minted here verifies with[@veritasacta/verifyand the browser verifier just the same.

protect-mcp dashboardis the operator view for moving from visibility to enforcement:

- Tool inventory:every observed tool, call count, high/medium/low risk, and whether the active policy has an exact rule, a wildcard fallback, or no rule.
- Policy coverage:one-click local policy edits forRequire approval,Block, orObserve. Restart the wrapper after reviewing changes.
- Exact-action approval queue:the exact tool, action, destination, redacted payload preview, payload hash, policy basis, and reason capture before a human approves, denies, edits, or takes over.
- Receipt chain:request ids correlated with signed receipt hashes, so an audit reviewer can see which decisions have cryptographic proof.
- Audit export:downloads the offline-verifiable audit bundle when signed receipts exist. If only unsigned local logs exist, the dashboard explains that signing must be enabled first.

For live desktop fallback approvals, start the dashboard with the local gateway approval endpoint and nonce printed by the wrapper:

npx protect-mcp dashboard --open \ --approval-endpoint http://127.0.0.1:9876 \ --approval-nonce "$PROTECT_MCP_APPROVAL_NONCE"

Approveforwards to the live local gateway when those flags are present.Deny,Edit, andTake overare recorded locally as approval-resolution records; use them as the operator instruction and rerun the tool when needed.

Fail-closed Cedar policy gate plus signed receipts for AI agent tool calls.

protect-mcpis a gate that sits in front of an AI agent's tool calls. It evaluates each call against aCedarpolicy (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.

- Fail-closed by default.On any policy error, a missing engine, or an evaluation failure, the decision is DENY. The gate never silently allows. An observe mode exists for shadow rollout, but even there a call that would be blocked is flaggedwould_deny: true, so a failure is never silent.
- It proves its own restraint.serve --enforceanddoctorrun 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.
- Every decision is a receipt anyone can verify.Decisions are Ed25519-signed and verifiable offline with
@veritasacta/verify. No vendor trust required: the math does not care who runs it.

Quickstart: install to first useful proof

# 1. Generate an Ed25519 keypair, config template, and sample policy. npx protect-mcp init # 2. Wrap any MCP server in shadow mode. Nothing is blocked yet; calls are logged. npx protect-mcp wrap -- node your-mcp-server.js # 3. Inspect the local-only dashboard: tool inventory, risk, approvals, receipts. npx protect-mcp dashboard --open # 4. Draft a reviewable policy from observed calls. npx protect-mcp recommend --write # 5. When reviewed, restart the wrapper in enforce mode with that policy. npx protect-mcp --policy protect-mcp.recommended.json --enforce -- node your-mcp-server.js

For Claude Desktop, run a dry-run config patch first, then apply it:

npx protect-mcp wrap --claude-desktop npx protect-mcp wrap --claude-desktop --write npx protect-mcp dashboard --open

The dashboard binds to127.0.0.1, reads only local log/receipt files, and does not upload anything. Usenpx protect-mcp connectonly 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 agateway_restraint, an allow adecision_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:

{ "mcpServers": { "protect-mcp": { "command": "npx", "args": ["-y", "protect-mcp", "mcp"] } } }

Receipts are byte-compatible with the ones the gate signs at runtime, so a receipt minted here verifies with@veritasacta/verifyand the browser verifier just the same.

protect-mcp dashboardis the operator view for moving from visibility to enforcement:

- Tool inventory:every observed tool, call count, high/medium/low risk, and whether the active policy has an exact rule, a wildcard fallback, or no rule.
- Policy coverage:one-click local policy edits forRequire approval,Block, orObserve. Restart the wrapper after reviewing changes.
- Exact-action approval queue:the exact tool, action, destination, redacted payload preview, payload hash, policy basis, and reason capture before a human approves, denies, edits, or takes over.
- Receipt chain:request ids correlated with signed receipt hashes, so an audit reviewer can see which decisions have cryptographic proof.
- Audit export:downloads the offline-verifiable audit bundle when signed receipts exist. If only unsigned local logs exist, the dashboard explains that signing must be enabled first.

For live desktop fallback approvals, start the dashboard with the local gateway approval endpoint and nonce printed by the wrapper:

npx protect-mcp dashboard --open \ --approval-endpoint http://127.0.0.1:9876 \ --approval-nonce "$PROTECT_MCP_APPROVAL_NONCE"

Approveforwards to the live local gateway when those flags are present.Deny,Edit, andTake overare recorded locally as approval-resolution records; use them as the operator instruction and rerun the tool when needed.

Paid Boundary MVP: digest anchoring, not data upload

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.

# Create or refresh a local org identity and public-key directory. npx protect-mcp registry init --org "Meridian Global Macro" --billing-account acct_meridian # Local preview: writes a digest registry and shareable static verifier page. npx protect-mcp registry anchor # Hosted mode: uploads receipt digests only for independent anchoring. SCOPEBLIND_TOKEN=... npx protect-mcp registry anchor \ --hosted \ --endpoint https://api.scopeblind.com \ --verifier-base https://legate.scopeblind.com

The local preview is deliberately labeledlocal-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-demogenerates a complete three-minute sales/demo pack:

npx protect-mcp killer-demo --dir ./scopeblind-demo

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 generatedDEMO-RUNBOOK.mdfirst. Then run the printed dashboard command to walk a customer through the exact sequence.

Commitment-mode receipts can carry acommitted_fields_rootinstead of exposing every field in cleartext. Later, the holder can disclose selected fields only:

npx protect-mcp verify-disclosure \ --receipt ./receipts/selective-disclosure.receipt.json \ --disclosure ./receipts/selective-disclosure.tool-only.json

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.

Prove a claim over the record (position-blind attestations)

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:

# "No action reached the network across the record": npx protect-mcp claim --no net.egress # other predicates: # --only fs.read,fs.write all actions were confined to these capabilities # --no-verdict blocked no action was blocked # --count blocked how many were blocked

Anyone verifies it offline, seeing only the categories, never the content:

npx protect-mcp verify-claim claim-<id>.json

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--anchorto 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):

npx protect-mcp claim --no net.egress --anchor

This is an accountable, position-blind attestation, not full zero-knowledge: it reveals the shape, not the content.

Try it in 60 seconds (no agent required)

Watch the two-minute film atlegate.scopeblind.com/record, then replay it against your own copy:

npx protect-mcp sample # seed a labeled sample record (8 decisions: 1 blocked, 2 payments) npx protect-mcp record # open it: signatures verified in your browser npx protect-mcp claim --payment-under 100 --anchor --output payments-under-100.json npx protect-mcp verify-claim payments-under-100.json npx protect-mcp anchor-record

Drop the generateddemo-tampered.jsonlinto the record page to watch a post-signing edit get caught.samplerefuses 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.

# Generate hook config and a sample Cedar policy. npx protect-mcp init-hooks # Serve the Claude Code hook gate in enforce mode. It runs a restraint self-test # first and refuses to start if it cannot prove it denies a forbidden vector. npx protect-mcp serve --enforce --cedar ./cedar

One-shot evaluation, the way a PreToolUse hook calls it. Exit code 2 means deny (the tool is blocked); exit 0 means allow:

npx protect-mcp evaluate --cedar ./cedar --tool Bash --input '{"command":"rm"}' echo $? # 2 -> denied, fail-closed npx protect-mcp evaluate --cedar ./cedar --tool Read --input '{"path":"README.md"}' echo $? # 0 -> allowed

A missing or unloadable policy denies (exit 2) unless you explicitly pass--fail-on-missing-policy false.

protect-mcp init-hookswrites a.claude/settings.jsonfor you. To wire the gate by hand, the two verbs you need areevaluate(PreToolUse, blocks on exit 2) andsign(PostToolUse, records a receipt). Pin the version so a Claude Code session always runs the gate you tested:

{ "hooks": { "PreToolUse": [ { "matcher": "", "hooks": [ { "type": "command", "command": "npx protect-mcp@0.9.1 evaluate --cedar ./cedar --tool \"$TOOL_NAME\" --input \"$TOOL_INPUT\"" } ] } ], "PostToolUse": [ { "matcher": "", "hooks": [ { "type": "command", "command": "npx protect-mcp@0.9.1 sign --tool \"$TOOL_NAME\" --receipts ./receipts --key ./keys/gateway.json" } ] } ] } }

evaluateexits 2 on deny so Claude Code blocks the tool call, and 0 on allow.signis 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.

Use it in other agents (Codex, Cursor, Gemini, Hermes)

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:

# the PreToolUse / before-tool command for each host npx -y protect-mcp@latest evaluate --format codex --cedar ./cedar # OpenAI Codex npx -y protect-mcp@latest evaluate --format gemini --cedar ./cedar # Gemini CLI BeforeTool npx -y protect-mcp@latest evaluate --format cursor --cedar ./cedar # Cursor beforeShellExecution npx -y protect-mcp@latest evaluate --format hermes --cedar ./cedar # Hermes pre_tool_call

Pair each withsign --format <host>on the post-tool event for receipts. The important case isHermes, which ignores hook exit codes and reads the verdict from stdout, so--format hermesdenies via{"decision":"block"}rather than exit 2 (a raw exit-2 would silently fail open there). Without--format, the verbs read--tool/--inputflags exactly as in the Claude Code section above.

Cedar policies live in a directory you point at with--cedar. Aforbidrule denies, apermitrule allows. To match against a value in the tool input, use the.contains()idiom:

// Allow read-only tools. permit( principal, action == Action::"MCP::Tool::call", resource == Tool::"Read" ); // Deny dangerous shell commands by matching the command against a list. forbid( principal, action == Action::"MCP::Tool::call", resource == Tool::"Bash" ) when { ["rm", "dd", "mkfs"].contains(context.command) }; // Block destructive tools outright. forbid( principal, action == Action::"MCP::Tool::call", resource == Tool::"delete_file" );

Hazard:do NOT writecontext.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. SeeGHSA-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:

npx protect-mcp policy-packs list npx protect-mcp policy-packs show secrets-safe npx protect-mcp policy-packs install filesystem-safe --dir ./cedar npx protect-mcp policy-packs install all --dir ./cedar npx protect-mcp serve --cedar ./cedar

- 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 @veritasacta/verify ./receipts/receipts.jsonl --format jsonl # Exit 0 = valid, non-zero = tampered or malformed

npx protect-mcp bundle --output audit.jsonexports a self-contained, offline-verifiable audit bundle of your receipts plus the public signing key.

protect-mcp0.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 --enforceanddoctorrun 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 aforbidrule could fail to block.Upgrade to >= 0.7.0.

Details and remediation:GHSA-hm46-7j72-rpv9. To report a vulnerability, seeSECURITY.md.

Runnpx protect-mcp --helpfor the full flag reference.

- Protocol (IETF):draft-farley-acta-signed-receipts
-
CHANGELOG
-
npm
-
scopeblind.com

This is a web browser that enables your coding agent, such as Claude Code, to visit websites on your behalf and assist you in identifying bugs or creating UI test cases.

Official managed MCP server for the Cycode platform. Exposes projects, violations, compliance frameworks, audit logs, brokers, SBOM, and more via OAuth-authenticated remote access — no local install required.

A feature-rich gateway and proxy that federates MCP and REST services, unifying discovery, authentication, rate-limiting, and observability into a single endpoint for AI clients.

Paid remote MCP for OAuth scope risk inspection, approval routing, consent receipts, server policy validation, and scope audit exports.

Security testing MCP server with 51 tools for penetration testing, network forensics, memory analysis, and vulnerability assessment.

Provides SD Elements API integration for security and compliance management.

AI Agent Supply Chain Security - Intercepts and validates every package installation, git clone, and script download triggered by AI coding agents before it executes.

Secure every MCP server with one governed gateway. Give each AI agent its own scoped MCP access, contain credentials at the gateway, and audit every MCP tool call without wiring agents directly to each server.

MCP server for ESET Connect API - 102 tools, RO/RW mode, stdio+HTTP, OAuth2

Enables AI assistants to interact with Fleet Device Management for device management, security monitoring, and compliance enforcement.

Securely manage secrets and policies in HashiCorp Vault through an MCP interface.

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.