PARITY-MATRIX-HOSTED.md markdown
145 lines 19.2 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago

Hosted parity matrix (Hub browser ↔ gateway ↔ MCP)

Purpose (G0): One place to see which user-visible capability is implemented in the Hub (web/hub/hub.js + static shell), which HTTP surface owns the behavior (hub/gateway/server.mjs proxy, hub/bridge/server.mjs, or hub/icp canister), and which knowtation-hosted MCP tool (if any) calls the same upstream. Use this to spot empty cells (missing client) and documented intentional differences (not silent drift).

Governance (G1): For any change that ships both Hub and hosted MCP, follow H0–H4 below and add or adjust a row here in the same PR when the capability list changes.

Check Done
H0 Outcome + exact routes/auth documented
H0 Agent memory /api/v1/memory* (Track B3 prep) ☑ — gateway→bridge tests in test/gateway-memory-bridge-proxy.test.mjs
H1 Shared core implemented once (canister / bridge / lib/)
H2 First client shipped
H3 Second client calls same H1 paths
H4 Docs + smoke Hub + reconnect MCP smoke

Related: AGENT-INTEGRATION.md §2 (hosted MCP), hub/gateway/mcp-hosted-server.mjs (tool implementations).


Vault read / write / list

User capability Hub entry (UI / flow) Canonical API (first hop) Hosted MCP tool Parity notes
List notes (browse, filters) Main list + filters; GET /api/v1/notes?… via api() Gateway gatewayProxyGetNotesList → canister GET …/api/v1/notes list_notes Gateway applies scope / client-side filters where canister ignores query params; MCP uses same list contract with canisterUserId for X-User-Id (see playbook § parity).
Open / read note Note drawer; GET /api/v1/notes/:path Same path proxied to canister get_note Same vault-relative path string in Hub and MCP.
Create / update note body Editor save; POST /api/v1/notes Canister POST …/notes write Hub sends JSON body; MCP same.
Semantic / keyword search Search bar + Search; POST /api/v1/search Gateway → bridge POST /api/v1/search search Same bridge route; roles enforced per gateway + ACL.
Rebuild vector index Re-index control; POST /api/v1/index Gateway → bridge index Costly; admin on MCP; same upstream intent as Hub.

Import, media, backup, export

User capability Hub entry Canonical API Hosted MCP tool Parity notes
Import files (markdown, PDF, DOCX, exports, …) Import modal; POST /api/v1/import (multipart) — optional 4A₂ in-browser JSZip (one file = hub-bulk.zip) and 4B sequential multi-file (e.g. many PDFs) = N of the same route. 4C (drop zone) is client-only; same multipart as Choose folder. Gateway proxyImportToBridge → bridge POST /api/v1/import import (one call per file; no import_batch) Admin ACL on MCP; gateway runs billing gate when BRIDGE_URL set. ZIP: bridge/Hub extract .zip to a temp directory and pass that path to runImport—works for folder-capable types (e.g. markdown walks .md). pdf / docx importers require a single file path; Hub 4B sends N sequential uploads (see IMPORT-SOURCES.md § Hub browser). Pre-merge hosted: IMPORT-URL-AND-DOCUMENTS-PHASES.md §4V.
Import from https URL Import modal → URL field; POST /api/v1/import-url (JSON) Gateway proxyTo → bridge POST /api/v1/import-url import_url Admin-only on MCP (same as import); SSRF-safe fetch on bridge.
Transcribe audio / video import Import flow with audio/video Bridge import + Whisper (lib/transcribe.mjs) transcribe MCP uses base64 + filename; Hub uses file upload — same bridge importer.
Git / GitHub vault backup Settings → Backup; Back up now; POST /api/v1/vault/sync Gateway → bridge POST /api/v1/vault/sync vault_sync Editor+; needs GitHub connected on bridge for success.
Export single open note Note drawer Export; POST /api/v1/export with { path, format } Gateway handler for scoped export No MCP row: hosted MCP export is full-vault GET {canister}/api/v1/export with MCP-only byte cap (EXPORT_TOO_LARGE); not the same operation as Hub single-note export.
Export full vault (admin) No first-class Hub button in hub.js for full JSON dump Canister GET /api/v1/export (also used by bridge backup paths) export Intentional product split: MCP admin convenience vs Hub UX; document when adding Hub “download all”.

