AI Blog

The token proves the agent, not the errand

Personal Agent Protocol draft 0.1 spends its rigour on identity — client keys, DPoP-bound tokens, an issuer that must match the discovery document — and then describes what the agent may do with two scopes plus whatever each company invents. Three access surfaces carry three credential strengths and one shared authorisation vocabulary, so "Poppy-compliant" says almost nothing about the blast radius.

By Agentic AI Wiki 13 min read

Draft 0.1 of the Personal Agent Protocol, published 9 October 2026, spends most of its normative weight on proving which agent is calling: an HTTPS client identifier, a public key, a session token bound to that key with DPoP, and a requirement that the issuer in the company's OAuth metadata match the issuer in its discovery document. Then it describes what the agent is allowed to do with two scopes — poppy:read and poppy:write — plus whatever each company invents under custom_scopes. The identity is cryptographic and portable. The permission is a word in a dropdown, and it means something different at every merchant you connect to.

At a glance

Meta and Sierra announced the protocol on 6 October and published the draft three days later, under a nickname — Poppy — that has already outrun the formal name. Reported design-partner counts and lists differ between write-ups; the draft itself is the part worth reading.

LayerWhat draft 0.1 specifiesHow testable it isWho decides the meaning
Discovery A document at /.well-known/poppy.json; agents must not use one whose major version they do not support Mechanical — fetch, parse, compare The protocol
Agent identity An HTTPS client identifier plus a public key Mechanical — signature verifies or does not The protocol
Issuer trust The issuer in the OAuth metadata (RFC 8414) must match poppy.json, and the domain must be listed Mechanical, and load-bearing: without it any domain could claim another company's issuer The protocol
Authorisation poppy:read for viewing orders and bookings, poppy:write for making changes, independent of each other, plus per-company custom_scopes Not testable — "making changes" is a category, not a contract Each company, separately
The Poppy draft 0.1 handshake A flow from a company's well-known poppy.json discovery document, through the agent's version and domain checks and the requirement that the OAuth metadata issuer match that document, to a user authorising scopes and a key-bound session token being issued. The token then reaches three access surfaces: the account API with DPoP proof of possession, an MCP endpoint with a resource-limited bearer token, and the browser, where a signed assertion is exchanged for ordinary session cookies. Draft 0.1: four checks on the connection, one distinction on the errand 1 · Discovery /.well-known/poppy.json published by the company 2 · Agent identity HTTPS client identifier and a public key 3 · Issuer must match OAuth metadata (RFC 8414) issuer == poppy.json 4 · User authorises poppy:read / poppy:write + company custom_scopes Session token bound to the agent’s key DPoP proof of possession replay needs the key Account API key-bound token, DPoP strongest of the three MCP endpoint bearer token, accepted only when resource == that API Browser signed assertion exchanged for ordinary session cookies the key stops here Steps 1–3 are cryptographic and testable. Step 4 is the only place the protocol says what the agent is allowed to do, and it offers two standard scopes plus whatever each company invents under custom_scopes.
Four checks before the token, and one choice after it. The asymmetry is the design.

The connection layer is genuinely good, and it is the part people will skip

It is worth being precise about what the draft gets right, because the criticism below is not that the authors were careless. Session tokens are bound to the agent's key with DPoP proof of possession, so a token lifted from a log or a compromised proxy is inert without the private key that minted the proof. Bearer tokens — the kind a stolen string replays perfectly — are accepted on exactly one surface, the MCP API, and only when the request's resource is that API's own URL. That is a tighter audience restriction than most production OAuth deployments manage.

The issuer check is the quietly important one. An agent must confirm that the issuer advertised in the company's OAuth authorisation-server metadata matches the issuer named in poppy.json, and that the domain appears in that document. Skip it and any domain can claim another company's issuer and collect tokens minted for it — a textbook confused deputy, with the agent as the deputy and your customer's account as the resource. It is also exactly the kind of check that gets dropped from a fast integration, because nothing fails when you omit it.

So the handshake is not the weak point. The weak point is that a protocol built this carefully around who is calling leaves what they were sent to do almost entirely to the implementer.

Two scopes is the whole authorisation model

