Skip to content

561 Group · Engineering

One catalog, five machine faces: MCP, A2A, ActivityPub, llms.txt and x402 discovery

One 130-offer catalog compiles into x402 discovery, an MCP server, an A2A agent card, an ActivityPub outbox and llms.txt so agents find the same prices.

Engineering

One catalog, five machine faces: MCP, A2A, ActivityPub, llms.txt and x402 discovery

Agents discover paid APIs through whatever door their framework opens: an MCP server, an A2A agent card, an ActivityPub actor, an llms.txt file, or the x402 /.well-known/x402 document. The Red Cup seller at market.561.group keeps one authored catalog of 130 offers and compiles every one of those doors from it, so no door can quote a different price, route or input schema than another. This article walks through each face with the live URLs and the one command that produces them all.

Why not write each discovery document by hand?

Every agent-discovery format invites a hand-maintained list. MCP wants tool descriptions, A2A wants skills, llms.txt wants links, OpenAPI wants paths, a directory wants resources. A seller with 130 offers and five formats has 650 chances for the price in one place to disagree with the price in another, and an agent that sees two prices will believe the cheaper one and be refused by the 402. The remedy is the oldest one in software: one source, many projections.

In the market repository, the only author-editable offer list is data/catalog.json. A script, scripts/compile-catalog.mjs, derives the compiled declarations, the content identities and the ActivityPub outbox from it. The repository's own documentation is blunt about it: the compiled files are "generated outputs derived by scripts/compile-catalog.mjs; neither is a separate author-editable offer catalog", and a hand-edit to a generated file is forbidden by the operating procedure. Offers that are proposed but not yet qualified stay listed:false with saleStatus:"held" so that no projection can leak a held route into live charging.

What are the faces, and where do I find each one?

FaceLive URLWhat an agent gets
x402 discovery`/.well-known/x402`x402Version: 2, 130 resources with URL, method, price, asset, network, input and output schemas
Catalog`/v1/catalog`The richest record: schemas, examples, pricing tariff, content-addressed sku, cell and law
OpenAPI`/openapi.json`OpenAPI 3.1.1 derived from the same catalog used for execution
A2A agent card`/.well-known/agent-card.json`Protocol 0.3.0 card with 130 skills, one per offer
MCPPOST https://market.561.group/mcpThree read-only tools: list_apis, search_apis, get_api
ActivityPub`/actors/market`A Service actor whose outbox holds 130 public Offer activities
llms.txt`/llms.txt`One line per offer: link, method, price, description

The first five of those are the "faces" in the title; the catalog and OpenAPI are the structured source projections they share.

The x402 discovery document

/.well-known/x402 is a JSON document of resource descriptions. Each entry has the shape a crawler or a directory needs to list it without calling the endpoint:

json
{ "url": "https://market.561.group/v1/data/json-pointer", "method": "POST",
  "name": "RFC 6901 JSON Pointer", "price": "$0.0012",
  "pricing": {"mode": "canonical-json-byte-bands", "...": "..."},
  "asset": "0x8335…2913", "network": "eip155:8453",
  "inputSchema": {"...": "..."}, "outputSchema": {"...": "..."} }

(Shape from the live document; fields abbreviated. The asset is the USDC contract on Base, shortened here.) The advertised price is the starting price; for byte-priced offers see Per-byte pricing. It is a preview. The seller says so everywhere: "the current 402 challenge is authoritative".

The MCP server

The MCP face is stateless and read-only. It answers JSON-RPC at /mcp, supports protocol versions 2026-07-28 and 2025-06-18, requires no session or handshake from modern clients, and exposes three tools annotated readOnlyHint: true. It performs no payment, no proxying and has no side effects; its source says so in the header comment. You can list the tools with the legacy version header:

bash
curl -s -X POST https://market.561.group/mcp \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -H 'MCP-Protocol-Version: 2025-06-18' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

and search the catalog by capability:

bash
curl -s -X POST https://market.561.group/mcp \
  -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \
  -H 'MCP-Protocol-Version: 2025-06-18' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_apis","arguments":{"query":"belnap","limit":2}}}'

