AI agents and MCP integration
The challenge
Traditional OAuth 2.0 was designed for humans delegating to applications. AI agents break that model in several ways:
- No principle of least privilege by default — long-lived, broadly scoped tokens are the norm, not the exception.
- No delegation chain visibility — when an agent calls a downstream agent, there is no standard record of who authorized what.
- Privilege escalation risk — agents that can register new clients or request broad scopes can exceed their intended authorization.
- No trust differentiation — agents from different providers, with different risk profiles, get treated identically.
- Sparse audit trails — without structured token metadata, you cannot reconstruct what an agent did or why it was allowed.
How PBAC handles it
Trust tiers for agent clients
Agent identity is carried in a software statement — a signed JWT presented at Dynamic Client Registration (DCR). The statement can include agent-specific claims such as agent_provider and agent_model. Policy data defines which providers belong to which trust tier:
{
"agents": {
"untrusted_providers": ["untrusted-provider"],
"semi_trusted_providers": ["semi-trusted-provider"]
}
}
OPA evaluates these tiers at token issuance time. A semi-trusted agent requesting mcp:tools receives a 403 access_denied — no code change, no redeployment. Adding a new provider tier means updating a data row.
Scoped, time-bound tokens
Agent tokens are issued with reduced TTLs (e.g. expires_in=300) and constrained to the exact scopes and resources declared in the software statement. The jit_single_use flag in the OPA output causes the AS to delete the token after the first successful introspection — agents cannot reuse a token after the resource server has validated it.
MCP server protection
An MCP server protects its endpoints by calling the AS introspect endpoint on every request:
- The agent presents a Bearer token.
- The MCP server calls
POST /introspectwith its own RS credential. - The AS re-evaluates the OPA token policy, merging any RS-supplied context (resource type, scopes).
- The AS returns
active: true/falseplus any obligations from the policy output. - The MCP server allows or denies the request.
This means the policy fires on every tool call, not just at login. If policy data changes (e.g., a provider is downgraded), the change takes effect at the next introspection — without touching the agent or the MCP server.
The mcp-demo in this repository is a working end-to-end demonstration of this flow.
Delegation chains
Token exchange (subject token validation, scope narrowing, id_token exchange) is implemented. The actor_token parameter for full composite tokens with act.sub is planned — see RFC 8693 status.
When a primary agent needs to sub-delegate work to a specialized downstream agent, it uses the OAuth 2.0 Token Exchange grant. The downstream agent receives a composite token that carries:
sub— the original human whose data is being accessedact.sub— the delegating agentaud— the downstream agentscp— scopes down-scoped to exactly what the downstream agent needs
OPA validates the full chain before issuing the composite token: the subject token must be valid, the actor must be authorized to delegate, the audience must be a registered client, and the requested scopes must be a subset of the subject grant.
See the Token exchange guide for the full API flow.
Architecture
Example: protecting an MCP server
The mcp-demo walks through the full lifecycle:
Step 0 — Discovery. The agent calls the MCP metadata endpoint (no auth required) to discover the AS token endpoint.
Step 1 — Get a token. The agent registers via DCR (or reuses a cached client_id) and requests a token with client credentials:
POST /token
grant_type=client_credentials
scope=mcp:tools mcp:resources
resource=http://localhost:5200/*
resource_types=urn:mcp:server
OPA evaluates the agent's agent_provider claim against the trust tier data. A trusted provider receives a token with expires_in=300. An untrusted provider receives 403 access_denied.
Step 2 — Call tools/list. The agent calls the MCP server with the Bearer token. The MCP server introspects, OPA approves, and the tool list is returned.
Step 3 — Call tools/call. The agent invokes a tool (e.g. get_time). The MCP server introspects again with the execute scope context — policy fires on every call.
Step 4 — No token. A call without a Bearer token receives 401 with a WWW-Authenticate header pointing to the discovery endpoint.
To run the demo locally:
./mcp-demo/run.sh
Then open http://localhost:5100. See mcp-demo/README.md for full configuration options.
Trust tier matrix
The agentic workflow test suite validates the following policy enforcement:
| Agent | Provider | mcp:tools | mcp:resources | Corporate APIs |
|---|---|---|---|---|
| Trusted | identos | Allowed | Allowed | read |
| Semi-trusted | semi-trusted-provider | Denied | Allowed | read |
| Untrusted | untrusted-provider | Denied | Denied | Denied |
Policy denials are enforced by agents.rego at token issuance; no change to the MCP server or the agent is required to adjust a tier.
Next steps
- MCP demo — run the working end-to-end demo
- Token exchange — RFC 8693 scope narrowing and cross-domain identity
- Registering software — how agents register with software statements
- Policy data — configuring trust tiers and entitlements in OPA
- Concepts: policy — how OPA and Rego fit into the access model
- Talk to us — Discuss agent authorization for your environment