Personal Agent Protocol draft 0.1 was published on 9 Oct 2026 · What goes in poppy.json →
PAP Checker/Sites/stacktr.ee
PAP discovery report

stacktr.ee

Publishes a poppy.json with 1 problem to fix. Organization: Stacktree.

Publishes poppy.json, with problems
1problem
HTTP 200 Version 0.1 Sign-in direct Routes APIs Checked 3 hours ago First seen 16 Oct 2026
Open poppy.json ↗
Findings1 problem · 14 passed
Discovery
OK
poppy.json published
Served over HTTPS at /.well-known/poppy.json.
§3
OK
Protocol version 0.1
A major.minor version this checker reads.
§3.1
OK
organization.domain matches the host that serves it
It must be the host that serves the document, after any redirects, compared ignoring case.
§3.1
Sign-in
OK
OAuth issuer: https://api.stacktr.ee
An HTTPS issuer identifier.
§3.1
OK
Sign-in types: direct
How a user can sign in through a personal agent.
§4.4
Sign-in server
OK
OAuth server metadata published
Found at the issuer (RFC 8414).
§3.2
OK
issuer matches auth.issuer
Exact match, as agents must check.
§3.2
OK
poppy_domains lists stacktr.ee
The issuer confirms this domain may use it.
§3.2
Problem
dpop_signing_alg_values_supported is missing
Companies must publish the algorithms they accept for DPoP Proofs (RFC 9449 §5.1), and the list must include ES256. Personal agents sign proofs with an algorithm from it.
How to fix →
§3.2, §4.3
OK
token_endpoint published
Issues Session and Account Tokens.
§3.2
OK
revocation_endpoint published
Revokes Account Tokens (sign-out).
§3.2
OK
authorization_endpoint published
Starts Direct Sign-In.
§3.2
Routes
OK
Offers: APIs
At least one of agent, apis or web is listed.
§3.1
APIs
OK
apis[0]: MCP server names the company's issuer
Its protected resource metadata lists auth.issuer in authorization_servers, so MCP clients can sign in.
§6
OK
apis[1]: OpenAPI 3.1.0 description
Reachable, and a version the draft allows (3.0 or 3.1).
§6

poppy.json as served

0.7 KB
{
    "protocol_version": "0.1",
    "organization": {
        "name": "Stacktree",
        "domain": "stacktr.ee"
    },
    "auth": {
        "issuer": "https://api.stacktr.ee",
        "direct": {
            "scopes": [
                "poppy:read",
                "poppy:write"
            ]
        }
    },
    "apis": [
        {
            "type": "mcp",
            "url": "https://api.stacktr.ee/mcp",
            "description": "Publish a page to a private link that opens with no account, update it in place, and see who opened it and what they commented."
        },
        {
            "type": "openapi",
            "url": "https://api.stacktr.ee/openapi.json",
            "description": "The same over REST: publish (POST /sites, JSON or a file), update, passcodes, named links, opens (GET /sites/{id}/activity) and comments."
        }
    ]
}

OAuth server metadata as served

