Least-Privilege MCP Tool Calls
An agent preparing a board packet reads financials, drafts a document, and notifies a reviewer group: three MCP tool calls across three authorization domains, all behind one sentence of human intent.
This series separates the parts that are already tractable from the part that is still missing. Least privilege for a single call has two natural designs. The agent can carry narrow authority in a token, or the MCP server can decide each call at the resource. The standards forming around AuthZEN, COAZ, ARAP, OAuth’s challenge-and-remediation family, and MCP structured denials make those calls more interoperable. But once the work spans several tools and servers, per-call authorization still has no shared object for the task the user approved. Correlation is not governance. Threading those calls together with a shared identifier is not the same as a layer that can decide whether the whole task is still what the user approved.
Read it if you are designing MCP servers, authorization servers, agent gateways, or policy systems and need to decide where fine-grained authorization should live.
The choice in one pass
- Need authority to travel? Token-side.
- Need live resource semantics? Resource-side.
- Need a standard PEP-to-PDP shape? AuthZEN, with COAZ mapping the tool call into it.
- Need denied-but-requestable calls? ARAP, the MCP SEPs, or a transaction challenge.
- Need the work to survive a disconnect? SEP-2848’s held task.
- Need verifiable continuity across calls, servers, and domains? A Mission.
Part 1: Two Models for Fine-Grained Access
Part 1 establishes the problem, compares the two basic architectures on plain OAuth, and lays out the protocol-layer challenge family before MCP enters.
- Token-side authorization: the agent presents an access token narrowed to the requested tool action.
- Failure signaling and remediation: OAuth’s graduated challenge family carries the no and how to ask at four grains.
insufficient_scopefor the capability class,insufficient_authorization_detailswith ready-to-useauthorization_detailsfor standing authority at the action’s grain (draft-zehavi-oauth-rar-metadata), step-up for authentication strength (RFC 9470), and a transaction-specific challenge for a single transaction (draft-rosomakho-oauth-txn-challenge). Trigger at the resource, remediation at the AS, enforcement by token. - Resource-side authorization: the MCP server acts as the enforcement point and evaluates the concrete call.
- Where the state lives: authorization state can live in the token (claims are the state, and reissuance is how it changes), in a store the PDP evaluates (Zanzibar-style tuples, entitlements), or in a hybrid overlay. The topology changes what token reuse is worth and what an approval must do to take effect.
- The tool boundary:
tools/listcan reduce exposure, but everytools/callstill needs execution-time authorization. - The choice: carry authority when it must travel. Evaluate locally when meaning, freshness, or risk posture belongs at the resource.
Part 2: Closing the Per-Call Gaps
Part 2 picks up where the two models strain and shows which standards or proposals close which gap.
- AuthZEN standardizes the policy question: subject, action, resource, context.
- COAZ maps MCP tool arguments and tokens into that decision shape.
- ARAP turns a denial into a governed request instead of a dead-end
403. - Fulfillment is undefined: ARAP standardizes the request and the re-evaluation, not how an approval becomes durable authorization state. Token-resident state fulfills by minting (AROP binds that to OAuth issuance). Store-resident state fulfills by a write no standard defines.
- AROP, MCP SEP-2643, MCP SEP-2848, and transaction challenges bind the requestable-denial pattern to OAuth, MCP, and hybrid flows.
- One shape at three layers: the same denied-here-is-how-to-ask signal appears on the token side (
insufficient_authorization_detailsfor standing authority, a transaction challenge for a single transaction), as an SEP-2643 denial envelope at the MCP layer, and as an ARAP requestable denial at the policy layer. - The remaining gap: none of them names the task across calls, servers, and authorization domains. SEP-2848’s held task carries lifecycle continuity, and nothing carries verifiable continuity: proof that the denial, the approval, the re-evaluation, and the execution belong to one undertaking.
Where This Leads
The series ends by isolating the missing abstraction: a durable task object that tokens and PDP decisions can point back to. I call that object a Mission. Defining it, the approval that creates it, the lifecycle that governs it, the enforcement that binds every call back to it, and the evidence that makes its continuity verifiable, is its own body of work. The two parts stand on their own.