Add hierarchical key-scoped catalog API for machine consumers

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>
This commit is contained in:
Samuel Amar
2026-09-02 11:39:07 +02:00
co-authored by Claude Fable 5
parent b90ecaf61c
commit 9a3feccc90
5 changed files with 352 additions and 4 deletions
+2 -1
View File
@@ -13,7 +13,8 @@ router = APIRouter(prefix="/admin")
templates = Jinja2Templates(directory=str(config.BASE_DIR / "app" / "templates"))
# Slugs the proxy catch-all must never claim
RESERVED_SLUGS = {"admin", "static", "health", "docs", "redoc", "openapi.json"}
RESERVED_SLUGS = {"admin", "static", "health", "docs", "redoc", "openapi.json",
"catalog", "mcp"}
def build_tree(endpoints: list[Endpoint]) -> dict: