The first part laid out two models for least-privilege MCP tool calls. In the token-side model, the authority lives in a token an authorization server mints. In the resource-side model, the server that runs the tool decides each call. Both authorize a single call well. Both, on plain OAuth, leave the same gaps.
Keep the board packet in mind. An agent preparing it reads Q3 financials from one system, drafts a document in a second, and notifies the audit committee through a third, three tool calls behind one sentence of human intent. This part walks the standards and proposals closing the nearer gaps, then pins down the one that remains.
Four gaps appear once the two models are on the table: the shape of the decision, the mapping from a tool call into that decision, the denied-but-requestable workflow, and the task context that spans calls. AuthZEN standardizes the first. COAZ standardizes the second. ARAP and the wire proposals standardize the third. The fourth is the one that remains, and it is where this part ends.
The stakes scale with reach. If you run one MCP server, AuthZEN and ARAP are enough to make its decisions and denials governable. If you run an agent across three servers, they are not, because no single server knows whether its local call is still part of the same approved task.
AuthZEN Standardizes the Question, Not the Answer
Both models, at the moment of decision, are asking the same question. Given this subject, this action, this resource, and this context, is the call allowed? On plain OAuth, each deployment asks it in its own shape. The AuthZEN Authorization API 1.0 makes that question standard. It defines an evaluation request with a subject, action, resource, and context, a decision response, and a /.well-known/authzen-configuration endpoint so a PEP, the enforcement point, can discover a PDP, the decision point. The policy engine behind it can be Cedar, OpenFGA, OPA, or another engine, without changing the wire contract.
That helps both models. In the resource-side model, the MCP server (or an API gateway in front of it) becomes a PEP and asks a PDP the concrete question:
| |
The subject is the user, with the client and actor in context, so the decision turns on the user’s authority and the agent’s together. In the token-side model, the AS can call the same PDP at issuance time, which is one concrete way to delegate the resource-domain evaluation a generic AS would otherwise lack.
One question the evaluation request raises is who builds it. The tool call has arguments and a token. The PDP wants a subject, an action, a resource, and a context. The AuthZEN profile for MCP tool authorization, COAZ, standardizes that mapping. A tool publishes an x-coaz-mapping in its inputSchema that says how its arguments and the caller’s token become the subject, action, resource, and context the API expects. The mapping lives in metadata, so any enforcement point, an API or AI gateway, a service mesh, or the MCP server itself, can build the same request against a compatible PDP instead of hand-coding the translation per tool.
What AuthZEN does not do is close the structural gap between the two models. It standardizes how you ask the question. It does not change who owns the answer. The AS still needs the resource’s ontology to ask a meaningful question about financials. The resource-side decision is still not portable to another party. And a denial is still just decision: false. AuthZEN tells you how to ask. It does not tell you what happens when the answer is no.
ARAP: Turning a Denial into a Request
The missing piece is the workflow that begins where a plain decision ends. The draft AuthZEN Access Request and Approval Profile, ARAP, defines a requestable denial. The answer is no right now, and the response carries a structured, bound description of how to ask. The agent can act on it instead of giving up.
It helps to separate two things. A denial signal carries the no and how to ask, which insufficient_authorization_details already does on the token side. The approval workflow is what happens next, the request, the decision, and the rebinding to a fresh evaluation. ARAP standardizes that workflow, which is why it gets the longer treatment here. The denial signals are how the no is carried at each layer.
A requestable denial returns decision: false with an access_request the caller can submit:
| |
The PEP submits that to the advertised endpoint, presenting the denial binding so the request cannot be replayed against a different call, and gets back a task with a status endpoint to poll until a decision:
| |
The binding is the load-bearing part. An approval is an input to a fresh decision, not a standing grant. Bind it to the exact subject, action, resource, and request, bind it in time, and reevaluate at execution. The denial binding ensures the approval that comes back covers the call that was denied and no other. After approval, the decision point reevaluates with freshness-bounded policy state before anything executes, which closes the window between approval and use.
ARAP, a draft profile, is the answer to “what happens when the answer is no.” On its own, though, it does not say where the workflow runs. That turns out to be the move that heals the split between the two models.
ARAP at the Resource, at the Authorization Server, or Both
The requestable-denial workflow is the same shape no matter who hosts it: deny with a bound request, carry the request to whoever decides, resume on approval. What changes is where the decision and the issuance live. That makes ARAP a single governance vocabulary that both models can speak.
ARAP at the Resource
The MCP server is the PEP. It evaluates the call, and on a requestable denial it brokers the access request itself and parks the work as a server-held task. The agent holds only a task handle. No new client-held token is minted. After approval, the server reevaluates before execution. For the client developer this is the quiet win. The agent keeps presenting the one token it already holds, and the approval happens behind the resource. There is no second token to acquire, cache, or match to this call.
This keeps domain knowledge and the decision at the resource, where the resource-side model wanted them, and it gives the missing denial-to-approval workflow a home on the tool boundary through held work. At-most-once dispatch and exactly-once business effects still require careful server design and application-level idempotency. A task handle alone cannot provide those guarantees.
ARAP at the Authorization Server
The AS is the decision point. On a requestable denial, it does not just fail the token request. It returns a deferral the client can resume, and it issues the narrow token once the decision completes. The work that used to have no native OAuth home, getting an out-of-band human to approve a token, now has a defined completion.
The completion needs a transport. CIBA does decoupled approval well. A human approves out-of-band on their own device, and tokens come back by poll, ping, or push. But CIBA begins with a client asking to authenticate a user, not with a resource refusing a specific call, so it has nowhere to carry the requestable-denial signal or bind an approval to the call that triggered it. It is the right tool for one step, getting a human to say yes, and the wrong thing to build the workflow on. OAuth Deferred Token Response fits better. The AS returns an authorization_pending response carrying a deferral_code, the client resumes by polling the token endpoint under the urn:ietf:params:oauth:grant-type:deferred grant type or through a registered notification callback, and the AS reevaluates before issuing. No browser and no front-channel round trip is what makes repeated asynchronous approval practical call after call. RFC 8628 Device Grant and RFC 9470 Step-up cover adjacent steps. Each solves one hop. ARAP originates and carries the requestable-denial signal that ties the hops together.
Or Both
The two placements compose. An agent can hit a resource-side denial, and the resource can escalate it to the authorization server when minting a portable token is the right answer, or the AS can defer to resource-side evaluation when the meaning lives at the resource. Because the denial, the request, and the binding are the same artifacts in both directions, the escalation does not change shape as it crosses the boundary.
This is what heals the split the two models started from. Before ARAP, choosing the resource-side model meant inventing a denial-to-approval workflow, and choosing the token-side model meant inventing one too, and the two did not interoperate. With ARAP, you choose where the decision lives on its merits. Ontology and freshness pull the decision toward the resource. Portability pulls authority toward the AS. You reuse one approval workflow either way. The decision placement and the governance workflow stop being the same choice.
Paths Forward
ARAP defines the requestable-denial workflow at the policy layer. Several proposals carry a denial-to-approval flow on the wire, at the authorization server, at the tool boundary, and in between. Some build on ARAP, some arrive at the same shape independently. All are proposals, not settled specifications.
- At the authorization server: the proposed AuthZEN Access Request OAuth Profile. AROP specifies the AS-hosted placement directly. It pairs ARAP with a completion mechanism such as Deferred Token Response or Transaction Authorization Challenge, uses CIBA only for the out-of-band human-approval step, and reuses RAR to carry the authorization details. It adds no grant types or parameters of its own.
- At the tool boundary, two MCP proposals approach the denied-but-requestable case from different ends. MCP SEP-2643, Structured Authorization Denials, standardizes the denial itself. It is a JSON-RPC envelope carrying a failure classification, a retry correlation handle, and structured remediation hints, today a URL-based approval through elicitation or a credential issuance through OAuth scopes and RAR. It is MCP’s own requestable denial, transport-agnostic and backward compatible, and its hints can route to either model, the resource’s own approval surface or an authorization server for a narrow credential. MCP SEP-2848, Asynchronous Approval for Tool Calls, standardizes the workflow on the far side of a denial. The server brokers the access request and parks the work as an MCP task the agent polls, reevaluating before execution after approval, and it references ARAP as its backend. One proposal says here is why, and here is how to ask. The other says hold this task while I handle the asking. They compose. A structured denial can hand off to a brokered task.
- The hybrid: the individual OAuth Transaction Authorization Challenge draft. The resource detects that the agent’s token does not authorize the specific transaction in front of it and issues a transaction challenge naming the resource, the action, and the transaction-specific context. The client takes the challenge to the AS, which evaluates it, requests consent or step-up if needed, and issues a transaction-specific token bound to that exact transaction. The resource is back in the trigger path, like the resource-side model. The AS still mints the token, like the token-side model. It is more disciplined than the bare
WWW-Authenticateplus RAR cycle, because the resource hands the AS a precise transaction description instead of relying on the client to construct a correct RAR from discovered metadata.
Notice the pattern across all of this. The same structured “denied, here is how to ask” is showing up at three layers, largely independently. On the token side, insufficient_authorization_details carries the missing authority as RAR in a WWW-Authenticate challenge. At the MCP layer, SEP-2643 carries it in a JSON-RPC denial envelope. At the policy layer, ARAP carries it as a requestable denial. Different specs, different audiences, one shape. A resource that adopts more than one can answer in whichever form the caller in front of it understands.
The Specs That Close the Gaps
Side by side, here is what each piece adds, which model it serves, and what it costs.
| Approach | Layer | What it adds | Serves | Status | Main tradeoff |
|---|---|---|---|---|---|
RAR with insufficient_authorization_details | OAuth resource server | Action-grained authority and a structured signal that more is needed | Token-side | Individual draft | Machine-actionable, but inherits the AS ontology problem and token churn |
| AuthZEN Authorization API | PEP to PDP | A standard evaluation request, response, and PDP discovery | Both | Final 1.0 | A portable decision contract, but it does not change who owns the answer |
| AuthZEN COAZ profile | MCP tool schema to AuthZEN | A standard mapping from tool arguments and tokens to subject-action-resource-context | Both | WG draft | Makes request construction portable, but it is the mapping, not the decision or the workflow |
| ARAP | Decision point | The requestable-denial to approval workflow | Both | Draft profile | One workflow for either placement, but the flow only, not the wire |
| AROP (openid/authzen#531) | Authorization server | ARAP completed through OAuth token issuance | Token-side | Proposed | Reuses OAuth with no new grant or parameter, but AS-centric |
| MCP SEP-2643 | MCP JSON-RPC | A structured denial envelope with remediation hints | Either | Draft SEP | MCP-native and backward compatible, but the denial, not the approval |
| MCP SEP-2848 | MCP tool, via held work | Server-brokered asynchronous approval | Resource-side | Experimental draft | Decision and workflow stay at the resource, but the server owns idempotency |
| Transaction Authorization Challenge | Resource to authorization server | An RS-described transaction and an AS-minted per-transaction token | Hybrid | Individual draft | A precise transaction without client-built RAR, but it adds an AS round trip |
| Durable task object | Above all of them | A durable, approved object the whole task binds to | Both | No standard yet | The piece none of the above provides |
Every row but the last standardizes an interface inside a single call. The last one is what the rest of this part is about.
The Gap Neither Model Closes
Several objects in this stack look like they might be the task, and none is. It is worth saying what each one is, and is not:
| Object | What it represents | What it does not represent |
|---|---|---|
| Access token | Authority a client can present | The whole task |
| PDP decision | Whether one call is allowed | A durable task lifecycle |
| Access request | A request to approve a denied action | Standing authority by itself |
| Held work | Pending work at a tool boundary | User-approved purpose |
| Mission | The governed task and its purpose | The local resource policy |
The first four are standardized in the stack today. The last is not. Both models can work well for one tool call to one MCP server. The trouble is never a single call. Per-call least-privilege can be locally correct and globally wrong. Every call is in bounds, and the task as a whole still ends up outside what the user approved, with no layer positioned to notice. The board-packet agent makes at least three calls across three MCP servers and three Authorization Servers, and may iterate within each. It may not even act alone, a planner can spawn sub-agents, so the fan-out runs across actors as well as calls, and the actor chain names who is acting, not the task they act under. What does that look like at the protocol layer?
In the token-side model, each new MCP server starts its own discovery cycle, and each AS sees only its own calls and operation vocabulary. Unless the deployment adds a shared task identifier and governance service, consent and audit remain local to each authorization domain. The client may accumulate several narrow, short-lived tokens, while each AS resolves the ontology problem independently.
In the resource-side model, each MCP server’s PDP evaluates calls with only its local context. Unless the deployment supplies a shared task identifier and lifecycle, requestable denials create separate tasks and audit records. Token churn disappears. Cross-server approval and audit fragmentation do not.
The root cause is structural. Both models build per-call authorization on a protocol stack with no first-class task object. AuthZEN standardized the decision, ARAP the denial-to-approval workflow, AROP and SEP-2848 the wire. None of them introduces an object for the work itself, so deployments fall back on proprietary transaction identifiers that correlate records without governing them.
The cost is not only operational, the repeated prompts, the orphaned tokens, the audit joined by timestamp and luck. It is a security boundary problem. The finance approval may allow Q3 financials for the board packet, but the document server cannot tell whether the draft it is creating is still inside that approved purpose, and the workflow server cannot tell whether the notice it is about to send carries only what the board-packet task approved or material that task never covered. Each server can authorize its local call correctly and still fail to preserve the user’s original intent across the task.
It is fair to ask whether this is a real problem or a tidy-minded one. Per-call least-privilege plus good logging catches a great deal. But catching is after the fact. The value of naming the task is that a server could refuse the drifting call in the first place, because it could weigh the call against the work the user approved instead of in isolation. Audit tells you the boundary was crossed. A task object is what lets a server hold it.
Why Correlation Is Not Governance
The obvious workarounds correlate, but they do not govern. They are observability, not authority. A shared transaction or trace identifier threads the calls together for debugging, but it carries no approval, no binding, and no lifecycle, so nothing can revoke or widen the task through it. A session keeps the work running across calls, but that is runtime continuity, not an approval record. A task hint passed in the RAR or the AuthZEN context is client-asserted text the resource has no reason to trust. The OAuth grant groups what one authorization server issued, not what one user approved across three of them. Each names the task in some weak sense. None lets a server decide whether a call is still inside the approved work. Better client orchestration, smarter SDKs, and richer log shipping help the same way, and close the structural gap the same amount, which is not at all. The protocol still does not name the task, so everything above it has to infer the task from indirect signals every time.
Whatever fills that gap, the requirements are the same on either model. Any candidate has to answer five questions that per-call authorization cannot:
- Identity. Does the task have a stable identifier that every participating server and authorization domain can reference, without itself becoming a cross-context correlator?
- Approval. Did the user approve the task once, against a description of what it will do, instead of re-approving each fragment?
- Binding. Can every token and every PDP decision be tied back to that task, so a credential or a permit names the work it serves?
- Expansion. When the agent needs authority the task did not anticipate, is there a governed way to widen it that preserves lineage, instead of spawning an unrelated approval?
- Audit. Can a reviewer reconstruct everything done under the task by its identifier, deterministically, instead of stitching logs by timestamp and client?
Picture the board packet with that object in place. At approval, the task gets an identifier. Every token the agent mints and every decision a PDP returns carries it. A server evaluating create_doc can check the call against the approved task, not just against the agent’s scope, and refuse a draft that has drifted outside it. Revoking the task stops the draft and the notify even though each call, taken alone, was permitted. The audit reads as one story under one identifier instead of three logs joined by timestamp. None of that requires a new grant type, and the task object is not the token. It is a separate, governed record that tokens and decisions reference, a name for the work they serve.
Those are the questions, not the answer. No standard object in the OAuth, AuthZEN, or MCP stack answers them today. MCP does define a task, but that is held work, a runtime handle for one pending call, not a governed record of the user’s approved purpose across many calls. One proposed model fits the requirements. In the broader Mission-Bound Authorization series, I call it a Mission, a durable, governed record of the approved task that every token and decision can point back to. What makes it trustworthy, where a task hint is not, is provenance. A hint is asserted by the client. A Mission is issued and governed by an authority, so a resource can rely on it the way it already relies on a token. These two parts do not define that object. Open-world OAuth needs a shaping step that turns a request into one (Open-World OAuth Still Needs Mission Shaping), and a session is not that object (Sessions Are Not Missions). Their job was to establish why per-call authorization, on either model, needs one.
Where to Start
The smallest useful pieces are independent. Each one pays for itself before the rest arrives.
- If you build MCP servers, put an authorization check at tool execution and use the same policy system to filter
tools/list. Treat filtering as exposure control. Always authorizetools/call. Use the AuthZEN Authorization API for the PEP-to-PDP contract so the decision does not depend on one policy engine, and publish a COAZx-coaz-mappingin each tool’s schema so any gateway or PDP can build the request from the tool definition. Two draft SEPs target the denied-but-requestable case from different ends. SEP-2643 standardizes a structured denial envelope, and SEP-2848 standardizes server-side asynchronous approval using held work. - If you run an Authorization Server for agent clients, publish RAR-type metadata so clients can discover supported
authorization_detailsschemas, and add resource-domain validation rather than assuming schema discovery gives the AS semantic knowledge. For denied-but-requestable decisions, adopt the Access Request and Approval Profile and watch the proposed AuthZEN Access Request OAuth Profile, which composes it with an explicit OAuth completion mechanism. - If you build an agent or orchestrator, you are the one who feels token selection, retry loops, task handles, and approval UX. Lean on resource-side decisioning and held work where you can, so the agent presents one credential and polls for completion instead of running the acquisition loop. Where authority has to travel, expect to cache tokens by the authority they carry, handle the challenge family, and resume out-of-band approvals without losing the thread of the task.
These pieces pay for themselves independently. But notice what none of them fixes: once a task spans more than one call, server, or authorization domain, you are still missing the object that names the task. Carry authority when it must travel, evaluate locally when context must stay local, standardize the decision and the denial workflow, and treat the absent task object as the next thing to build, not a detail to paper over with log correlation. Per-call least-privilege is necessary, but it governs calls, not the task they serve. Until something names the task, the user’s intent is the one thing no layer is positioned to protect.