Agent Control for MCP · Open Quickstart

Set policy on your AI agent. Watch it block a bad action. In about 10 minutes.

Install the runtime, write one policy, and watch it stop a real data leak before it happens — then walk away with a signed, verifiable record of exactly what it did. Runs on your laptop. No sales call.

▶ Preview · simulated — a 30-second look at the block
agent → runtime
$ agent calls salesforce.contacts
  session_max_sensitivity: "pii"
< HTTP/1.1 403 Forbidden
< "message": "Request denied by policy"
< "error_code": "POLICY_DENY"
✓ Blocked before it reached Salesforce
< 0.5ms governance overhead per tool call

A customer-service agent pulls records with names, accounts and PII from Salesforce to do its job. What stops it from leaking sensitive data on a tool? And, could you prove to a regulator it didn't?

An agent calls a tool. Your policy engine says allow. The call goes through. None of that proves the engine itself wasn't tampered with, or that your audit log reflects what actually happened.


Agent Control runs the policy where the agent can't reach it — every tool call your agent routes through the runtime is checked, enforced, and signed into a tamper-evident record. This quickstart lets you feel that in half an hour, on your laptop.

Five quick steps from install to a blocked leak

Everything leads to step four — the moment you watch your own policy stop something it shouldn't allow.

01

Install

One pip install. The demo tool ships with it.

02

Write your policy

A few lines of Cedar — your rules, not ours.

03

Wire it in

Point one call at the runtime. Nothing else changes.

THE POINT
04

Watch it block

Fire a bad action. Watch the policy return 403.

05

Prove it

Get a signed, verifiable record of what happened.

The quickstart

Copy each block. We've filled in every file for you — nothing to hand-author, nothing to hash. Follow along top to bottom.

Before you startPython 3.11+ · pip · macOS or Linux · two terminal windows · ~10 minutes · no special hardware.
1

Install the runtime

Installs the cmcp runtime and the demo Salesforce tool. The mock tool is bundled — you won't hit a missing-server error. Open source (MIT): github.com/agentrust-io/cmcp

Terminal
pip install cmcp-runtime
2

Drop in the config & your policy

Paste each block into your terminal, top to bottom. The cat > … EOF wrapper writes each file for you — no editor needed. Everything lands in a new cmcp-quickstart/ folder. Your policy (block 2) is what decides what's allowed.

1 · Creates your folder + cmcp-config.yaml
mkdir -p cmcp-quickstart/policies && cd cmcp-quickstart
cat > cmcp-config.yaml << 'EOF'
attestation:
  provider: auto
  enforcement_mode: enforcing   # block, don't just log
policy_bundle_path: ./policies/
catalog_path: ./catalog.json
EOF
2 · Creates your policy bundle — your rules
cat > policies/manifest.json << 'EOF'
{ "version": "0.1.0", "authored_at": "2026-06-05T00:00:00Z",
  "author_identity": "quickstart@opaque.co", "commit_sha": "quickstart-demo" }
EOF

cat > policies/agent.cedar << 'EOF'
// Rule 1 — allow the demo-agent workflow to call tools
permit ( principal, action == cMCP::Action::"call_tool", resource )
when { context.workflow_id == "demo-agent" };

// Rule 2 — block salesforce.contacts once the session has touched PII
forbid ( principal, action == cMCP::Action::"call_tool",
         resource == cMCP::Resource::"salesforce.contacts" )
when { context.session_max_sensitivity == "pii" };

// Rule 3 — allow everything else
permit ( principal, action == cMCP::Action::"call_tool", resource );
EOF

