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 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.
Everything leads to step four — the moment you watch your own policy stop something it shouldn't allow.
One pip install. The demo tool ships with 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.
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
pip install cmcp-runtime
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.
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
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
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 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.
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.
Tell us if 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.