This guide explains how SMCP fits into an orchestrator stack, how to deploy a Gateway, and how to define SecurityContexts for your agents.
SMCP operates at the protocol layer, on top of the physical security boundary already provided by the Orchestrator Proxy pattern.
┌─────────────────────────────────────────────────────────────┐
│ Agent Container │
│ SMCP SDK: generate keypair → attest → sign envelopes │
└──────────────────────────────┬──────────────────────────────┘
│ SmcpEnvelope (over TLS)
▼
┌─────────────────────────────────────────────────────────────┐
│ Orchestrator — SmcpMiddleware │
│ │
│ Physical layer: Orchestrator Proxy Pattern │
│ - All agent tool calls physically route through here │
│ - Internal tools executed via Runtime::exec() │
│ - External tools executed with orchestrator credentials │
│ │
│ Protocol layer: SMCP │
│ - AttestationService: verify workload, issue JWT │
│ - SmcpMiddleware: verify signature, validate JWT │
│ - PolicyEngine (Cedar): evaluate SecurityContext │
│ - Unwrap → forward plain MCP to Tool Server │
└──────────────────────────────┬──────────────────────────────┘
│ Standard MCP JSON-RPC
▼
┌─────────────────────────────────────────────────────────────┐
│ Tool Server │
│ (No SMCP awareness — receives ordinary MCP JSON-RPC) │
└─────────────────────────────────────────────────────────────┘The physical proxy layer ensures requests are routed correctly and credentials are held by the orchestrator, not agents. SMCP adds protocol-level identity and authorization enforcement. Both layers are required; neither alone provides complete security.
The SMCP Gateway exposes two endpoints:
Request body:
{
"public_key": "<Base64 Ed25519 public key>",
"workload_id": "<execution session ID>",
"requested_scope": "<SecurityContext name>"
}Success response (200):
{
"status": "attested",
"security_token": "<JWT>",
"expires_at": "2026-02-21T13:00:00Z",
"session_id": "<SmcpSession UUID>"
}Failure responses:
401— workload identity could not be verified (error code3000or3002)403— requestedSecurityContextnot found (error code3001)
Request body: A complete SmcpEnvelope JSON object.
Success response (200):
{
"payload": {
"jsonrpc": "2.0",
"result": { ... },
"id": 1
}
}Failure responses:
401— envelope verification failed (signature, JWT, timestamp; error codes1xxx)403— policy violation (error codes2xxx)
A SecurityContext is a named permission boundary. Agents request a SecurityContext by name at attestation.
These examples are taken from RFC Appendix A:
Allows web search and read-only filesystem access within /workspace:
name: read-only-research
capabilities:
- tool_pattern: "web_search"
domain_allowlist:
- "*.wikipedia.org"
- "*.arxiv.org"
- "*.scholar.google.com"
- tool_pattern: "filesystem.read"
path_allowlist:
- "/workspace"
- tool_pattern: "filesystem.list"
path_allowlist:
- "/workspace"
deny_list:
- tool_pattern: "filesystem.write"
- tool_pattern: "filesystem.delete"
- tool_pattern: "shell.*"Allows read/write filesystem access and git operations within a project directory:
name: code-assistant
capabilities:
- tool_pattern: "filesystem.*"
path_allowlist:
- "/workspace/project"
- tool_pattern: "git.*"
path_allowlist:
- "/workspace/project"
- tool_pattern: "shell.run"
command_allowlist:
- "npm test"
- "cargo test"
- "pytest"
deny_list:
- tool_pattern: "filesystem.delete"
# Restrict delete to be explicit
- tool_pattern: "shell.run"
# Denies unlisted commands (deny_list evaluated first)Note: The
deny_listis evaluated before capabilities. A tool matching any deny rule is blocked regardless of whether it also matches a capability.
Full access — intended for trusted orchestrator-level tooling only:
name: admin-unrestricted
capabilities:
- tool_pattern: "*"
deny_list: []| Setting | Recommended | Maximum |
|---|---|---|
| Token lifetime | 1 hour | 24 hours |
| Key rotation (Gateway signing key) | Every 90 days | — |
Short-lived tokens limit the blast radius of a stolen JWT. The signature binding (agent's ephemeral private key → token) provides an additional layer: a stolen token is useless without the corresponding private key.
For long-running agents, implement token renewal by calling attest() again before the token expires.
In a production deployment, the Gateway should not hold its signing key directly. Instead, it should use a KMS Transit Engine (Encryption-as-a-Service):
AttestationService → Transit Engine API (sign) → KMS
│
└─ Ed25519 key
managed by KMS
never distributedThis implements the Keymaster Pattern: the key material never leaves the HSM/KMS. Compromise of the orchestrator process does not expose the signing key.
The JWT is signed with EdDSA (alg: EdDSA in the JWT header). Verification requires the Gateway's public key, which can be fetched from a well-known endpoint or distributed out-of-band for SDK use.
During attestation, the Gateway must verify that the workload_id maps to a real, currently running execution. For example:
- Container runtime: The Gateway checks the container runtime API to confirm a container with the matching execution ID is running, and cross-references the submitted public key with what was registered at container start.
- VM runtime: Similar verification via the hypervisor management API.
This step prevents attackers from forging attestation requests with arbitrary workload_ids.
In multi-tenant deployments, SecurityContexts are scoped to namespaces. For example, using OpenBao namespaces to isolate per-tenant secrets and signing keys:
tenant-acme/
SecurityContexts:
- research-safe (Acme-specific domain allowlists)
- code-assistant (Acme-specific path boundaries)
tenant-beta/
SecurityContexts:
- research-safe (Beta-specific domain allowlists — different from Acme's)Namespace isolation ensures that two tenants with a SecurityContext named research-safe cannot cross-access each other's resources even if names collide.
Every SMCP operation should publish domain events to an audit event store. These events power the audit trail and compliance reporting:
| Event | Description |
|---|---|
AttestationSucceeded |
Agent attested; session created |
AttestationFailed |
Attestation rejected; reason logged |
ToolCallAuthorized |
Tool call passed PolicyEngine; forwarded to Tool Server |
PolicyViolationBlocked |
Tool call rejected; violation type and details logged |
SignatureVerificationFailed |
Envelope signature invalid |
SecurityTokenExpired |
Agent's JWT expired mid-session |
SessionRevoked |
Gateway revoked the session (e.g., execution cancelled) |
SMCP is transport-agnostic. In the current Docker-based deployment, the agent communicates with the Gateway over TCP/TLS. In the Phase 2 Firecracker deployment:
- The
SmcpEnvelopeis transmitted over VSOCK (virtual socket between the MicroVM and host). - No changes to the agent-side SDK are required — the envelope format and endpoints are identical.
- The Gateway-side
SmcpMiddlewareadds a VSOCK listener alongside the existing TCP listener.
This is possible because the SmcpEnvelope is transport-agnostic: it contains all the identity and authorization information needed for stateless verification, regardless of how it was delivered.
- RFC smcp-v1-specification — full protocol specification including test vectors and compliance mapping
- OpenBao Transit Engine — encryption-as-a-service for Gateway key signing
- Cedar Policy Language — declarative policy engine for SecurityContext evaluation