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.
A customer-service agent pulls records from Salesforce to do its job — names, accounts, PII. What stops it leaking sensitive data on a tool call it shouldn't make — 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.
Everything leads to step four — the moment you watch your own policy stop something it shouldn't allow.
One pip install — the runtime, that's it.
A few lines of Cedar — your rules, not ours.
Point one call at the runtime. Nothing else changes.
Fire a bad action. Watch the policy return 403.
Get a signed, verifiable record of what happened.
Copy each block. We've filled in every file for you — nothing to hand-author, nothing to hash. Follow along top to bottom.
Creates a project folder, an isolated Python environment, and installs the cmcp runtime — the enforcement engine. (The venv is why pip install won't get blocked on recent macOS.) No tool server needed — in Step 4 your policy blocks the call before it forwards, so salesforce.contacts is a placeholder for your real MCP server. Open source (MIT): github.com/agentrust-io/cmcp
mkdir -p cmcp-quickstart && cd cmcp-quickstart python3 -m venv venv && source venv/bin/activate pip install cmcp-runtime
Paste each block into the same Terminal 1, top to bottom — you're already inside cmcp-quickstart from Step 1. The cat > … EOF wrapper writes each file for you, no editor needed. Your policy (block 2) is what decides what's allowed.
mkdir -p policies 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
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
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
cmcp validate-config --config cmcp-config.yaml
Expect ✓ Config valid: cmcp-config.yaml. If you see an error instead, a block didn't paste cleanly — re-run that one.
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.
CMCP_DEV_MODE=1 cmcp start --config cmcp-config.yaml
In a second terminal, run cd cmcp-quickstart && source venv/bin/activate first (so cmcp is available here too), 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. Not blocked? You're likely in advisory mode — check the config says enforcing.
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" }
}
}'
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.
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 →
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
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.
This is the whole reason the page exists — tell us it worked, and whether it matters.
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.