MCP
Tools the Open Knowledge MCP server exposes to AI agents.
The MCP server gives AI agents structured access to your knowledge base. Two reads are server-free: exec (shell-style reads, fs-direct against the disk) and preview_url (reads ui.lock directly) both work even when the editor is down. Every other read tool (search, links, history, etc.) and all write tools route through the Hocuspocus server, which Open Knowledge starts for you on the first write.
The surface is 17 tools. Three of the four write verbs — write, edit, delete — are native CRUD operations polymorphic over a target (document, folder, template, asset): per-target fields nest inside the address key (write({ document: { path, content } })), and you pass exactly one target per call. move is the fourth write verb but takes flat from/to paths and auto-detects whether the path is a document, folder, or asset (no template target).
Tools
| Tool | Purpose |
|---|---|
exec | Read-only shell (cat, ls, grep, find, head, tail, wc, sort, uniq, cut); reads return frontmatter, backlinks, and recent history. Fs-direct; works without the server. |
search | Ranked workspace search (title boost + body BM25 + recency; same engine the cmd-K palette uses) |
links | Wiki-link graph. kind selects: backlinks, forward, dead, orphans, hubs, or suggest. Accepts an array (e.g. ["dead", "orphans", "hubs"]) to fetch several views in one call; each view nests under its own key in the response |
history | Version timeline for a doc. Each entry carries a version (commit SHA) you pass to restore_version |
config | Read the effective merged config (config({ key: "appearance.theme" }) for a sub-tree; omit key for the whole config) |
palette | Markdown-native authoring forms, themed html preview embed starters, and theme tokens. Pass components for the canonical components' full JSX prop schemas |
preview_url | Resolve the browser-reachable preview URL. Per-response previewUrl fields elsewhere are route-only (/#/<doc>); call this when you need the full openable URL |
share_link | Build a GitHub-substrate share URL for a doc to send to a teammate (read-only against .git/; never publishes) |
write | Create or overwrite a document, folder, template, or asset. For a document: { path, content }, or { path, template } to instantiate from a folder template. position selects replace (full rewrite; the only mode that touches frontmatter), append, or prepend |
edit | Modify a document (body find/replace or a frontmatter merge-patch), a folder (frontmatter merge-patch), or a template |
delete | Delete a document (one path or an array), folder, template, or asset |
move | Move or rename a document, folder, or asset and rewrite every affected link |
checkpoint | Save a project-wide version snapshot — a single restore point. Returns its version |
restore_version | Restore one document to a historical version (the SHA from history or checkpoint) |
conflicts | Read GitHub-sync merge conflicts. kind: "list" enumerates tracked conflicts; kind: "content" returns one file's base / ours / theirs stages |
resolve_conflict | Write a chosen resolution (mine / theirs / content / delete) and commit |
workflow | Procedural guides. kind selects: ingest (capture a source), research (gather + write provisional findings), consolidate (promote research to a canonical article), or discover (onboard an existing repo) |
Output shape mirrors the input
The write verbs nest their result under the same target key you wrote, mirroring the input: write({ folder }) returns { folder: { ok, path } }, edit({ document }) returns { document: { … } } (with any contentDivergence), and a batch returns { documents: [ … ] }. The uniform preview envelope (previewUrl, previewUrlSource, warning) always stays at the top level — every tool surfaces it the same way. conflicts and links nest the same way under their kind.
Instantiating from a template
write accepts a template field on the document target — write({ document: { path, template } }) — that resolves against the cascade of templates available for the target document's parent folder, using the same folder-up walk the Folders and templates page describes. The template body becomes the new document's content; the template's own info block (its name and description) is stripped, so it doesn't bleed onto the document.
content and template are mutually exclusive. With template, position is forced to replace (initial create semantics).
Editing frontmatter
Use edit({ document: { path, frontmatter } }) for frontmatter edits: it applies a JSON Merge Patch (set or create a key with a value, delete a key by passing null). A document body find/replace (edit({ document: { path, find, replace } })) is body-only and refuses patterns that touch frontmatter; write with position: "replace" is the only write mode that includes the ---\n…\n--- block (other positions ignore any frontmatter in the payload). Folders and templates take frontmatter the same way: edit({ folder: { path, frontmatter } }).
Edit summaries
The write tools (write, edit, move, checkpoint) accept an optional summary describing the intent of the edit, e.g. "Fixed token-refresh race". Summaries appear on the document's timeline so readers can scan recent agent activity.
Cap is 80 characters. Avoid secrets and PII; summaries persist to git history.
Conflict-aware writes
Every mutating tool (write, edit, delete, move, restore_version, and agent undo) refuses to mutate a doc whose GitHub-sync state is conflict.
To recover, call conflicts({ kind: "content", file }) to inspect the merge stages, then resolve_conflict with one of:
mine: resolve to your committed version (stage 2 — runsgit checkout --ours <file>thengit add).theirs: resolve to their committed version (stage 3 — runsgit checkout --theirs <file>thengit add).content: write the exact bytes you supply (for example, a merged result you composed by reading both stages).delete:git rmthe file (for delete-vs-modify shapes where one stage is missing).
To detect conflict state proactively without waiting for a 409, call conflicts({ kind: "list" }); it enumerates every conflicted doc with its lifecycle: { status, reason }. exec("cat …") also returns that lifecycle field for any doc.
Preview links
Read and write tools return a previewUrl for any doc they touched, but those are route-only (/#/<doc> with no host:port), meant to identify the doc, not to be opened as-is. Hosts that want to open the editor (Claude Code Desktop's preview_start, terminal open <url>) call preview_url to resolve the full URL once per session. The editor refocuses automatically on subsequent writes.
preview_url always carries an autoOpen boolean (top-level on its response) reflecting the user's appearance.preview.autoOpen preference. The write tools (write, edit) carry the same boolean on the warning object, which fires only when no browser is attached to the preview. In the common case (a browser is attached), the write response has no warning and no autoOpen field. Agents honor autoOpen before navigating: true (default) follows the host-capability routing in the bundled skill; false means the user is managing their own preview window, so the agent surfaces the URL on request but does not open or refresh anything. The value is resolved fresh on every tool call, so a mid-session toggle propagates within 0–1 calls, with no client restart.