Poppy access surfaces against four properties A matrix with the three Poppy access surfaces as rows and four properties as columns: replay protection, audience binding, revocation granularity, and how finely the grant distinguishes actions. The account API is strong on replay protection, the MCP endpoint is strong on audience binding, the browser surface is weak on both, and all three share the same weak action granularity of two standard scopes. Where draft 0.1 is strict, and where every row is the same replay protection audience binding revocation granularity action granularity Account API Strong (DPoP) Medium Per grant Weak: two scopes MCP endpoint Weak (bearer) Strong (resource) Per grant Weak: two scopes Browser session Weak (cookie) Medium (origin) Session-wide Weak: two scopes Strong Medium Weak Replay, audience and revocation are specified per surface and differ. The right-hand column does not differ, because poppy:read and poppy:write are the only standard distinctions and both are unbounded within their half. Assessment of draft 0.1 as published on 9 October 2026; the draft states it may change in breaking ways.
The first three columns were specified per surface. The fourth is the same everywhere, because there is only one answer in the draft.

poppy:read covers viewing account information — orders, bookings. poppy:write covers making changes, with exchanging an item given as the example. The two are independent, so a client that needs both requests both. That is a clean design for a consent screen and an unbounded one for a permission: inside poppy:write, changing a delivery address and cancelling a subscription are the same grant, and so is anything else the merchant's API exposes as a mutation.

The draft does provide an escape hatch — a company can declare its own scopes, and the published example document includes an addresses scope described as managing saved shipping addresses. This is the right pressure valve and the wrong place for the detail to live. The one thing a protocol exists to standardise is what a grant means, so that a user who has consented once at one merchant has learned something transferable about consenting at the next. Push that into custom_scopes and the user learns nothing: the dialogue says "manage your account" at every site and covers a different blast radius at each.

Compare what the agent-to-agent lineage did with the same problem. A capability description is a machine-readable statement of what an operation does, which is why capability discovery and agent cards spend their complexity on the verb rather than the caller. Poppy inherits OAuth's shape instead, and OAuth's scopes were always a human-readable label with a per-provider meaning — tolerable when a person clicked through once for a photo-sharing app, less so when the grantee is a loop that will exercise the grant a thousand times without being asked again.

Three ways in, and the traffic will take the weakest one

What each Poppy access surface carries Three columns comparing the credential each Poppy access surface carries: the account API uses a key-bound token with DPoP proof of possession, the MCP endpoint accepts a bearer token only when the resource matches that API's URL, and the browser surface exchanges a signed assertion for ordinary session cookies, after which no key is involved. Three ways in, three different things to steal Account API Key-bound session token with DPoP proof of possession A stolen token is useless without the key MCP endpoint Bearer token, accepted only when resource is that API’s own URL A stolen token works, but only at one audience Browser Signed assertion traded for ordinary session cookies A stolen cookie is a logged-in browser The cryptography degrades left to right; the authorisation is the same two scopes in all three columns.
What an attacker gets from each surface, left to right. The cryptography degrades; the authorisation does not change.

The draft describes three access surfaces, and they do not have equal properties. The account API carries the key-bound token with DPoP. The MCP endpoint takes a bearer token with the audience pinned to its own URL. Browser access works differently in kind: the agent exchanges a signed assertion for session cookies, and from that point it is holding what a logged-in browser holds. The key did its job at the door and then stepped out of the picture.

Predict where the volume goes. Publishing a conforming account API is a roadmap item for most merchants; exposing the existing web session to an agent is a small shim over infrastructure that already exists. The browser path will carry disproportionate traffic for the same reason screen-scraping carried it for a decade — it is the one that works on the stack you already shipped. That makes the weakest credential in the protocol the most common one in practice, and it puts the agent back in the position browser agents have always been in: ambient authority over everything the session can reach, with no per-action gate between the model and the mutation.

None of this is an argument against shipping the browser surface. It is an argument for not reading "Poppy-compliant" as a statement about security posture. Three surfaces with three credential strengths and one shared authorisation vocabulary means the compliance badge tells you almost nothing about which one a given integration uses.

What to do if you are the company publishing the document

