# Protocol-native approvals: the AI agent approval workflow in your MCP client

flowifai's approval gate is server-side: a gated tool call pauses until an eligible
human approves it in the console. Protocol-native approvals make that AI agent
approval workflow feel native in the MCP client itself — the approval link is
delivered over the MCP wire, the human approves in the console, and the client
completes the call. No copy-pasting references, no polling by hand.

## What you see, step by step

In a supported client (say, Claude Code):

1. The agent calls a gated tool. Instead of a plain "pending" text result, flowifai
   answers with a protocol-level URL elicitation carrying the approval deep link.
2. The client surfaces it to you: an approval is required, with a link into the
   flowifai console inbox for exactly this request.
3. A human opens the link and approves (or denies) in the console — same console, same
   policy checks, same audit trail as always.
4. flowifai notifies the client that the elicitation is complete; the client retries
   the tool call, the broker executes the approved action exactly once, and the agent
   gets the real result.

If the request is denied, expires, or is revoked, the retry returns that outcome
instead — the agent is never left hanging.

> **How completion reaches your client.** flowifai emits a spec-standard
> `notifications/elicitation/complete` when the decision lands, and also answers a
> lightweight status poll, so the retry that finishes the call is driven by whichever your
> client supports. In current clients the loop converges on the client's own retry after
> approval; the push notification is there for clients that consume it. Either way you never
> poll by hand, and the decision is always made server-side — the client never approves.

## Client support matrix

| MCP client | Protocol-native approval loop |
| --- | --- |
| Claude Code ≥ 2.1.76 | Full loop: approval link surfaced in-client, call completes after approval |
| VS Code ≥ 1.107 | Full loop: approval link surfaced in-client, call completes after approval |
| Cursor | Not yet — pending text + manual retry |
| Claude Desktop | Not yet — pending text + manual retry |
| Windsurf | Not yet — pending text + manual retry |

Support is verified per client family, not assumed from capability flags. The
allowlist is config-extendable (`FLOWIFAI_ELICITATION_CLIENTS`) as more clients ship
support.

## Graceful degradation

Clients outside the matrix lose nothing they had before. On a gated call they receive
today's pending text: the approval reference plus instructions to call the same tool
again with the same arguments and the `__approval_ref` parameter set. A human approves
in the console exactly as in the full loop; the agent (or you) retries and the call
completes. The gate, the policy, and the audit trail are identical — only the delivery
of the approval link is less integrated.

flowifai never blocks on any client's adoption: the protocol-native path activates
only when a session negotiates the required MCP protocol revision *and* the client is
on the verified allowlist. Every other session keeps the baseline behavior unchanged.

## Delivery, not authorization

The elicitation dialog is never the security boundary. What the client "accepts" is
consent to open a URL — nothing more. The approval decision itself:

- is made in the flowifai console by an eligible approver, authenticated as a human
  user distinct from the agent's machine identity;
- is checked against your policy (n-of-m approvals, approver groups, one-deny veto);
- is recorded in the append-only audit log, in the same transaction as the state
  change.

No MCP client response — accept, decline, or anything a compromised agent might forge —
can authorize execution. A client that mishandles the elicitation can only make the
approval link less convenient to reach; it cannot approve anything.

## About the spec's "same user" expectation

The MCP elicitation spec expects the user completing an elicitation to be the user
interacting with the client. flowifai deliberately reconciles this with its
separation-of-duty model: the person approving is often *not* the person (or agent)
that initiated the call — that is the product, not a violation. The reconciliation
holds because the URL itself grants nothing: it points at an org-gated console page,
any org member may view it, only eligible approvers may decide, and every decision is
server-side and audited. Delivering the link to the initiating user is a convenience;
authorization never travels through the client.

## Spec status

This behavior tracks the MCP specification revision 2025-11-25 (URL-mode elicitation),
which is a pre-final revision — a follow-up spec revision is expected, and URL
elicitation carries forward in it. flowifai's promised invariant is the degradation
contract above: supported clients get the integrated loop, everything else keeps the
plain pending-text behavior, and the server-side gate is identical in both.

## Related

- [Core concepts](/docs/core-concepts/) — the ticket lifecycle behind the loop
- [Security model](/docs/security-model/) — why the gate lives server-side
- [Quickstart](/docs/quickstart/) — set up your first gated call