Capture and “inbox” style writes

User capability Hub entry Canonical API Hosted MCP tool Parity notes
Quick capture line to vault Quick-add / new note flows using POST /api/v1/notes Canister write capture MCP uses lib/capture-inbox.mjs payload builder → same canister POST as write, not Hub webhook POST /api/v1/capture (webhook + secret is a different door).

Derived / agentic operations (no dedicated Hub mirror)

These MCP tools reuse the same canister and bridge primitives as rows above; the Hub does not expose a matching named feature—users achieve similar outcomes manually (list, open, search).

User capability Hub entry Canonical API Hosted MCP tool Parity notes
Related notes (semantic neighbors) Canister read source + bridge POST /api/v1/search relate Bridge uses query embedding; local lib/relate.mjs document embedding — documented small gap in playbook.
Note heading outline Canister GET …/notes/:path + lib/note-outline.mjs get_note_outline Same read path and role as get_note; response excludes body, snippets, full frontmatter, absolute paths, summaries, vectors, and memory events.
Note heading tree Canister GET …/notes/:path + lib/document-tree.mjs get_document_tree Same read path and role as get_note; response excludes body, snippets, full frontmatter, absolute paths, summaries, vectors, labels, metadata facets, resources, and memory events.
Metadata facets Canister GET …/notes/:path + lib/vault.mjs normalizeMetadataFacets get_metadata_facets Same read path and role as get_note; response excludes body, snippets, full frontmatter, absolute paths, summaries, vectors, labels, OCR, PageIndex output, media metadata, resources, and memory events.
Backlinks ([[wikilink]]) Canister list + per-note GET …/notes/:path + lib/wikilink.mjs backlinks Soft cap 2000 notes scanned; fields backlinks_truncated, backlinks_notes_scanned.
Checkbox tasks extraction Canister list/get + lib/extract-tasks.mjs extract_tasks Client-side folder/project/tag/date filters; canister list query not authoritative — see playbook.
Note clustering (embed + k-means) Canister list/get + bridge POST /api/v1/embed + lib/kmeans.mjs cluster Caps documented in playbook.
Tag suggestions from neighbors Canister read + bridge search + optional neighbor reads tag_suggest Default neighbor pool 40; optional neighbor_limit 5–80.

LLM sampling on note text (MCP-first)

User capability Hub entry Canonical API Hosted MCP tool Parity notes
Summarize note — (no Hub control equivalent to MCP sampling) Canister reads in gateway MCP handler + MCP sampling summarize Hub users read the note; MCP may use sampling — see AGENT-INTEGRATION.md.
Enrich / expand note text Proposal enrich is policy/settings and proposal pipeline, not the same as MCP enrich on arbitrary path Canister reads + sampling in MCP enrich Different product shape: Hub “enrich” wording ties to proposals; MCP enrich is generic path + sampling.

Hosted MCP prompts (Track B1 + B2 + B3) — composition only

User capability Hub entry Canonical API Hosted MCP surface Parity notes
Agent-oriented briefs / plans (B1) — (no dedicated Hub “prompt” UI) Same as rows above: GET …/notes, POST …/search, GET …/notes/:path MCP prompts/get IDs: daily-brief, search-and-synthesize, project-summary, temporal-summary, content-plan Composition only: no new HTTP routes; same vault partition rules as tools (canisterUserId on canister). Optional sampling prefill matches self-hosted where used (mcp/prompts/register.mjs).
Meeting / gap / chain / entities / capture-format prompts (B2) Same upstreams; causal chain uses POST …/search with chain + GET …/notes/:path (not local graph resource) MCP prompts/get IDs: meeting-notes, knowledge-gap, causal-chain, extract-entities, write-from-capture meeting-notes: user-supplied transcript only (no vault read). knowledge-gap: semantic search snippets. causal-chain: index-backed chain filter + date sort — may omit unrindexed notes vs local listNotesForCausalChainId. extract-entities: list + embed like project-summary. write-from-capture: text instructions only (no templates/capture.md on hosted); write-from-capture minimum role editor (implies persisting notes).
Memory context / informed search / resume (B3) GET {bridge}/api/v1/memory?… (+ vault POST {bridge}/api/v1/search + GET …/notes/:path for memory-informed-search) MCP prompts/get IDs: memory-context, memory-informed-search, resume-session Same composition as self-hosted mcp/prompts/register.mjs; memory-informed-search uses GET …/memory?type=search, not POST …/memory/search.

