CRP v0.2 · Proposed. Submitted to the MCP working group as an experimental capability (discussion #2246). Not yet ratified. Open spec (CC-BY-4.0); any vault can implement it.
CRP v0.2 · Proposed · MCP Working Group
Credential Resolution Protocol
The last-mile credential standard for MCP. OAuth secured the front door. CRP standardizes the hop where secrets actually live — so agents use credentials without holding them.
Protocol-first. Vendor-neutral. Sanctum is a reference implementation — not required to implement CRP.
The gap
OAuth stops at the server door
MCP OAuth 2.1 authenticates client → MCP server. It says nothing about how that server reaches GitHub, OpenAI, databases, or internal APIs. Today those keys sit in .env files — the unsecured last mile.
How CRP works
Use-handle, never a secret
CRP standardizes the last mile OAuth doesn't cover: the hop from an MCP server to the downstream API it calls on your behalf. Instead of handing the caller a secret, a CRP provider returns a use-handle — a lease plus a proxy URL. The caller routes its request through that URL; the provider injects the real credential in transit and forwards upstream. The secret never reaches the caller — not disk, not memory, not the wire.
Request — crp/use
{
"method": "crp/use",
"params": {
"service": "openai",
"ttl": 300,
"context": { "purpose": "chat", "traceId": "req-8f2c" }
}
}Response — a handle, never a secret
{
"lease": {
"id": "lease_a1b2c3",
"expiresAt": "2026-07-17T18:05:00Z",
"ttl": 300,
"renewable": true,
"delegationDepth": 0
},
"proxyBaseUrl": "https://provider.local/proxy/t/lease_a1b2c3",
"service": "openai",
"credentialDescriptor": {
"type": "api_key",
"brokered": false,
"autoRefresh": false,
"classification": "confidential"
}
}The caller points its existing HTTP SDK's base URL at proxyBaseUrl and authenticates with the session token it already holds. It never sees the credential — it just makes normal API calls through the handle.

Lease lifecycle
Bounded grants, instant kill
A lease is a time- and scope-bound grant, bound to the requesting identity. It is the unit of containment: a leaked handle is worth only what the lease permits, for only as long as it lives, and only through the provider.
Mint
crp/use issues a lease with a TTL, optional scopes, and a proxy handle.
Use
Requests through proxyBaseUrl are checked (identity, expiry, scope) on every call; the provider injects the credential.
Renew
crp/lease extends a renewable lease within provider limits.
Revoke
crp/revoke kills a lease immediately; child leases cascade.
Expire
Leases end at their TTL with no action required.
Because the credential only works through the provider, revocation is immediate and total — there is no long-lived secret to chase down.
Operations
CRP v0.2 surface
Normative surface for the MCP experimental capability. Full text in the specification.
crp/useREQUIREDPrimary op. Returns a lease + proxy handle — never a secret. Provider injects credentials in transit.
crp/list · lease · revokeOPTIONAL / RECOMMENDEDDiscovery, renew/release, and emergency kill-switch with cascade on delegated leases.
Delegation · broker · classifyFull tierBounded delegation, federated identity brokering (e.g. Entra), sensitivity classification.
Graduated outcomesFull tierrequire_approval and quarantine — policy results beyond flat allow/deny.
Error model
Stable codes for programmatic clients
CRP defines a stable error family (JSON-RPC codes in the -330xx range) so callers can react programmatically rather than parsing prose.
| Code | Name | Meaning |
|---|---|---|
| -33001 | version_mismatch | Provider and caller CRP majors are incompatible |
| -33002 | service_not_found | See note on uniform not-found/not-permitted |
| -33003 | policy_denied | See note on uniform not-found/not-permitted |
| -33004 | lease_not_found | Unknown lease id |
| -33005 | lease_expired | Lease TTL elapsed |
| -33006 | lease_not_renewable | Renewal not permitted |
| -33007 | credential_unavailable | Provider cannot resolve the credential |
| -33008 | rate_limited | Caller exceeded provider limits |
| -33009 | scope_unavailable | Requested scope not grantable |
| -33010 | provider_error | Internal provider failure |
| -33011 | feature_not_supported | Op/feature not offered at this conformance tier |
| -33012 | revocation_failed | Revoke could not complete |
| -33013 | delegation_depth_exceeded | Delegation would exceed the depth ceiling |
| -33014 | broker_exchange_failed | Federated-token exchange failed |
| -33020 | require_approval | Graduated outcome: held pending human approval |
| -33021 | quarantine | Graduated outcome: lease revoked by policy |
Note on service_not_found / policy_denied: a provider MAY return a single uniform "not found or not permitted" for both cases so a caller cannot enumerate which services exist. This is the recommended default.
Delegation
Child leases without escalating secrets
A caller can derive a child lease from one it holds — for a sub-agent or a narrower task — without ever exposing the credential.
Same credential
The child is bound to the same credential the parent holds — delegation never escalates to a different credential.
Bounded depth
Depth is capped by a provider ceiling; a chain cannot grow without limit (delegation_depth_exceeded).
Cascade revoke
Revoking a parent cascades to its entire subtree — no orphaned grants.
Brokered federated identity
Short-lived tokens, still vault-side
For services that accept short-lived federated tokens instead of static secrets, a caller can request a brokered credential via identityScope. The provider performs the token exchange server-side (e.g. an Entra Agent ID two-leg federated exchange, or OAuth2 client-credentials) and refreshes it for the life of the lease — the handle stays stable. credentialDescriptor.brokered is true; the caller still never sees a token.
Entitlement to a given identity is enforced by the identity provider's own federation configuration plus the provider's access policy — a caller cannot assume an identity it is not authorized for.
MCP integration
Experimental capability — no fork
CRP rides MCP's experimental map. Servers advertise support; clients negotiate version. No breaking change to core MCP.
{
"experimental": {
"crp": {
"version": "0.2",
"provider": "example-vault",
"conformance": "standard",
"features": ["use", "list", "lease", "revoke", "delegate", "broker", "classify"]
}
}
}Features match the published CRP v0.2 use-centered surface (use required; no raw-secret export method in the protocol).
Conformance
Tiers built around use-not-retrieve
Providers advertise a conformance tier so callers know what to expect.
Basic
crp/use + leases + audit. The minimum: agents use credentials without holding them.
Standard
Basic + crp/list (discovery) + crp/revoke (kill switch) + version negotiation + data classification on descriptors.
Full
Standard + delegation + brokered federated identity + graduated outcomes (require_approval, quarantine) + classification-aware policy.
Security considerations
Containment by design
The handle is a capability, not a secret
proxyBaseUrl authorizes requests through the provider for the life of the lease — not a bearer credential for the upstream service, and not replayable off the provider.
Containment
Compromising a caller yields leases (TTL + scope + instant revoke), not raw keys. A leaked handle is a bounded, revocable incident.
Use-handle is primary
CRP defines use-not-retrieve as the conforming path. Providers that offer proprietary raw export are outside CRP for that path.
No enumeration oracle
Providers SHOULD return uniform errors for not-found vs not-permitted (see error model).
Transport
CRP assumes the provider terminates and re-originates the downstream request. Deployments SHOULD run the provider loopback-only or behind mutual TLS.
Implementer's on-ramp
Open protocol — any vault
CRP is an open protocol — implement it in any vault or secret manager. Start with the Basic tier (crp/use returning a lease + proxy handle), advertise the capability at MCP initialize, and add tiers as you go. Read the full normative spec at github.com/SanctumSec/crp-spec. Sanctum is a reference implementation — optional.