Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# cMCP: Confidential MCP Runtime

### Enforce MCP tool policy where it cannot be tampered with
### Enforce MCP tool policy inside a TEE, where the agent it governs cannot reach it

<p align="center">
<a href="https://agentrust-io.github.io/cmcp">
Expand All @@ -24,7 +24,7 @@

[![CI](https://github.com/agentrust-io/cmcp/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/agentrust-io/cmcp/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE) [![PyPI](https://img.shields.io/pypi/v/cmcp-runtime)](https://pypi.org/project/cmcp-runtime/) [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/agentrust-io/cmcp/badge)](https://scorecard.dev/viewer/?uri=github.com/agentrust-io/cmcp) [![Discord](https://img.shields.io/badge/Discord-Join-5865F2?logo=discord&logoColor=white&style=flat)](https://discord.gg/grgzFEHgkj)

> **Developer Preview** - launching at Confidential Computing Summit, June 23 2026. May have breaking changes before v1.0.
> **Developer Preview** - launched at the Confidential Computing Summit, June 23 2026. May have breaking changes before v1.0. See [STATUS.md](STATUS.md) for exactly what ships today versus what is on the roadmap.

**cMCP (Confidential MCP Runtime) is the secure, confidential way to run MCP: an open-source gateway that enforces MCP tool-call policy inside a hardware Trusted Execution Environment (TEE).** Every tool call is intercepted, evaluated against a Cedar policy bundle, and enforced where the process it governs cannot reach it. Each session produces a signed, hardware-attested TRACE Claim that a verifier checks without trusting the operator. If you are looking for a secure version of MCP, this is the AgenTrust runtime for it.

Expand Down Expand Up @@ -63,7 +63,7 @@ Create `cmcp-config.yaml`:
```yaml
attestation:
provider: auto
enforcement_mode: advisory
enforcement_mode: advisory # advisory eases first-run tuning; the default is `enforcing`
policy_bundle_path: ./policies/
catalog_path: ./catalog.json
```
Expand Down Expand Up @@ -115,20 +115,21 @@ Agent -> cMCP Runtime -> Cedar Policy Engine (TEE) -> Tool
| `sev-snp` | AMD SEV-SNP (Azure DCasv5, AWS C6a Nitro) | High | AMD KDS |
| `tdx` | Intel TDX (Azure DCedsv5, GCP C3) | High | Intel PCS |
| `gpu-cc` _(v0.2)_ | NVIDIA H100/H200/Blackwell (CC mode) | High | NVIDIA Remote Attestation Service (NRAS) |
| `opaque` _(explicit opt-in)_ | OPAQUE Confidential Runtime | High | Set `OPAQUE_ATTESTATION_URL`; not in auto-detect chain (stub: detect() returns False, not yet implemented) |
| `opaque` _(opt-in)_ | OPAQUE Confidential Runtime | n/a _(not yet implemented)_ | Placeholder: `detect()` returns `False`, so it is never auto-selected until implemented |

Provider auto-detects: `SEV-SNP -> TDX -> TPM -> software`. `opaque` is explicit opt-in via `OPAQUE_ATTESTATION_URL` and is never selected automatically.
Provider auto-detect probe order: `tpm -> sev-snp -> tdx -> opaque` — the first provider whose `detect()` succeeds is selected. `opaque` is a not-yet-implemented placeholder and is never auto-selected. If no hardware provider is detected, the gateway starts only under `CMCP_DEV_MODE=1` (a non-attested software-only fallback) and otherwise refuses to start.

```python
from cmcp_gateway.config import TEEProvider
from cmcp_runtime.config import TEEProvider

# Auto-detect (default)
# attestation.provider: auto -> sev-snp -> tdx -> tpm -> software
# attestation.provider: auto -> tpm -> sev-snp -> tdx -> opaque
# (software-only is used only under CMCP_DEV_MODE=1)

# Explicit hardware selection
# attestation.provider: sev-snp

# OPAQUE Managed Runtime (explicit opt-in only)
# OPAQUE Managed Runtime (opt-in only; not yet implemented)
# OPAQUE_ATTESTATION_URL=https://... cmcp start --config cmcp-config.yaml
```

Expand Down Expand Up @@ -196,12 +197,15 @@ A `GatewayClaim` is the unit of proof handed to an auditor, regulator, or downst
| `trace.runtime` | TEE platform and hardware measurement recorded at enclave boot |
| `trace.policy.bundle_hash` | SHA-256 of the Cedar bundle loaded at startup; changing any policy file changes this value |
| `trace.cnf.jwk` | Ed25519 public key bound to the TEE signing key |
| `trace.tool_transcript` | Audit-chain-derived per-call view: `hash` (binds to the audit chain tip), `call_count`, and privacy-preserving `entries` (tool name, data class, decision) |
| `gateway.audit_chain` | Hash-chained audit log root and tip; verifiable without replaying individual entries |
| `signature` | Ed25519 over canonical JSON of the full claim body (RFC 8785) |

(This table is a summary of the most-used fields.)

Verification with the `cmcp_verify` library does not require trusting the operator. The verifier checks the signature against the TEE-bound key, the policy bundle hash against the approved value, and the audit chain for internal consistency.

See [docs/spec/verification-library.md](docs/spec/verification-library.md) and the [TRACE specification](https://trace.agentrust-io.com) for the full verification protocol.
The normative schema is [`schemas/trace-claim.schema.json`](schemas/trace-claim.schema.json), and [docs/quickstart.md](docs/quickstart.md) shows a complete example. See [docs/spec/verification-library.md](docs/spec/verification-library.md) and the [TRACE specification](https://trace.agentrust-io.com) for the full verification protocol.

---

Expand Down
9 changes: 8 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,18 @@ Scope: Minimal viable trust layer for MCP servers, sufficient for early adopters

## v0.2: Released (June 2026)

Provider-specific attestation verification:
Provider-specific attestation verification (report parsing plus certificate-chain
verification, validated against real vendor roots; report-signature paths validated with
synthetic vectors):
- TPM2 quote verification
- AMD SEV-SNP attestation report parsing and verification
- Intel TDX attestation report parsing and verification

> Report *generation* requires the corresponding TEE hardware. Until a backend verifies a
> real quote end to end against a golden measurement on a confidential VM, these verifiers
> should not be described as fully hardware-attested. This is the same status tracked for
> the shared verifier code in the sibling [ca2a](https://github.com/agentrust-io/ca2a) repo.

Server integration:
- Session-scoped TRACE Claim emission wired into `server.py` request lifecycle
- Claim correlation across multi-turn sessions
Expand Down
36 changes: 36 additions & 0 deletions STATUS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# cMCP — current status

This file is the single source of truth for what ships today versus what is on the roadmap.
Other docs (README, SPEC, quickstart) should link here rather than restate status, so the
picture is stated once. Developer Preview: interfaces may change before v1.0.

## Defaults (from `cmcp_runtime.config`)

| Setting | Default |
|---|---|
| `attestation.provider` | `auto` (probe order `tpm -> sev-snp -> tdx -> opaque`) |
| `attestation.enforcement_mode` | `enforcing` |
| `attestation.staleness_policy` | `fail_closed` |
| `attestation.validity_seconds` | `86400` |
| `policy_reload_interval_seconds` | `0` (disabled; policy change requires an enclave restart) |

## Capabilities

| Capability | Status | Notes |
|---|---|---|
| MCP interception + Cedar policy evaluation inside the TEE | Shipped | HTTP/SSE transport. `stdio` is not yet supported (bridge planned, Phase 2). |
| Enforcement modes (`enforcing` / `advisory` / `silent`) | Shipped | Default is `enforcing`. |
| Hash-chained audit log, TEE-sealed signing key | Shipped | |
| `GatewayClaim` (TRACE Claim) generation + signing | Shipped | Normative schema: [`schemas/trace-claim.schema.json`](schemas/trace-claim.schema.json). |
| Offline verification (`cmcp_verify`) | Shipped | No operator trust required when the verifier independently checks the attestation report. |
| Agent Manifest identity binding | Shipped | Optional; trust in the issuer key is an out-of-band PKI concern. |
| Attestation verifiers: `tpm`, `sev-snp`, `tdx` | Partial | Report parsing + certificate-chain verification against real vendor roots; report-signature paths validated with synthetic vectors. End-to-end validation against a real hardware quote on a confidential VM is pending — do not describe as fully hardware-attested until then. |
| `opaque` provider | Not implemented | Opt-in placeholder; `detect()` returns `False`, so it is never auto-selected until implemented. |
| `gpu-cc` (NVIDIA H100/H200/Blackwell, via NRAS) | Planned (v0.2) | |
| Transparency-log anchoring for TRACE Claims | v0.2 | Write and lookup. |
| Server-side (provider) attestation | Not yet (Phase 2) | Phase 1 attests the gateway boundary only. |
| Real-time policy update without enclave restart | Not yet | `policy_reload_interval_seconds` is `0`; a policy change requires a restart. |
| Full RATS/EAT conformance | v1.0 target | Claims are EAT-shaped today; full conformance is tracked for v1.0. |

See [ROADMAP.md](ROADMAP.md) for version sequencing and [LIMITATIONS.md](LIMITATIONS.md) for
what cMCP does not prevent.
95 changes: 61 additions & 34 deletions docs/SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,45 +127,68 @@ Network position: sits between agent host and MCP servers. The gateway is the on

## 5. TRACE Claim Schema

The unit of proof handed to an auditor. Produced per-session or per-call (configurable).
The unit of proof handed to an auditor, produced per session (or per call, configurable).
The normative schema is [`schemas/trace-claim.schema.json`](../schemas/trace-claim.schema.json),
and a full worked example is in [the quickstart](quickstart.md). The envelope is a
`GatewayClaim`: canonical TRACE v0.1 fields live under `trace`, cMCP-specific addenda live
under `gateway`, and `signature` is detached (computed over every other field).

```json
{
"trace_version": "1.0",
"session_id": "<uuid>",
"timestamp_utc": "<ISO 8601>",
"tee_public_key": "<hex>",
"attestation_report": {
"provider": "sev-snp | tdx | tpm | opaque",
"measurement": "<PCR values or SEV measurement>",
"report_data": "<nonce binding key to report>"
"cmcp_version": "1.0",
"trace": {
"eat_profile": "tag:agentrust.io,2026:trace-v0.1",
"iat": 1730000000,
"subject": "spiffe://cmcp.gateway/tee/<key-prefix>",
"runtime": {
"platform": "amd-sev-snp | intel-tdx | tpm2 | software-only",
"measurement": "sha256:<hex>",
"nonce": "<base64url nonce binding the report to this session>"
},
"policy": {
"bundle_hash": "sha256:<hex>",
"enforcement_mode": "enforce | advisory | silent",
"version": "<semver>"
},
"data_class": "<highest sensitivity reached this session>",
"tool_transcript": {
"hash": "sha256:<audit chain tip>",
"call_count": 42,
"entries": [
{ "tool_name": "salesforce.query", "data_class": "pii", "decision": "allow" }
]
},
"cnf": { "jwk": { "kty": "OKP", "crv": "Ed25519", "x": "<base64url>", "kid": "cmcp-<id>" } }
},
"policy_bundle": {
"hash": "<sha256>",
"enforcement_mode": "enforcing | advisory | silent",
"policy_version": "<semver>"
"gateway": {
"session_id": "<uuid>",
"sequence_number": 1,
"audit_chain": { "root": "sha256:<hex>", "tip": "sha256:<hex>", "length": 43 },
"call_summary": {
"tool_calls_total": 42,
"tool_calls_allowed": 40,
"tool_calls_denied": 2,
"tool_calls_faulted": 0,
"tools_invoked": ["salesforce.query", "snowflake.read"],
"session_max_sensitivity": "pii",
"call_graph_summary": { "compliance_domains_touched": [], "cross_boundary_events": [] }
},
"catalog": { "hash": "sha256:<hex>", "drift_detected": false },
"attestation_generated_at": "<ISO 8601>",
"attestation_validity_seconds": 86400,
"attestation_stale": false,
"catalog_exceptions": []
},
"tool_catalog": {
"hash": "<sha256 of approved catalog at startup>"
},
"call_summary": {
"tool_calls_total": 42,
"tool_calls_allowed": 40,
"tool_calls_denied": 2,
"tools_invoked": ["salesforce.query", "snowflake.read"]
},
"audit_chain_root": "<sha256 of first entry>",
"audit_chain_tip": "<sha256 of last entry>",
"signature": "<TEE-sealed key signature over canonical JSON>"
"signature": "<base64url Ed25519 over the canonical JSON of every field except signature>"
}
```

Verification (no operator trust required):
1. Verify tee_public_key against attestation_report (hardware-rooted)
2. Verify signature using tee_public_key
3. Check policy_bundle.hash against the approved hash on record
4. Check tool_catalog.hash against the approved catalog hash on record
5. Walk audit_chain_root to audit_chain_tip for call-level detail
1. Verify the `trace.cnf.jwk` public key against `trace.runtime` (hardware-rooted attestation)
2. Verify `signature` using that key
3. Check `trace.policy.bundle_hash` against the approved bundle hash on record
4. Check `gateway.catalog.hash` against the approved catalog hash on record
5. Recompute `trace.tool_transcript.hash` and walk `gateway.audit_chain` root to tip for call-level detail

---

Expand Down Expand Up @@ -233,9 +256,13 @@ Across the four problems and 13 shapes, Phase 1 covers 11 outright and partially
| tpm | TPM 2.0 / vTPM | Medium |
| sev-snp | AMD SEV-SNP (Azure DCasv5, AWS C6a Nitro) | High |
| tdx | Intel TDX (Azure DCedsv5, GCP C3) | High |
| opaque | OPAQUE Managed Runtime | Highest |
| opaque | OPAQUE Managed Runtime (opt-in; not yet implemented) | n/a |

Auto-detection: tpm -> sev-snp -> tdx -> opaque. Default enforcement_mode: advisory.
Auto-detection probe order: `tpm -> sev-snp -> tdx -> opaque`. The first provider whose
`detect()` succeeds is selected. `opaque` is a placeholder whose `detect()` currently returns
`False`, so it is never auto-selected until it is implemented. If no hardware provider is
detected, the gateway starts only under `CMCP_DEV_MODE=1` (a non-attested software-only
fallback) and otherwise refuses to start. Default `enforcement_mode` is `enforcing`.

---

Expand All @@ -259,12 +286,12 @@ In scope:
- Session-context sensitivity tagging and bleed detection
- Tool catalog binding (tool name to specific upstream server identity)
- TRACE Claim generation and signing
- Hardware attestation: TPM, SEV-SNP, TDX, OPAQUE Managed
- Hardware attestation: TPM, SEV-SNP, TDX (OPAQUE Managed is an opt-in placeholder, not yet implemented)
- Enforcement modes: enforcing, advisory, silent
- Egress policy: allow/deny/redact per tool and per field
- Per-session TRACE Claim with call summary
- Agent-side verification library (cmcp-verify)
- Python SDK (cmcp-gateway), config file (cmcp-config.yaml)
- Python SDK (cmcp-runtime), config file (cmcp-config.yaml)

Not in Phase 1:
- MCP server-side attestation (Phase 2)
Expand Down