Agent memory (/api/v1/memory*) — Hub ↔ bridge ↔ future hosted MCP (Track B3 prep)

Vault-scoped event log and related operations. Gateway (hub/gateway/server.mjs) proxies to bridge (hub/bridge/server.mjs) with the same Authorization: Bearer <JWT> and X-Vault-Id model as other bridge-backed routes; bridge derives uid from JWT and vaultId from X-Vault-Id or vault_id query (see bridgeMemoryAuth). Hosted MCP uses upstreamFetch to these gateway URLs (not disk lib/memory) for Track B3 registerPrompt handlers on branch feat/b3-memory-prompts-implementation (merge to main when ready).

User capability Hub entry (UI / flow) Canonical API (first hop) Hosted MCP (planned) Parity notes
List memory events (time / type filters) Settings → consolidation flow loads recent passes: GET /api/v1/memory?type=consolidation_pass&limit=20 (web/hub/hub.js) Gateway → GET {bridge}/api/v1/memory Track B3: prompts/get (memory-context, resume-session, …) via GET …/memory?… JSON { events, count }. Each element includes type, ts, data (and typically id) — same fields formatMemoryEventsAsync reads from local mm.list() in mcp/prompts/helpers.mjs. Bridge applies type, since, until, limit (default 20, max 100). Hosted (Netlify Blobs): list reads blob store; self-hosted: MemoryManager + file provider.
Latest value for a memory key — (no dedicated Hub control; API exists) Gateway → GET {bridge}/api/v1/memory/:key Optional future tool/prompt helper JSON { key, value, updated_at, id? } (value is event data or null).
Store / upsert user memory event Gateway → POST {bridge}/api/v1/memory/store JSON { key, value, ttl? } Track B3+ if exposed Bridge requireBridgeAuth + requireBridgeEditorOrAdmin (viewers 403).
memory-informed-search prompt (Track B3) GET {bridge}/api/v1/memory?type=search&limit=… (recent search-type memory events) + POST {bridge}/api/v1/search (vault hits) Track B3: prompts/get Matches self-hosted mcp/prompts/register.mjs: vault runSearch + formatMemoryEventsAsync with type: 'search'not POST …/memory/search.
Semantic search inside the memory event store (vector over memory) Gateway → POST {bridge}/api/v1/memory/search Future tool or prompt enhancement Bridge stub today (results: [], fixed note). Separate phase from B3 prompt parity; needs embeddings, caps, and security review before shipping.
Clear memory Gateway → DELETE {bridge}/api/v1/memory/clear optional query type, before Editor+ if exposed Bridge requireBridgeAuth + requireBridgeEditorOrAdmin.
Memory file stats Gateway → GET {bridge}/api/v1/memory-stats JSON from MemoryManager.stats().
Run consolidation (LLM) Hub consolidation UI: preview + run Gateway → POST {bridge}/api/v1/memory/consolidate (gateway runBillingGate + billing-aware body merge on hosted) Bridge requires editor+; cooldown / cost fields — see interlock § Track B3 prep.
Consolidation quota / cooldown Hub reads status after run Gateway → GET {bridge}/api/v1/memory/consolidate/status JSON cooldown + cost summary fields.

Session / identity (MCP resource)