cat > policies/schema.cedarschema << 'EOF'
{"cMCP":{"entityTypes":{"Principal":{"memberOfTypes":[],"shape":{"type":"Record","attributes":{"session_id":{"type":"String","required":true},"workflow_id":{"type":"String","required":true}}}},"Resource":{"memberOfTypes":[],"shape":{"type":"Record","attributes":{"tool_name":{"type":"String","required":true}}}}},"actions":{"call_tool":{"appliesTo":{"principalTypes":["cMCP::Principal"],"resourceTypes":["cMCP::Resource"],"context":{"type":"Record","attributes":{"session_max_sensitivity":{"type":"String","required":true},"workflow_id":{"type":"String","required":true}}}}}}}}
EOF
3 · Creates catalog.json — the approved tool (hash pre-computed for you)
cat > catalog.json << 'EOF'
[
  {
    "tool_name": "salesforce.contacts",
    "server": {
      "display_name": "Salesforce Contacts MCP Server (mock)",
      "url": "http://localhost:9001/mcp",
      "tls_fingerprint": "SHA256:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
      "transport": "http-sse",
      "rotation_mode": "key-pinned"
    },
    "approved_definition": {
      "description": "Query Salesforce contacts by account name or contact ID.",
      "input_schema": {
        "type": "object",
        "required": ["query"],
        "properties": {
          "query": {"type": "string", "description": "Account name or contact ID"},
          "max_records": {"type": "integer", "default": 50}
        }
      },
      "output_schema": {
        "type": "object",
        "properties": { "contacts": {"type": "array"}, "total_count": {"type": "integer"} }
      }
    },
    "definition_hash": "sha256:b42ecf14612f23456b5b0794864a00288d4038ac444cedb87fc214cefee89e35",
    "compliance_domain": "pii",
    "requires_baa": false,
    "sensitivity_level": "pii",
    "added_at": "2026-06-05T00:00:00Z",
    "approved_by": "quickstart@opaque.co"
  }
]
EOF
3

Start the runtime

Run this in the same terminal where you just created the files (you're inside cmcp-quickstart). It keeps running and won't return a prompt — that's normal, and the startup notices are expected, not errors. Leave it open and open a second terminal for the next step.

Terminal 1 — leave running
CMCP_DEV_MODE=1 cmcp start --config cmcp-config.yaml
4

Fire a bad action — watch it get blocked

In a second terminal, run cd cmcp-quickstart first, then paste this. It's your support agent trying to pull a customer's Salesforce record after the session already handled PII — exactly what your rule forbids. Watch your runtime return a 403 before it ever reaches Salesforce.

Terminal 2 — you, playing the agent
curl -X POST http://localhost:8443/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0", "id": 2, "method": "tools/call",
    "params": {
      "name": "salesforce.contacts",
      "arguments": { "query": "Acme Corp" },
      "_cmcp": { "session_id": "demo-session-001", "workflow_id": "demo-agent", "session_max_sensitivity": "pii" }
    }
  }'
WHAT YOU'LL SEE — 403 FORBIDDEN

Your policy stops a PII record from leaving on a tool call — before it reaches Salesforce, decided by the rule you wrote, enforced where the agent can't tamper with it. That's the barrier most teams can't cross today: shipping an agent you can actually prove is governed.

5

Walk away with proof

Closing the session mints a signed TRACE claim — a tamper-evident record of which tools ran and which policy decided each call. Verify it yourself; you don't have to trust us. See the full TRACE claim schema →

Terminal 2 — finalize the session, then verify
SID=$(curl -s "http://localhost:8443/audit/export?session_id=demo-session-001" \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['entries'][0]['session_id'])")
curl -s -X POST "http://localhost:8443/sessions/$SID/close" | python3 -m json.tool > claim.json
cmcp verify claim.json
schemaPASS ✓
signaturePASS ✓
policy_bundle.hashPASS ✓
tool_catalog.hashPASS ✓
attestation_freshnessPASS ✓
audit_chainPASS ✓
hardware_attestationFAIL — software-only (expected in dev)
RESULTpartially_verified

Every cryptographic check passes — the one FAIL is hardware attestation, which dev mode can't provide. Run it on Confidential Core — OPAQUE's hardware layer — and that check passes too: the result flips to verified, the version you hand a regulator.

Stuck? Every block above is copy-paste — the file blocks write themselves via cat > … EOF, the rest are commands. Keep your first terminal (the runtime) running while you work in the second. Full walkthrough & troubleshooting: cMCP quickstart · debugging guide.

You did it

Two questions before you go.

Tell us if it worked, and whether it matters.

Load the claim.json you just verified, or paste its contents below — this is your enforcement evidence.
Or from your terminal: cat claim.json | pbcopy (macOS), then paste above.
The one question we actually need answered.
Thank you — that's the loop.

You installed it, wrote a policy, watched it block a bad action, and proved it. That's exactly the barrier we're trying to remove. We'll be in touch if you left an email.