(motir-marketing) /docs/mcp/tools renders the PUBLISHED catalogue through lib/docs.ts — the list returns, and the copy does not
Type · code · motir-marketing · ONE PR · the CONSUMER half of the tool-catalogue seam · blocked_by MOTIR-4194
Why this exists · MOTIR-4180 removed an unguarded hand-copy of motir-core's tool registry from this page — 24 of 55 names in five groups matching no permission — because nothing in this repository could check it. That was the right fix for the defect and it left the surface poorer: Motir currently publishes no tool catalogue anywhere. MOTIR-4194 serves the artifact; this card renders it.
The shape — it already exists in this repository, one page over
/docs/api is the template, and following it is the whole card: lib/docs.ts:fetchOpenApiSpec fetches ${APP_ORIGIN}/api/openapi/v1.json at request time, app/docs/api/page.tsx is export const dynamic = 'force-dynamic', and nothing is committed. Do that, for the catalogue. A reader beside fetchOpenApiSpec, a page that renders what it returns, and no list in the repository.
⚠️ The one thing this card must not do
Do not commit a fallback list. A hard-coded array behind an if (!res.ok) is the exact defect MOTIR-4180 removed, re-entering through the door marked resilience — and it is worse than the original, because it renders only when the truth is unreachable, so it is stale precisely when it is displayed and nobody sees it go wrong. fetchOpenApiSpec already models the right behaviour: it throws when the artifact is unreachable. Do the same. A docs page that fails loudly beats one that lies quietly.
tests/docs/docs.test.ts currently asserts that neither /docs/mcp page names any tool (MOTIR-4180's toolNameLiterals limb). That guard stays, and it must still pass — which it will, because the names arrive at request time and are never written into the source. If it goes red, a copy has come back.
Scope
- A catalogue reader in
lib/docs.ts— typed, fetched from the published path MOTIR-4194 serves,revalidate: 0, throws when unreachable. app/docs/mcp/tools/page.tsxrenders it: the groups as the document orders them, the tools within each, each with its summary.force-dynamic, as/docs/apiis.- The page's header comment and
lib/docs.ts's — both rewritten by MOTIR-4180 to say "there is no artifact to consume" — updated, because that stops being true here. Both files say in as many words what this card is meant to do; read them first. - Prose kept where it is still true: the live
tools/listis still the authoritative surface, and what a token may call still depends on its grant.
Acceptance criteria
(Ordering: every criterion is true at PR-open in motir-marketing; none reads main, a merge or a deploy. Repository: motir-marketing alone — the endpoint is MOTIR-4194's.)
/docs/mcp/toolsrenders every tool the published document carries, grouped as the document groups them — no group label and no tool name is authored in this repository.- No committed fallback, no default array, no fixture rendered on failure. The reader throws when the artifact is unreachable, asserted by a test that stubs a non-OK response and expects a throw.
tests/docs/docs.test.ts'stoolNameLiteralslimb (MOTIR-4180) is unchanged and still green — the page source names no tool. If satisfying criterion 1 requires touching that limb, the implementation is wrong, not the guard.- The parse the page renders through is asserted against a fixture, so a shape change in the served document fails here rather than silently rendering an empty catalogue — the same discipline the OpenAPI limb already applies.
- The existing OpenAPI limbs are untouched and still pass.
- Both header comments (scope item 3) describe what now ships.
pnpm lint · format:check · typecheck · build · testpass. The page composes existing primitives and tokens; if it introduces any ink/ground pair not already rendered on--el-page-bgelsewhere in/docs, say which and measure it — otherwise state that it introduces none.- The PR body carries a How to test: the route, what a reader should see, and how to observe the failure mode (point
NEXT_PUBLIC_MOTIR_APP_ORIGINat an origin serving no catalogue and confirm the page fails rather than rendering a stale or empty list).