Discovery · Poppy · Personal Agent Protocol draft 0.1

How to write your poppy.json

Everything that goes in /.well-known/poppy.json for the Personal Agent Protocol, with three starter files and the mistakes that make personal agents reject it.

The key idea

poppy.json is a small pointer file. It must sit at /.well-known/poppy.json over https, name a domain that matches the one agents asked, and point to an OAuth server whose metadata vouches for that domain.

Every personal agent starts with one request: GET https://yourdomain.com/.well-known/poppy.json. This file tells it who you are, how sessions and sign-in work, and which interfaces it may use. It is the first thing to publish, and the only thing you need to be discoverable.

Where it lives

  • At https://{domain}/.well-known/poppy.json, where the domain is yours or a subdomain you control.
  • Over https. The URL may redirect to a copy hosted elsewhere, but every redirect must be to an https URL.
  • Served as JSON. Send caching headers (for example Cache-Control: public, max-age=3600): agents cache the file by them.

The smallest file

If you only want agents to know your website is there:

{
  "protocol_version": "0.1",
  "organization": { "name": "Example Shop", "domain": "example.com" },
  "web": {}
}

Agents then browse your site as ordinary signed-out visitors. No OAuth server is needed yet.

Every field

Field Required What it holds
protocol_version Yes "0.1" for this draft, as major.minor. Agents refuse a major version they don’t support.
organization Yes name to show users, and domain, which must match the host agents requested (a leading www. is ignored).
auth If you list agent, apis or a browser-session endpoint issuer, your OAuth issuer URL, plus one block per sign-in type you offer: direct, device, mediated.
auth.direct / auth.device If offered scopes: what that sign-in type can grant.
auth.mediated If offered endpoint that takes credentials, fields describing them (name, label, secret), and scopes.
auth.custom_scopes No A short description of each scope you define beyond poppy:read and poppy:write.
agent One of agent, apis or web protocols: each with a type (today poppy) and an https endpoint for conversations.
apis One of agent, apis or web A list, each with type (openapi or mcp), url and a short description.
web One of agent, apis or web Your website. The optional browser_session_endpoint is where an agent’s browser joins a session.
extensions No Extensions you support, keyed by name, each with a version (for example operations).

Any entry under agent, apis or extensions may add a resource if you want tokens issued for that one service. Agents ignore fields they don’t recognise, so you can add more later without breaking anyone.

Three starter files

Website plus sign-in. Users connect their account on your own sign-in page, then the agent browses your site signed in:

{
  "protocol_version": "0.1",
  "organization": { "name": "Example Shop", "domain": "example.com" },
  "auth": {
    "issuer": "https://auth.example.com",
    "direct": { "scopes": ["poppy:read", "poppy:write"] }
  },
  "web": { "browser_session_endpoint": "https://example.com/poppy/browser-session" }
}

An MCP server. The quickest API for agents. The MCP server must accept Poppy session tokens and point to your issuer in its protected resource metadata:

{
  "protocol_version": "0.1",
  "organization": { "name": "Example Shop", "domain": "example.com" },
  "auth": {
    "issuer": "https://auth.example.com",
    "direct": { "scopes": ["poppy:read", "poppy:write"] },
    "device": { "scopes": ["poppy:read"] }
  },
  "apis": [
    { "type": "mcp", "url": "https://mcp.example.com/mcp", "description": "Orders, returns and product search" }
  ]
}

Everything. APIs, your own agent, the website and a custom scope:

{
  "protocol_version": "0.1",
  "organization": { "name": "Example Shop", "domain": "example.com" },
  "auth": {
    "issuer": "https://auth.example.com",
    "direct": { "scopes": ["poppy:read", "poppy:write", "addresses"] },
    "custom_scopes": { "addresses": "Manage saved delivery addresses" }
  },
  "agent": {
    "protocols": [{ "type": "poppy", "endpoint": "https://api.example.com/poppy/conversations" }]
  },
  "web": { "browser_session_endpoint": "https://example.com/poppy/browser-session" },
  "apis": [
    { "type": "openapi", "url": "https://api.example.com/openapi.json", "description": "Orders, returns and exchanges" },
    { "type": "mcp", "url": "https://mcp.example.com/mcp", "description": "Product search and sizing" }
  ],
  "extensions": {
    "operations": { "version": "1", "endpoint": "https://api.example.com/poppy/operations" }
  }
}

The OAuth metadata it points to

Before using your file, an agent fetches your issuer’s OAuth metadata (RFC 8414, at /.well-known/oauth-authorization-server) and checks two things: the metadata’s issuer is exactly your auth.issuer, and its poppy_domains list includes your organization.domain. Without that second check, any website could name your OAuth server and receive tokens meant for you.

{
  "issuer": "https://auth.example.com",
  "token_endpoint": "https://auth.example.com/oauth/token",
  "revocation_endpoint": "https://auth.example.com/oauth/revoke",
  "authorization_endpoint": "https://auth.example.com/oauth/authorize",
  "poppy_domains": ["example.com", "example.co.uk"]
}

Several domains may name one issuer, such as a site per country. They then count as one company. More in Set up your OAuth server.

Mistakes agents reject

  • The domain doesn’t match. organization.domain says example.com but the file is served from shop.example.net. After a redirect, the host the file ends up on does not count; the host the agent asked does.
  • poppy_domains is missing from the OAuth metadata, or doesn’t list your domain.
  • The issuer differs by a character, such as a trailing slash in one document and not the other.
  • auth is missing while apis or agent is listed. Those need sessions, and sessions need auth.
  • A scope starts with poppy: but isn’t poppy:read or poppy:write. That prefix is reserved.
  • A redirect to http, or a file served as HTML.

The checker tests each of these and shows the fix.

Free Poppy checker

See what your domain needs for the Personal Agent Protocol, one step at a time.

Check your domain

Written against Personal Agent Protocol (Poppy, PAP) draft 0.1, which may change. Flow is not affiliated with the protocol's authors.