Proposal: Agent Identity and Delegation for MCP Tool Calls #2404
Replies: 5 comments
-
|
@pcarleton @pja-ant Would love your thoughts on this, it sits at the intersection of auth and the agents working group. Happy to answer any questions or iterate on the design. |
Beta Was this translation helpful? Give feedback.
-
|
we've hacked around this before with manual allowlists, but it breaks down once you get deep nesting — you lose track of what each agent in the chain can actually do. revocation's the killer though: if a parent agent goes rogue mid-request, how do you unwind that delegation? |
Beta Was this translation helpful? Give feedback.
-
|
Good questions, both are exactly what motivated the design. On deep nesting: Each delegation in the chain can only attenuate (narrow) the parent's permissions, never widen them. So if Agent A delegates On mid-request revocation: Revocation is checked at verification time, not delegation time. Each proof includes the full chain, and The implementation is live across Rust, TypeScript, and Python if you want to try it: https://github.com/kanoniv/agent-auth |
Beta Was this translation helpful? Give feedback.
-
|
Great proposal. Agent identity and delegation is one of the most critical missing pieces in MCP right now. I've been working on a production implementation of exactly this. ScopeBlind Passport provides a portable, signed agent identity that works today:
For the "delegation" part specifically: we use a binding receipt that links the agent's Ed25519 identity key to a P-256 DPoP key. The operator signs this binding, creating a verifiable chain: Operator → Agent Identity → Per-Request DPoP Proof. The enforcement layer is protect-mcp — a stdio proxy that evaluates the agent's Passport at session start and assigns tool-level access based on the trust tier. Every tool call produces a signed decision receipt. Would love to align on the identity schema if there's interest in standardizing this at the spec level. |
Beta Was this translation helpful? Give feedback.
-
|
Strong proposal. The delegation chain design is exactly right — attenuation-only is the correct security model for nested agent systems. We've been working on the complementary layer: cross-organizational agent identity. MCP's OAuth 2.1 handles human→server auth, this proposal handles agent→agent delegation within a system, but neither addresses: how does Server X verify that Agent Y from Organization Z is who it claims to be when there's no shared IdP? At RSAC 2026 last week, 200+ vendors launched agent identity products. Every single one assumes a shared admin or control plane. Zero handle the cross-org case — Agent A (running on Org 1's infra) calling a tool hosted by Org 2, where Org 2 has no prior relationship with Org 1. The Solana Agent Trust Protocol (SATP) addresses this by anchoring agent identity on-chain:
The two-layer model: this proposal for intra-system delegation (who authorized this agent to act) + SATP for cross-system identity (is this agent who it claims to be, and should I trust it). The Happy to collaborate on composability. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Problem
MCP has a robust authorization spec for the human-to-server relationship: OAuth 2.1 handles "which human authorized this client to access this server." This works well for the HTTP transport.
But there is no standard mechanism for agent-to-agent authorization in tool calls. When Agent A delegates a task to Agent B, and Agent B calls an MCP tool, the server has no way to answer:
This gap is especially acute for:
Today, MCP servers must fall back to API keys, environment variables, or custom headers. None of these support delegation, attenuation, or cryptographic verification.
Proposed Extension
Add an optional
authfield toparams._metaontools/callrequests:{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "search_contacts", "arguments": { "query": "Alice Smith" }, "_meta": { "auth": { "type": "delegation-proof", "version": "1", "invoker_did": "did:agent:4a1b2c3d...", "invoker_public_key": "a1b2c3d4e5f6...", "proof": "<base64-encoded invocation proof>" } } } }Design principles:
_meta.auth. Servers choose whether to require, accept, or ignore it._metais already part of the spec. Servers that don't understandauthignore it. Clients that don't support it send calls without it.How It Works
Setup (one-time)
A human or organization creates a root authority (Ed25519 keypair) and delegates to agents with constraints:
Each delegation is signed by the issuer. Caveats (action scope, expiry, cost limits, resource patterns) accumulate and can only narrow - never widen.
Per-call flow
params._meta.authServer verification (5 lines)
TypeScript:
Python:
Rust:
Caveat Types
Delegation proofs support constraints that are checked at verification time:
action_scope["search", "resolve"]expires_at"2026-04-01T00:00:00Z"max_cost5.0resource"entity:customer:*"context{"session_id": "abc"}custom{"org": "acme"}Caveats accumulate through the chain. A sub-agent inherits all parent caveats plus any additional restrictions. This means delegation can only narrow authority, never widen it.
Security Properties
did:agent:identifiers. No central registry required.is_revoked(delegation_hash) -> bool. Implementations can plug in any revocation backend.costwhenmax_costcaveat is present) result in rejection, not silent bypass.What This Does NOT Do
did:agent:but the proof format is DID-method-agnostic._metafield. No protocol-level changes needed.Reference Implementation
An MIT-licensed library implementing this proposal is available in three languages:
All three produce byte-identical proofs and can cross-verify (sign in Python, verify in Rust).
Source: github.com/kanoniv/agent-auth
Related Discussions
Beta Was this translation helpful? Give feedback.
All reactions