diff --git a/README.md b/README.md index b0d0864..3ca693b 100644 --- a/README.md +++ b/README.md @@ -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

@@ -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. @@ -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 ``` @@ -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 ``` @@ -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. --- diff --git a/ROADMAP.md b/ROADMAP.md index 1dd8314..f319213 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -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 diff --git a/STATUS.md b/STATUS.md new file mode 100644 index 0000000..1b15152 --- /dev/null +++ b/STATUS.md @@ -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. diff --git a/docs/SPEC.md b/docs/SPEC.md index 5b7d60a..bec0db6 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -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": "", - "timestamp_utc": "", - "tee_public_key": "", - "attestation_report": { - "provider": "sev-snp | tdx | tpm | opaque", - "measurement": "", - "report_data": "" + "cmcp_version": "1.0", + "trace": { + "eat_profile": "tag:agentrust.io,2026:trace-v0.1", + "iat": 1730000000, + "subject": "spiffe://cmcp.gateway/tee/", + "runtime": { + "platform": "amd-sev-snp | intel-tdx | tpm2 | software-only", + "measurement": "sha256:", + "nonce": "" + }, + "policy": { + "bundle_hash": "sha256:", + "enforcement_mode": "enforce | advisory | silent", + "version": "" + }, + "data_class": "", + "tool_transcript": { + "hash": "sha256:", + "call_count": 42, + "entries": [ + { "tool_name": "salesforce.query", "data_class": "pii", "decision": "allow" } + ] + }, + "cnf": { "jwk": { "kty": "OKP", "crv": "Ed25519", "x": "", "kid": "cmcp-" } } }, - "policy_bundle": { - "hash": "", - "enforcement_mode": "enforcing | advisory | silent", - "policy_version": "" + "gateway": { + "session_id": "", + "sequence_number": 1, + "audit_chain": { "root": "sha256:", "tip": "sha256:", "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:", "drift_detected": false }, + "attestation_generated_at": "", + "attestation_validity_seconds": 86400, + "attestation_stale": false, + "catalog_exceptions": [] }, - "tool_catalog": { - "hash": "" - }, - "call_summary": { - "tool_calls_total": 42, - "tool_calls_allowed": 40, - "tool_calls_denied": 2, - "tools_invoked": ["salesforce.query", "snowflake.read"] - }, - "audit_chain_root": "", - "audit_chain_tip": "", - "signature": "" + "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 --- @@ -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`. --- @@ -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)