The useful consequence of a two-scope model is that your own API becomes the policy surface. Everything the protocol declines to distinguish, you have to distinguish on the other side of the token.

  • Enumerate what poppy:write reaches, in writing, before you publish. Every mutation an agent-held token can perform is now in one bucket. If cancelling a subscription, changing a payout destination and redeeming a credit are all in that bucket, the protocol will not stop any of them and your consent screen implied one of them.
  • Declare custom scopes for the irreversible operations, not the convenient ones. The example document carves out saved addresses. The better use of the mechanism is the short list of actions you would want a separate, revocable, individually-logged grant for — refunds, payouts, deletions, anything with a counterparty.
  • Keep step-up confirmation on your side of the boundary. The draft defers finer permissions, which means for now the only place a high-value action can be gated is your own API. Treat an agent-originated mutation above a threshold the way scoped credentials for agents treats any privileged call: a separate authorisation, not a flag on the session.
  • Log the client identifier on every write and keep it queryable. The protocol hands you something genuinely new — a stable, cryptographically-proven identity for the calling agent. That is the join key for a decision receipt, for revoking one agent without revoking a category, and for answering the first question anybody asks after an incident.
  • Treat your own rate limits and error bodies as an agent interface. A 429 is a pause rather than a signal to an automated caller, and your error text is now a prompt. The engineering is the same whatever protocol delivered the request — see serving agent traffic.

What is not there yet, and why that matters for your timeline

Draft 0.1 says plainly that any part of it can change before a stable version, including in ways that are not backward compatible — and the documentation is published under Apache 2.0, which is a good sign about intent and no sign at all about stability. Implementers building against it this week report three concrete absences: no JSON Schema for the discovery document, no official conformance suite, and no published reference implementation, with design workshops and a reference implementation expected in the following weeks.

Payments, push notifications and finer-grained permissions are explicitly not covered. The partner lists reported around the announcement include payment networks, which is worth holding loosely: a design partner is not a specified feature, and the two get conflated fast in coverage. The honest status is a draft with notable backing and three of its most consequential surfaces deferred.

The practical read: publishing a poppy.json and an account API is cheap and reversible, and doing it now buys you position. Writing the grant semantics your product needs into a protocol that has not specified them is the part that will have to be redone, so put that logic in your own authorisation layer where a spec revision cannot invalidate it. That is the standing advice for protocol revisions, and a 0.1 with a stated licence to break is the case it was written for.

FAQ

Is Poppy a replacement for MCP?

No. It assumes MCP: one of its three access surfaces is an MCP endpoint, with bearer tokens accepted only when the request's resource is that endpoint's URL. Poppy answers how a user's agent gets authorised against a business it does not have a prior relationship with; MCP answers how a tool is exposed once it is.

Does the DPoP binding mean a stolen token is harmless?

On the API and conversation surfaces, a stolen token alone cannot be replayed without the agent's private key, so the attack shifts to stealing the key or using the agent as a proxy. On the browser surface the credential is a session cookie, and that one replays exactly as cookies always have.

Can we implement against draft 0.1 today?

Mechanically yes, and several independent implementations already exist. With no JSON Schema and no conformance suite published, "conforming" is currently your own reading of prose, so pin the draft version you built against and expect a breaking revision.

What should we not put behind poppy:write?

Anything you would not grant for a year in a single click: refunds, payout-destination changes, subscription cancellation, account deletion, anything that moves money to a third party. Those belong behind a custom scope or a step-up confirmation in your own API.

Does this settle the agent-identity question?

It settles the easier half. The caller is now provable; the errand is not described anywhere a machine can check it. Until a grant carries a machine-readable statement of the operation it permits, the authorisation decision stays on the resource server, which is where it has always actually lived.

Further reading

On this wiki:

Sources:

  • Personal Agent Protocol specification, draft 0.1 (published 9 October 2026; documentation licensed Apache 2.0), and Sierra's accompanying announcement
  • Contemporaneous coverage of the 6 October announcement by Meta and Sierra and of the 9 October draft, which differ on design-partner lists
  • Independent implementation notes from projects integrating draft 0.1, reporting the absent JSON Schema, conformance suite and reference implementation