5.2 KB
{
    "issuer": "https://api.stacktr.ee",
    "authorization_endpoint": "https://api.stacktr.ee/oauth/authorize",
    "token_endpoint": "https://api.stacktr.ee/oauth/token",
    "registration_endpoint": "https://api.stacktr.ee/oauth/register",
    "revocation_endpoint": "https://api.stacktr.ee/oauth/revoke",
    "response_types_supported": [
        "code"
    ],
    "grant_types_supported": [
        "authorization_code",
        "refresh_token"
    ],
    "code_challenge_methods_supported": [
        "S256"
    ],
    "token_endpoint_auth_methods_supported": [
        "none",
        "client_secret_post",
        "client_secret_basic"
    ],
    "scopes_supported": [
        "sites:write",
        "sites:read"
    ],
    "resource_indicators_supported": true,
    "response_modes_supported": [
        "query"
    ],
    "service_documentation": "https://stacktr.ee/docs",
    "agent_auth": {
        "skill": "https://stacktr.ee/auth.md",
        "register_uri": "https://api.stacktr.ee/oauth/register",
        "identity_types_supported": [
            "oauth_client",
            "anonymous",
            "wallet"
        ],
        "credential_types_supported": [
            "oauth_access_token",
            "api_key",
            "wallet_signature",
            "claim_token"
        ],
        "mcp_endpoint": "https://api.stacktr.ee/mcp",
        "mcp_credential_types_supported": [
            "oauth_access_token",
            "api_key"
        ],
        "registration_methods": [
            {
                "type": "oauth_dynamic_client_registration",
                "description": "RFC 7591 Dynamic Client Registration. The standard path for MCP connectors (e.g. claude.ai). Register, then run the OAuth 2.1 + PKCE authorization-code flow.",
                "register_uri": "https://api.stacktr.ee/oauth/register",
                "authorization_uri": "https://api.stacktr.ee/oauth/authorize",
                "token_uri": "https://api.stacktr.ee/oauth/token",
                "revocation_uri": "https://api.stacktr.ee/oauth/revoke",
                "code_challenge_methods_supported": [
                    "S256"
                ],
                "scopes_supported": [
                    "sites:write",
                    "sites:read"
                ]
            },
            {
                "type": "api_key",
                "description": "Long-lived API key (stk_live_...) for server-side or CLI agents. Create one in the dashboard and send it as a bearer token. Accepted on every REST route AND on the MCP endpoint at https://api.stacktr.ee/mcp, so an agent with a key needs no browser and no OAuth flow to speak MCP.",
                "register_uri": "https://app.stacktr.ee/api-keys",
                "credential_format": "Authorization: Bearer stk_live_...",
                "mcp_endpoint": "https://api.stacktr.ee/mcp"
            },
            {
                "type": "device_code",
                "description": "OAuth 2.0 Device Authorization Grant (RFC 8628), for an agent that has a human to ask but no browser to drive. POST the device-code endpoint (no auth) for { device_code, user_code, verification_url_complete, interval }; print the URL for the human; poll the poll endpoint every \"interval\" seconds until it answers { status: \"authorized\", api_key }. The key is handed over exactly once and belongs to the human's account, on their plan. Codes live 10 minutes; rate limited per IP.",
                "device_authorization_uri": "https://api.stacktr.ee/api-keys/device-code",
                "token_uri": "https://api.stacktr.ee/api-keys/device-code/poll",
                "verification_uri": "https://app.stacktr.ee/connect/cli",
                "credential_format": "Authorization: Bearer stk_live_..."
            },
            {
                "type": "anonymous",
                "description": "No registration. POST a file to the publish endpoint with no Authorization header to get a private, unguessable URL that lives 24 hours.",
                "endpoint": "https://api.stacktr.ee/sites"
            },
            {
                "type": "payment",
                "description": "Pay to provision a persistent identity with no human in the loop. The payment is the credential. GET the endpoint for the rail menu (which agentic-commerce protocols are live); POST the payment to receive an stk_live_ API key once. The key carries free-tier limits (3 pages in total, each expiring after 7 days, no email gates; passcodes do work); POST /unlock buys past them. Accepted protocols: x402 (USDC), MPP, ACP (Stripe shared payment token), AP2.",
                "endpoint": "https://api.stacktr.ee/provision",
                "protocols_supported": [
                    "x402",
                    "mpp",
                    "acp",
                    "ap2"
                ]
            },
            {
                "type": "wallet_signature",
                "description": "No registration and no key: the wallet that PAID for a page (x402 pay-per-publish) is its update credential. POST {\"wallet\":\"0x…\"} to the challenge endpoint, personal_sign (EIP-191) the returned message with that wallet, then send \"Authorization: Wallet challenge=…,sig=0x…\" on PUT /sites/{id}. Challenges are single-use, 5-minute TTL. Scope: content updates to pages carrying that payer wallet (adopted pages while the wallet stays account-linked). EVM EOA wallets only.",
                "endpoint": "https://api.stacktr.ee/wallet-auth/challenge"
            },
            {
                "type": "claim_token",
                "description": "No registration, no key, no wallet: the claim_token returned by an anonymous publish is that page's update credential while the page is unclaimed. Send \"Authorization: Claim <claim_token>\" on PUT /sites/{idOrSlug} with a JSON body {\"html\": \"...\"} (multipart with a \"file\" field also works). Works on every rail, including Solana x402 payers, who cannot use wallet_signature. Scope: replacing the content of that one page, nothing else. It stops working the moment the page is claimed (claiming rotates the token into the account), when the page expires, and for a blocked actor. Rate limited per IP and requires a direct client connection.",
                "endpoint": "https://api.stacktr.ee/sites/{idOrSlug}",
                "credential_format": "Authorization: Claim <claim_token>"
            }
        ]
    },
    "poppy_domains": [
        "stacktr.ee"
    ],
    "poppy_grant_types_supported": [
        "urn:ietf:params:oauth:grant-type:jwt-bearer",
        "authorization_code",
        "refresh_token"
    ],
    "poppy_token_endpoint_auth_methods_supported": [
        "private_key_jwt"
    ],
    "poppy_scopes_supported": [
        "poppy:read",
        "poppy:write"
    ],
    "poppy_dpop_signing_alg_values_supported": [
        "ES256",
        "RS256"
    ]
}

Rules from Personal Agent Protocol draft 0.1 (with changes through 16 Oct 2026). Section numbers refer to the specification. The draft can change before a stable version; see the path to 1.0.