User capability Hub entry Canonical API Hosted MCP surface Parity notes
See effective vault actor Session + vault switcher (implicit via gateway getHostedAccessContext) Bridge GET /api/v1/hosted-context (used by gateway and MCP bootstrap) Resource knowtation://hosted/vault-info Returns userId (JWT sub) and canisterUserId (effective partition); must match Hub list partition — see playbook § Hosted MCP canister X-User-Id parity.
MCP bootstrap / agent prime Hub Settings → Integrations → Copy prime (JSON pointer, no JWT) Same MCP session as other resources Resource knowtation://hosted/prime JSON: knowtation.prime/v1, session fields, mcp_prompts_registered_for_role, suggested next resources, token-layer copy. Self-hosted MCP: knowtation://prime.
Read note via MCP resource URI (R1) Note drawer (same bytes as open note) GET …/api/v1/notes/:path Resource template knowtation://hosted/vault/{+path} .md only; same upstreamFetch + headers as get_note. resources/list includes up to 50 concrete knowtation://hosted/vault/… URIs (SDK template list) for clients like Cursor.
Vault list JSON (first page + per-folder) via MCP resource (R2) Hub main list / folder-scoped list GET …/api/v1/notes?limit&offset (+ optional folder) Resources knowtation://hosted/vault-listing (root first page) and knowtation://hosted/vault/{prefix} when prefix does not end with .md Same canister list as list_notes; limit=100, offset=0; truncated: true when total > 100. Deeper pages / extra filters → list_notes.
Template markdown via MCP (R3) — (templates are vault notes under templates/) GET …/api/v1/notes?folder=templates, GET …/api/v1/notes/:path knowtation://hosted/templates-index (JSON path list), knowtation://hosted/template/{+name} Same reads as get_note / list_notes; mirrors self-hosted knowtation://vault/templates* without local disk.
Note-embedded image bytes (R3) Hub renders ![](https://…) in note body Canister GET …/notes/:path + outbound fetch to image URL Resource template knowtation://hosted/vault-image/{+notePath}/{index} (canonical; avoids overlap with vault/{+path}). Legacy knowtation://hosted/vault/…/note.md/image/n still handled via hosted-vault-note regex. HTTPS-only, mcp/resources/image-fetch.mjs (SSRF-safe). No hosted note-video binary resource; video stays as URLs in markdown (hosted MVP product choice).
Memory events by topic slug (R3) GET {bridge}/api/v1/memory?limit≤100 + client filter Resource template knowtation://hosted/memory/topic/{slug} Same extractTopicFromEvent heuristics as self-hosted knowtation://memory/topic/{slug}; topic list is derived from the latest bridge window only (not full-store enumeration).

Hub-only surfaces (no hosted MCP tool in this matrix)

Capabilities that correctly have no row in the MCP column today (non-goal or future work):

  • Auth, invites, workspace admin: /api/v1/auth/*, /api/v1/invites*, /api/v1/workspace, /api/v1/vault-access, /api/v1/scope, /api/v1/roles
  • Billing: /api/v1/billing/*
  • Proposals CRUD / policy: /api/v1/proposals*, /api/v1/settings/proposal-policy
  • (Agent memory is covered in § Agent memory above; hosted MCP memory trio registerPrompt handlers use GET …/memory + vault search as in that table. POST …/memory/search remains a future row until implemented beyond the stub.)
  • Facets / folders helpers: GET /api/v1/notes/facets, GET /api/v1/vault/folders (Hub filters; MCP tools use list_notes / paths)
  • Attestations: /api/v1/attest*
  • Image upload / proxy: upload-image, image-proxy*
  • Hosted Hub — video as file import: not an MVP surface; video in notes uses markdown links / URLs (same class as image-by-URL).

When a future MCP tool overlaps one of these, add a row and complete H0–H4.


How to maintain this file

  1. New MCP tool: Add a row; cite hub/gateway/mcp-hosted-server.mjs handler and upstream URL in the playbook or in PR description.
  2. New hosted MCP prompt: If the prompt exposes a new user-facing capability (not just composing existing list/search/read APIs), add a matrix row or document composition only in the PR.
  3. New Hub feature that reads/writes vault data: Add a row; confirm MCP either gains a tool or an explicit “—” with rationale.
  4. Refactor that moves HTTP paths: Update the Canonical API column only after reading hub/gateway/server.mjs and bridge/canister routes in repo.

Last inventory pass: 2026-04-22 — eighteen hosted tools (see test/mcp-hosted-tools-list.test.mjs TOOLS_ADMIN; includes import_url), thirteen hosted prompts (twelve for viewer when write-from-capture is hidden), and R3+ hosted resources (templates, note images, memory topics) in mcp-hosted-server.mjs; eight gateway-proxied memory routes (hub/gateway/server.mjshub/bridge/server.mjs).

File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago