Neues pageListQuerySchema (ISO 8601, Kulanz für Datum ohne Zeit),
Query-Parameter auf interner und Public-API-Seitenliste, Prisma-where
mit gte; neue Indizes (pondId, createdAt)/(pondId, updatedAt) als
Migration. OpenAPI-Parameter, MCP-Parität (list_pages
created_since/updated_since), Doku (api-guide, mcp-guide,
public-api.md), DB-Test inkl. 400 bei ungültigem Datum.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0155v2aT8AG1kZDQEZiCLBWC
The slug-based machine surfaces now see and shape the hierarchy:
- REST: page list/detail carry parent (the parent page's slug, nulled
when the token's user may not read it — same no-leak rule as the
internal list); create accepts parent; PATCH accepts parent
(slug nests, null moves to the top level, appended at the end of the
new sibling group via the new PagesService.moveToEnd). Cycle/depth
refusals keep their regular error codes. OpenAPI updated.
- MCP: list_pages returns parent, create_page takes an optional parent
slug, update_page moves with parent (slug|null); tool errors carry
the api code (page_cycle covered in the e2e pack).
- ZIP export deliberately stays flat — noted in features.md; the
hierarchy is organizational only.
e2e: REST pack covers nested create, list shape, move/root-move, 409
page_cycle, 404 unknown parent; MCP pack covers nested create, list
parent, and the cycle tool error.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
AI clients talk to the instance directly at /api/mcp — under the /api/
path (deviation from the issue's literal /mcp) so every existing reverse
proxy already routes it; no deployment changes anywhere.
- Transport: official @modelcontextprotocol/sdk server, STATELESS — each
POST builds a fresh server+transport pair, no session store, replicas
stay trivial; GET/DELETE answer 405. Auth per PAT bearer (#104 tokens),
per-token rate limit (429 + Retry-After).
- Own switches, independent of REST: instance mcp.enabled (admin
settings, default off; off = 404, feature invisible) + pond setting
mcpEnabled (pond-settings toggle, default off) — pinned independent in
both directions by tests.
- Tools (thin wrappers over the #104 services, same permission gates,
audit-logged writes): list_ponds, list_pages, read_page, search,
create_page, update_page (replace semantics through the collab-owned
restore path — open editors converge), add_comment, list_labels,
set_page_labels (exact replace), export_pond (link to the REST ZIP).
Tool errors carry the api error codes; results carry stable slugs/ids.
MCP resources stay the documented stage-2 stretch goal.
- Deliberately on the SDK's low-level Server API with a hand-written tool
table (mcp-tools.ts): the typed registerTool generics drove tsc out of
memory in a program this size; manual Zod validation keeps the wire
behavior explicit.
- PublicApiService exposure filtering parameterized ('api' | 'mcp',
shared pondFeatureEnabled helper) — one implementation, two switches.
- Docs: "Connect Claude Code / MCP clients" section in public-api.md
(claude mcp add one-liner + mcp-remote bridge for stdio clients).
Verification: 8-test e2e pack driving the real MCP SDK client over
Streamable HTTP against a listening api (initialize + tools/list, switch
independence in both directions, anonymous/garbage 401, opt-in 404
semantics, page roundtrip incl. restore-NOTIFY, labels/comments, read
scope blocked from writes with scope_required); live check through the
web proxy against the seeded stack (tools list, create, read, update,
search — LIVE CHECK PASSED); full api suite 61/61 files green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwZ4jR4KFAPvpjWevfUGX1