ADR 008: One operation registry for HTTP, MCP, and the typed client
Date: 2026-09-10. Status: accepted.
Decision#
- Stack: Hono 4 in one process (web client,
/api/v1,/mcp,/openapi.json,/sync,/assets), Zod 4 schemas with generated JSON Schema, MCP SDK v2 (@modelcontextprotocol/server+@modelcontextprotocol/hono, spec 2026-07-28) as a stateless Streamable HTTP server with bearer auth, plus anooklet mcp --stdiobridge. defineOp({ name, summary, description, input, output, annotations, scopes, expose, render, handler })is the single definition. Loops mountPOST /api/v1/<name>(with REST-style aliases where natural), build OpenAPI, register MCP tools (text content fromrender, structured content validated against the output schema, errors with hints), and derive a typed client. Plugins register ops through the same registry; plugin ops default to HTTP-only.- v1 exposes 18 MCP tools (ADR 013 adds
batch_undoandasset_uploadto the original 16) with annotations and a token budget fortools/list; read tools are marked always-loaded for clients that defer tools behind tool search. Writes accept markdown and return created outlines with ids;block_updatesupports string replacement within a block andif_version;batchis atomic withdry_runand idempotency keys. - Outline serialization: our mirror format with
^idsuffixes;ids: none, depth and size limits for cheap reads; JSON on request. - Safety: scoped tokens (
readdefault,write,admin) with labels as audit actors, soft delete to trash, rate limits, and achangestable written in the same transaction as the ops forchanges_since, UI attribution, and agent-batch undo.
Why#
- Evidence from the user's current Logseq MCP server: unpaginated 1,274-page listings, page reads that time out, no block ids in text mode, one-block-per-call inserts, full-page replace that destroys ids, duplicated pages after retries. Every one of those is a design error we can avoid by defining operations once with pagination, ids, tree inserts, and idempotency.
- OpenAPI-to-MCP generators produce one tool per endpoint and sprawl; oRPC has no MCP adapter; Effect is too heavy. A 200-line registry gives one source of truth.