Enterprise security gateway for MCP servers and Claude Code hooks. Signed receipts, Cedar policies, and swarm-aware audit trails.
Two commands. Every tool call is receipted.
# 1. Generate hooks, keys, Cedar policy, and /verify-receipt skill
npx protect-mcp init-hooks
# 2. Start the hook server
npx protect-mcp serveOpen Claude Code in the same project. Every tool call is now intercepted, evaluated, and signed.
| File | Purpose |
|---|---|
.claude/settings.json |
Hook config (PreToolUse, PostToolUse, + 9 lifecycle events) |
keys/gateway.json |
Ed25519 signing keypair (auto-gitignored) |
policies/agent.cedar |
Starter Cedar policy — customize to your needs |
protect-mcp.json |
JSON policy with signing + rate limits |
.claude/skills/verify-receipt/SKILL.md |
/verify-receipt skill for Claude Code |
Claude Code → POST /hook → protect-mcp (Cedar + sign) → response
↓
.protect-mcp-log.jsonl
.protect-mcp-receipts.jsonl
- PreToolUse: synchronous Cedar policy check → deny blocks the tool
- PostToolUse: async receipt signing → zero latency impact
- deny is architecturally final — it cannot be overridden by the model or other hooks
| Method | Path | Description |
|---|---|---|
| POST | /hook |
Claude Code hook endpoint |
| GET | /health |
Server status, policy info, signer info |
| GET | /receipts |
Recent signed receipts |
| GET | /receipts/latest |
Most recent receipt |
| GET | /suggestions |
Auto-generated Cedar policy fix suggestions |
| GET | /alerts |
Config tamper detection alerts |
# Inside Claude Code:
/verify-receipt
# From terminal:
curl http://127.0.0.1:9377/receipts/latest | jq .
npx protect-mcp receipts
# Check policy suggestions:
curl http://127.0.0.1:9377/suggestions | jq .Wrap any stdio MCP server as a transparent proxy:
# Shadow mode — log every tool call, enforce nothing
npx protect-mcp -- node my-server.js
# Enforce mode with policy
npx protect-mcp --policy protect-mcp.json --enforce -- node my-server.js
# Generate keys + config template
npx protect-mcp initprotect-mcp evaluates every tool call against a policy (JSON, Cedar, or external PDP), signs the decision as an Ed25519 receipt, and logs the result.
Two integration modes:
| Mode | Transport | Use Case |
|---|---|---|
| Hook Server | HTTP (npx protect-mcp serve) |
Claude Code, agent swarms |
| Stdio Proxy | stdin/stdout (npx protect-mcp -- ...) |
Claude Desktop, Cursor, any MCP client |
Three policy engines:
| Engine | Config | Notes |
|---|---|---|
| JSON | --policy policy.json |
Simple per-tool rules |
| Cedar | --cedar ./policies/ |
Local WASM evaluation via @cedar-policy/cedar-wasm |
| External PDP | policy_engine: "external" |
OPA, Cerbos, or any HTTP PDP |
In multi-agent sessions, protect-mcp automatically tracks the swarm topology.
11 hook events handled:
| Event | Type | Description |
|---|---|---|
PreToolUse |
Sync | Cedar/policy evaluation before tool execution |
PostToolUse |
Async | Receipt signing after tool execution |
SubagentStart / SubagentStop |
Lifecycle | Worker agent spawn/completion |
TaskCreated / TaskCompleted |
Lifecycle | Coordinator task assignment |
SessionStart / SessionEnd |
Lifecycle | Session lifecycle with sandbox detection |
TeammateIdle |
Lifecycle | Agent utilization monitoring |
ConfigChange |
Security | Tamper detection for .claude/settings.json |
Stop |
Lifecycle | Finalization + policy suggestion summary |
Each receipt includes:
swarm.agent_id,swarm.agent_type,swarm.team_nametiming.tool_duration_ms,timing.hook_latency_mspayload_digest(SHA-256 hash for payloads >1KB)deny_iteration(retry count after denial)sandbox_state(enabled/disabled/unavailable)- OpenTelemetry
otel_trace_idandotel_span_id
{
"default_tier": "unknown",
"tools": {
"dangerous_tool": { "block": true },
"admin_tool": { "min_tier": "signed-known", "rate_limit": "5/hour" },
"read_tool": { "require": "any", "rate_limit": "100/hour" },
"*": { "rate_limit": "500/hour" }
},
"signing": {
"key_path": "./keys/gateway.json",
"issuer": "protect-mcp",
"enabled": true
}
}Cedar deny decisions are authoritative — they cannot be overridden.
// Allow read-only tools
permit(
principal,
action == Action::"MCP::Tool::call",
resource == Tool::"Read"
);
// Block destructive tools
forbid(
principal,
action == Action::"MCP::Tool::call",
resource == Tool::"delete_file"
);
When a tool is denied, protect-mcp auto-suggests the minimal Cedar permit() rule via GET /suggestions.
Each prevents a real attack:
| Policy | Incident | OWASP |
|---|---|---|
clinejection.json |
CVE-2025-6514: MCP OAuth proxy hijack (437K environments) | A01, A03 |
terraform-destroy.json |
Autonomous Terraform agent destroys production | A05, A06 |
github-mcp-hijack.json |
Prompt injection via crafted GitHub issue | A01, A02, A03 |
data-exfiltration.json |
Agent data theft via outbound tool abuse | A02, A04 |
financial-safe.json |
Unauthorized financial transaction | A05, A06 |
Cedar equivalents available in policies/cedar/.
{
"mcpServers": {
"my-protected-server": {
"command": "npx",
"args": [
"-y", "protect-mcp",
"--policy", "/path/to/protect-mcp.json",
"--enforce",
"--", "node", "my-server.js"
]
}
}
}Same pattern — replace the server command with protect-mcp wrapping it.
Commands:
serve Start HTTP hook server for Claude Code (port 9377)
init-hooks Generate Claude Code hook config + skill + sample Cedar policy
quickstart Zero-config onboarding: init + demo + show receipts
init Generate Ed25519 keypair + config template
demo Start a demo server wrapped with protect-mcp
doctor Check your setup: keys, policies, verifier, connectivity
trace <id> Visualize the receipt DAG from a given receipt_id
status Show tool call statistics from the decision log
digest Generate a human-readable summary of agent activity
receipts Show recent persisted signed receipts
bundle Export an offline-verifiable audit bundle
simulate Dry-run a policy against recorded tool calls
report Generate a compliance report from an audit bundle
Options:
--policy <path> Policy/config JSON file
--cedar <dir> Cedar policy directory
--enforce Enable enforcement mode (default: shadow)
--port <port> HTTP server port (default: 9377 for serve)
--verbose Enable debug logging
Every tool call emits structured JSON to stderr:
[PROTECT_MCP] {"v":2,"tool":"read_file","decision":"allow","reason_code":"cedar_allow","policy_digest":"a1b2c3...","mode":"enforce","hook_event":"PreToolUse","timing":{"hook_latency_ms":1},"otel_trace_id":"..."}When signing is configured, a signed receipt is persisted to .protect-mcp-receipts.jsonl.
npx protect-mcp bundle --output audit.jsonSelf-contained offline-verifiable bundle with receipts + signing keys. Verify with npx @veritasacta/verify.
- IETF Internet-Draft: draft-farley-acta-signed-receipts-01 — Signed Decision Receipts for Machine-to-Machine Access Control
- Patent Status: 4 Australian provisional patents pending (2025-2026) covering decision receipts with configurable disclosure, tool-calling gateway, agent manifests, and portable identity
- Verification: Apache-2.0 —
npx @veritasacta/verify --self-test - Microsoft AGT Integration: PR #667 — Cedar policy bridge for Agent Governance Toolkit
MIT — free to use, modify, distribute, and build upon without restriction.
scopeblind.com · npm · GitHub · IETF Draft