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
@@ -6,7 +6,7 @@ from fastapi.staticfiles import StaticFiles
from fastapi.responses import RedirectResponse
from sqlalchemy import text
from app import config, portal, proxy, retention, security
from app import catalog, config, portal, proxy, retention, security
from app.admin import routes as admin_routes
from app.admin import stats as admin_stats
from app.admin.deps import LoginRequired, login_redirect_handler
@@ -131,6 +131,7 @@ def health():
app.include_router(admin_routes.router)
app.include_router(admin_stats.router)
app.include_router(portal.router)
app.include_router(catalog.router)
app.mount("/static", StaticFiles(directory=str(config.BASE_DIR / "app" / "static")), name="static")
# The proxy catch-all (/{slug}/...) must come last so it never shadows
# /admin, /static, /docs or /health.