Runnable demos for cMCP and TRACE. Three demos, ~4 minutes total.
pip install cmcp-runtime
cmcp-runtime includes all dependencies (starlette, uvicorn, cmcp-verify). All demos use CMCP_DEV_MODE=1 (software-only TEE, no hardware required). The local MCP server performs real filesystem operations on ./workspace/.
Set a bearer token (the cMCP Runtime requires one):
# bash
export CMCP_BEARER_TOKEN=demo-token# PowerShell
$env:CMCP_BEARER_TOKEN = "demo-token"Each demo has a run.py (works on any OS) and a run.sh (bash only). Server and cMCP Runtime logs are written to *.log files in the demo directory, not the terminal.
The agent calls three tools through the cMCP gateway. Cedar policy is enforced for every call. At session close, the gateway produces a signed TRACE claim carrying the policy bundle hash.
On real Intel TDX hardware, the policy bundle hash flows into RTMR[2] at startup. Here it appears in trace.policy.bundle_hash in the claim.
python demo-01-cmcp-in-action/run.py
What you see:
- cMCP starts, measures the policy bundle hash
write_file: Cedar allows it, real file written toworkspace/hello.txtread_file: Cedar allows it, reads the file backlist_dir: denied by Cedar policy (HTTP 403, error_code: POLICY_DENY)- TRACE claim shows
runtime.platform,runtime.measurement,policy.bundle_hash - Claim saved to
workspace/trace-claim.json(needed by demos 2 and 3)
The operator loads a different Cedar policy bundle (v1 vs v2). The claim's policy.bundle_hash changes. A verifier that pinned the v1 hash rejects v2 claims with POLICY_HASH_MISMATCH.
On real TDX hardware, the policy hash flows into RTMR[2] at startup -- the TEE measurement itself changes, not just a field in the claim.
Requires demo 1 to have run first (reads workspace/trace-claim.json).
python demo-02-policy-swap/run.py
What you see:
- v1 and v2 bundle hashes printed (visibly different SHA-256 values)
write_fileis DENIED under v2 policy (new Cedar forbid rule)cmcp verifyon the v1 claim with v2 hash -> POLICY_HASH_MISMATCHcmcp verifyon the v1 claim with v1 hash -> passes
The signed TRACE claim from demo-01 is verified with no gateway, no server, and no network call. Only cmcp_verify and the hashes embedded in the claim are used.
Requires demo 1 to have run first.
python demo-03-offline-trace/run.py
What you see:
- Claim fields printed:
runtime.platform,runtime.measurement,policy.bundle_hash - All cryptographic checks pass (schema, signature, policy hash, catalog hash, audit chain)
hardware_attestationis inunverified_fields(software-only mode -- on real TDX it would also be verified)- No connection made to any server
demos/
+-- README.md
+-- requirements.txt
+-- server/
| +-- server.py # Plain HTTP JSON-RPC 2.0 server: write_file, read_file, list_dir
| +-- requirements.txt
+-- workspace/ # Files written by demos (created at runtime)
+-- demo-01-cmcp-in-action/
| +-- cmcp-config.yaml
| +-- catalog.json # Approves write_file, read_file, list_dir
| +-- policies/ # Cedar: permit write_file+read_file, forbid list_dir
| +-- call.py # Demo agent: calls tools, closes session, saves claim
| +-- run.py # Cross-platform launcher (use this)
| +-- run.sh # bash-only launcher
+-- demo-02-policy-swap/
| +-- catalog.json
| +-- cmcp-config.yaml # Points to policies-v1/
| +-- cmcp-config-v2.yaml # Points to policies-v2/
| +-- policies-v1/ # Cedar: permit all
| +-- policies-v2/ # Cedar: deny write_file (hash differs from v1)
| +-- check_hash.py # Computes and compares bundle hashes
| +-- run.py # Cross-platform launcher (use this)
| +-- run.sh # bash-only launcher
+-- demo-03-offline-trace/
+-- verify.py # cmcp_verify.verify_trace_claim (no network)
+-- run.py # Cross-platform launcher (use this)
+-- run.sh # bash-only launcher
Agent (call.py)
|
v POST /mcp Authorization: Bearer <token>
[cMCP runtime :8443] <-- Cedar policy bundle (hash -> RTMR[2] on TDX)
|
v POST http://localhost:9001/mcp (JSON-RPC 2.0)
[server/server.py :9001] --> workspace/ (real file writes)
|
POST /sessions/{id}/close
|
v
TRACE claim (Ed25519 signed) --> workspace/trace-claim.json
|
v
cmcp_verify.verify_trace_claim() (no network, no operator trust)