On 2026-10-22 that search returned one structured result: the FOUR Evidence Name Conversion offer with its SKU, route /v1/four/reading-convert, preview price $0.001 and the producing package export. The server does not execute offers. It finds them; the agent then makes an ordinary x402 call. Requests are capped at 32 KiB and results at 40 per page. A modern-protocol request with mismatched headers is refused with HeaderMismatch, which we saw when we sent the 2026 version without its companion metadata headers: the server validates rather than guesses.

The A2A agent card

The agent card at /.well-known/agent-card.json declares protocolVersion 0.3.0, preferredTransport, no streaming, and 130 skills. Each skill has an id (for example publications/the-x402-economy), a name, a description, tags and example requests. It is a directory entry for agents that discover peers by card. It is not a task endpoint; paying and calling still go through the routes.

The ActivityPub outbox

Following ActivityPub convention, the market has a Service actor at https://market.561.group/actors/market, WebFinger at /.well-known/webfinger?resource=acct:market@market.561.group, and an outbox. The outbox is an OrderedCollection with totalItems: 130 and first/last links to 13 OrderedCollectionPages. Pages are bounded by item count (12) and by bytes (192 KiB), so a fediverse peer never has to fetch a multi-megabyte first page. Each item is an Offer activity addressed to Public whose object is a document of media type application/sen+cbor, named by an RFC 6920 content address:

json
{ "type": "Offer",
  "actor": "https://market.561.group/actors/market",
  "to": "https://www.w3.org/ns/activitystreams#Public",
  "object": { "type": "Document", "mediaType": "application/sen+cbor",
              "name": "ni:///sha-256;2Aafngw-StdkoQAmUKatPhGcduQ-oIO3Dyt5csPRT8Q" },
  "attachment": { "type": "Link", "name": "A2A Agent Card",
                  "href": "https://market.561.group/.well-known/agent-card.json" } }

(The object.url field, a base64 data URI carrying the CBOR, is omitted.) The outbox builder refuses to start if an activity is non-public, from a foreign origin, duplicated, or not an Offer. See content-addressed names for what the ni: name commits to.

llms.txt

/llms.txt lists every offer as a Markdown bullet with its link, METHOD route, price per call and description, under a one-sentence blockquote that tells a language model how to obtain a payment challenge. A model with browsing but no protocol support can read it, pick a route and follow the instructions to inspect the 402.

How does the agreement get enforced?

Three mechanisms keep the faces equal:

  1. One compile. npm run compile regenerates the compiled offers, the static Worker imports and the ActivityPub outbox together. A checker, npm run check:catalog, verifies that the source catalog and the compiled identities agree.
  2. A receiving audit. npm run receive checks the public release against the admitted seller catalog: fresh /v1/status and /v1/catalog, the unpaid 402 challenge of each listed route, and the payee, network and asset, with an independently supplied expected payee (Never trust the payee).
  3. Content addresses. Each catalog entry carries sku, cell and law as ni: names. The same SKU is returned by the MCP search_apis result, so a client can confirm that the MCP face, the catalog and the outbox describe the same offer without parsing prose.

The faces still can disagree on availability in time (a deploy may update the Worker before a cache expires), so the 402 challenge on the route itself is the final authority for price. That is why the previews all say "preview".

What does this cost the seller to maintain?

Almost nothing per format, which is the point. The catalog schema is one JSON Schema (schemas/offer.schema.json in the engine). An offer must name the typed operation it sells by its compute binding (package, export, argument projection), and may name its input admission and its scientific evidence. A new offer is one catalog entry; the compile step projects it into every face. The engine's declareCatalog refuses a route or gateway/operation declared twice.

What is not claimed?

Listing in a directory is not demand. The market's own procedure states that "a listing or HTTP 402 does not establish a customer purchase" and that a self-purchase "is not external demand". We report 130 offers and say nothing about buyers.

Start with what a seller should do beyond the spec for the other policies, or follow the Belnap-valued logic offers that the search example found.

Contents

Explore

Tagged

  • x402
  • mcp
  • a2a
  • activitypub
  • llms-txt
  • agent-discovery