GET /catalog walks agents through progressive disclosure: available
APIs with descriptions, then one API's tags, then a tag's endpoints,
then full detail for a single operation with $refs resolved inline.
Oversized tags (tag-poor upstreams) fall back to path-prefix groups,
drillable with ?prefix= and compressed through single-child chains.
Responses are filtered to the key's grants, carry ETags for cheap
revalidation, and reuse the discovery spec cache. Key auth is shared
with the docs portal via portal.resolve_api_key; 'catalog' and 'mcp'
are now reserved slugs.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Operations keep their upstream tags as the second grouping level, and
each service becomes an x-tagGroups entry (first level). Tag names
shared by several services are disambiguated with the service name.
The intro renders one section per service with the upstream spec's
title and info.description (the admin-entered description overrides).
The /docs renderer switches from Swagger UI to Scalar, which renders
x-tagGroups as a nested sidebar, keeps try-it-out, and gets the API
key pre-filled into its authentication panel.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GET /openapi.json (X-API-Key authenticated) merges the upstream OpenAPI
documents into one spec scoped to the calling key: only granted
operations, paths rewritten to gateway routes, component schemas
namespaced per service. GET /docs serves a Swagger UI portal that loads
the key-scoped spec and injects the key into try-it-out requests.
Discovery now caches the raw upstream spec documents (same 5-minute
TTL), and FastAPI's built-in /docs and /openapi.json are disabled in
favor of the portal routes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>