Trust Envelope ↔ MCP OAuth 2.1 Bridge — v1
Bidirectional mapping between BrainstormRouter's Trust Envelope and MCP OAuth 2.1 protected resource metadata. Enables agents authenticated to BR to access MCP tool servers with claim-bound authorization.
Status: Draft 1 · published 2026-05-16 · canonical URL https://docs.brainstormrouter.com/specs/mcp-oauth-bridge-v1
Authors: BrainstormRouter License: CC BY 4.0 (specification) — reference implementations under their respective package licenses
---
1. Abstract
This specification defines a bidirectional mapping between BrainstormRouter's Trust Envelope (an EdDSA-signed JWT representing a verified agent identity with capability, budget, and trust claims) and MCP OAuth 2.1 protected resource metadata (per the Model Context Protocol authorization spec, March 2025). It enables agents authenticated to BrainstormRouter to access MCP tool servers through the gateway with claim-bound authorization that survives the agent → gateway → tool-server round-trip.
The bridge is the smallest possible primitive that makes BR's per-agent governance (identity, budgets, scopes, anomaly scoring) load-bearing inside MCP tool execution, rather than terminating at the BR API boundary.
2. Motivation
The MCP authorization specification mandates OAuth 2.1 with protected resource metadata (RFC 9728 draft) for any MCP server that gates tool access on caller identity. Agent runtimes integrating multiple MCP servers therefore need a way to:
- Authenticate an agent once (at the BrainstormRouter boundary)
- Carry that authentication through the gateway to downstream MCP servers
- Have downstream MCP servers verify the agent's identity, capability scope, and budget allowance — without re-issuing tokens or holding upstream provider credentials
BrainstormRouter ships the Trust Envelope primitive — an EdDSA-signed JWT containing structured agent claims (br_principal, br_scope, br_budget, br_trust, br_observability, br_test). Without an OAuth bridge, the envelope is BR-only. With the bridge defined here, the envelope becomes the canonical agent-identity carrier for MCP tool execution across any compliant tool server.
3. Terminology
- Trust Envelope — the EdDSA-signed JWT that BrainstormRouter mints per request, carrying
br_*claims. Lifetime: bound to the request; not stored. See Trust Envelope v1. - MCP Server — any service implementing the Model Context Protocol with Streamable HTTP transport.
- MCP Gateway — BrainstormRouter when acting in its
/v1/mcp/connectcapacity, fronting one or more upstream MCP servers and injecting credentials secretlessly. - Resource Indicator — per RFC 8707, a URI identifying the protected MCP resource the agent is authorized to access.
- Capability Scope — the agent-facing primitive in
br_scope: a set of(provider, model, action)triples plus tool allowlists.
4. Bridge mapping
4.1 Claim correspondence
| Trust Envelope claim | OAuth 2.1 location | Encoding | ||||
|---|---|---|---|---|---|---|
br_principal.agent_id | sub (subject) | string | ||||
br_principal.tenant_id | tenant (custom claim) | string | ||||
br_scope.providers[] | resource[] (resource indicators) | one URI per allowed provider: https://api.brainstormrouter.com/v1/providers/{provider} | ||||
br_scope.models[] | scope (space-separated) | model:{provider}/{model_id} per allowed model; wildcard models:* means no model restriction | ||||
br_scope.tools[] | scope (space-separated) | tool:{tool_name} per allowed MCP tool | ||||
br_budget.remaining_usd | br_budget_remaining (custom claim) | number, dollars | ||||
br_budget.period_ends_at | br_budget_period_ends (custom claim) | ISO 8601 datetime | ||||
br_trust.tier | br_trust_tier (custom claim) | enum: restricted \ | bronze \ | silver \ | gold \ | platinum |
br_trust.xdr_risk | br_xdr_risk (custom claim) | number 0.0–1.0 | ||||
br_trust.anomaly_score | br_anomaly_score (custom claim) | number 0.0–1.0 | ||||
br_observability.request_id | jti (JWT ID) | UUID |
4.2 Token structure
A Trust Envelope ↔ MCP OAuth token is a JWS with header:
{
"alg": "EdDSA",
"typ": "JWT",
"kid": "<envelope-key-id>"
}
Payload:
{
"iss": "https://api.brainstormrouter.com",
"aud": "<mcp-server-resource-uri>",
"sub": "<agent_id>",
"tenant": "<tenant_id>",
"iat": 1715800000,
"exp": 1715800300,
"jti": "<request_uuid>",
"resource": [
"https://api.brainstormrouter.com/v1/providers/anthropic",
"https://api.brainstormrouter.com/v1/providers/openai"
],
"scope": "model:anthropic/claude-opus-4-7 tool:br_route_completion tool:br_memory_query",
"br_budget_remaining": 12.47,
"br_budget_period_ends": "2026-05-17T00:00:00Z",
"br_trust_tier": "gold",
"br_xdr_risk": 0.02,
"br_anomaly_score": 0.11
}
exp - iat SHOULD be ≤ 300 seconds (5 minutes). MCP servers MUST reject tokens with longer lifetimes.
4.3 Resource indicator semantics
Per RFC 8707, the resource claim is the authoritative declaration of which MCP server(s) this token may access. The aud claim MUST be one of the URIs in resource. An MCP server receiving the token MUST verify:
audmatches the MCP server's configured resource URI exactly- Token signature verifies against the issuer's published JWKS
iat ≤ now < exp- Required
scopeentries for the requested tool are present
Empty resource[] array (no provider restriction) MUST be treated as deny all — wildcard access is expressed by listing every supported provider URI explicitly. This matches BrainstormRouter's br_scope.providers semantics (locked 2026-05-13, issue #296: empty-array = "not yet load-bearing in A-1", but for the bridged token the semantics are stricter — empty means deny).
4.4 OAuth 2.1 protected resource metadata
An MCP server compliant with this bridge MUST expose GET /.well-known/oauth-protected-resource returning:
{
"resource": "https://example-mcp-server.com",
"authorization_servers": ["https://api.brainstormrouter.com"],
"bearer_methods_supported": ["header"],
"resource_documentation": "https://example-mcp-server.com/docs",
"resource_signing_alg_values_supported": ["EdDSA"],
"br_trust_envelope_version": "v1"
}
The br_trust_envelope_version claim is the indicator that this resource accepts BR-bridged tokens conforming to this specification.
5. Token issuance flow
┌──────────┐ 1. ┌─────────────────┐ 2. ┌──────────────┐
│ Agent │ ─────▶ │ BrainstormRouter │ ────▶ │ MCP Server │
│ (caller) │ ◀───── │ (issuer + gw) │ ◀──── │ (resource) │
└──────────┘ 4. └─────────────────┘ 3. └──────────────┘
- Agent authenticates to BR via API key or agent JWT; calls
POST /v1/mcp/connectwith the desired MCP server identifier and tool name. - BR validates the agent's identity, budget, scope, and anomaly score. If all gates pass, BR mints a Trust Envelope JWT with
audset to the target MCP server's resource URI, signs with the current envelope key, and forwards the request to the MCP server withAuthorization: Bearer. - MCP server verifies the token per §4.3, executes the tool (or returns 403 with structured
recovery.actionif scope insufficient), and returns the tool result. - BR forwards the response back to the agent, attaching the standard
X-BR-*observability headers.
The agent never sees the bridged token; it is minted, used, and discarded inside BR's request lifecycle.
6. Error responses
MCP servers rejecting a bridged token MUST return HTTP 401 or 403 with a body conforming to BrainstormRouter's ErrorEnvelope schema (forthcoming spec):
{
"error": {
"type": "insufficient_permissions",
"message": "Token scope does not include tool:br_memory_query",
"code": "scope_insufficient"
},
"recovery": {
"action": "escalate",
"endpoint": "POST /v1/rbac/request",
"method": "POST",
"message": "Request elevated scope from your operator"
}
}
The recovery.action enum is defined in the ErrorEnvelope spec. Agents consume recovery.action as a typed control-flow primitive — string parsing is non-conforming.
7. Reference implementations
| Language | Repository | License |
|---|---|---|
| TypeScript | @brainstormrouter/trust-envelope on npm | MIT |
| Python | brainstormrouter-trust-envelope on PyPI | MIT |
| Go | github.com/brainstormrouter/trust-envelope-go | MIT |
Each reference implementation MUST pass the conformance test vectors at specs/mcp-oauth-bridge-v1-test-vectors.json (forthcoming).
8. Security considerations
- Token replay: the 5-minute
explimit + per-requestjtimake replay attacks impractical. MCP servers SHOULD maintain a short-livedjticache (5 min TTL) to reject duplicates. - Key rotation: BR rotates envelope signing keys via the standard JWKS rollover. MCP servers MUST refresh JWKS at least every 24 hours.
- Audience confusion: a token issued for MCP server A MUST NOT be accepted by MCP server B. The
audcheck is strict equality. - Scope confusion: tools added to
br_scope.tools[]AFTER token issuance do NOT retroactively grant access. The token's scope is the authoritative allowlist for its lifetime. - Budget claims are advisory:
br_budget_remaininglets a tool server pre-flight an expensive operation, but the authoritative budget check is still BR's atomic Redis reserve. Tool servers MUST NOT rely onbr_budget_remainingas the sole spend control.
9. Versioning
This specification follows semantic versioning:
- Major (v2, v3, ...) — breaking claim renames, format changes, or removal
- Minor (v1.1, v1.2) — new optional claims, new resource metadata fields
- Patch (v1.0.1) — clarifications, typo fixes, additional test vectors
The current version is v1.0.0-draft-1. v1.0.0 final ships once at least two reference implementations pass the conformance vectors and one third-party MCP server has validated against the spec.
10. References
- RFC 8707 — Resource Indicators for OAuth 2.0
- RFC 9728 — OAuth 2.0 Protected Resource Metadata (draft)
- RFC 9068 — JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens
- Model Context Protocol Authorization Spec (March 2025)
- Trust Envelope v1
- ErrorEnvelope v1 (forthcoming)
Changelog
- 2026-05-16 — Draft 1 published. Maps the 6
br_*Trust Envelope claims to OAuth 2.1 protected resource metadata. Specifies the 5-minute token lifetime, deny-by-defaultresource[]semantics, and ErrorEnvelope-shaped 401/403 responses.