Skip to content

Show descriptions for public/free endpoints on server pages - #1030

Merged
onchainlu merged 4 commits into
mainfrom
public-endpoint-descriptions
Jul 15, 2026
Merged

Show descriptions for public/free endpoints on server pages#1030
onchainlu merged 4 commits into
mainfrom
public-endpoint-descriptions

Conversation

@onchainlu

@onchainlu onchainlu commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Problem

Merchant report: free catalog endpoints (security: [] public, apiKey, SIWX) show no description in the Resources list, and there's no way to set one. Paid endpoints get theirs from the 402 response's accepts[].description / resource.description.

Root cause

Free resources have no 402 response — listOriginsWithResources returns data: {} for them, so getDescription() always came back empty. The description was being dropped at the very start of the chain: @agentcash/discovery already folds each openapi operation's summary ?? description into endpoint.summary, but fetchDiscoveryDocument never mapped it into DiscoveredResource, so registration never saw it.

Fix

  • fetch-discovery maps the discovery summary into DiscoveredResource.description, dropping the package's "METHOD /path" placeholder (emitted when the merchant set neither summary nor description — noise next to the route itself) and capping at 500 chars (external origins control this text).
  • Registration threads it into Resource.metadata.description, following the existing free-row metadata pattern (authMode, pricingMode, price) — no schema migration. Paid rows store it too via the same metadata merge, as a display fallback.
  • The resource Header renders the 402-body description first, falling back to metadata.description (cleaned with cleanExternalText, clamped to two lines). Empty-string 402 descriptions also fall through.

Merchants set it in their openapi spec: operation summary (preferred) or description. Existing rows pick it up on the next (re-)registration of the origin.

Known limitation (matches existing pricingMode/price merge semantics): removing the text from the spec doesn't clear a previously stored value on re-register.

Verification

  • New test in register-origin.test.ts (written failing-first) asserting descriptions flow into registerFreeResource (public + siwx) and registerResource (paid) options.
  • New endpoint-description.test.ts covering placeholder filtering and the 500-char cap.
  • npx vitest run: 193 passed (16 files). pnpm format && pnpm lint && pnpm check: clean.

Free resources (siwx/public/apiKey) have no 402 response, and the
Resources list sourced descriptions exclusively from the parsed 402
body — so catalog rows always rendered an empty description, with no
way for merchants to set one.

The discovery package already folds each openapi operation's
summary ?? description into endpoint.summary; fetch-discovery simply
dropped it. Now:

- fetch-discovery maps it into DiscoveredResource.description,
  filtering the package's 'METHOD /path' placeholder
- registration stores it in Resource.metadata alongside the existing
  free-row fields (authMode, pricingMode, price); paid rows store it
  too via the same metadata merge
- the resource Header falls back to metadata.description (cleaned via
  cleanExternalText) when the 402 body has no description, clamped to
  two lines

Existing rows pick the description up on their next (re-)registration.
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
x402scan Ready Ready Preview, Comment Jul 15, 2026 2:36pm

Request Review

External origins control the description text — cap what registration
persists into Resource.metadata at 500 chars. Also reverts two files
that a repo-wide format pass reflowed without any code change.
@onchainlu
onchainlu merged commit 593b4a2 into main Jul 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant