Filesystem-first MCP server for Obsidian vaults — with an LLM-Wiki layer on top.
Inspired by Andrej Karpathy's LLM Wiki idea. You curate the sources; the LLM does the bookkeeping.
Install · Quick start · Architecture · LLM Wiki · Tools · Docs
- Filesystem-first. Operates on your vault directly. Obsidian doesn't need to be running for 80+ of the 90 tools.
- 90 typed MCP tools across notes, links, tags, tasks, Dataview, Canvas, Kanban, Mermaid, Marp, Templates — every one Zod-validated with
structuredContentoutput and client-safety annotations (readOnlyHint,destructiveHint,idempotentHint,openWorldHint). - LLM-Wiki orchestration — a
wiki.*namespace that turns your vault into a compounding knowledge base: ingest sources, auto-update an index + greppable log, lint for orphans / broken links / stale pages. Agent applies cross-refs via aproposedEditscontract so every write is visible in the transcript. - Both transports. Classic stdio for local MCP clients and Streamable HTTP (Hono) for remote, with CORS preflight,
MCP-Protocol-Versionhandling, origin 403, and optional bearer auth — all per the 2025-11-25 spec. - Ships everywhere. npm (
npx -y kobsidian-mcp), cross-platform.mcpbbundles for Claude Desktop drag-and-drop, asmithery.yamlfor Smithery, and aserver.jsonfor the MCP Registry. Each.mcpbrelease asset is VirusTotal-scanned with links appended to the release body.
Pick the channel that matches your client. All three read the same
OBSIDIAN_VAULT_PATH, OBSIDIAN_API_URL, and OBSIDIAN_REST_API_KEY
environment variables — see docs/ENVIRONMENT.md.
{
"mcpServers": {
"kobsidian": {
"type": "stdio",
"command": "npx",
"args": ["-y", "kobsidian-mcp"],
"env": {
"OBSIDIAN_VAULT_PATH": "/absolute/path/to/vault",
"OBSIDIAN_API_URL": "https://127.0.0.1:27124",
"OBSIDIAN_API_VERIFY_TLS": "false",
"OBSIDIAN_REST_API_KEY": "only-if-you-use-workspace-or-commands-tools"
}
}
}
}"type": "stdio" is optional on clients that infer transport from
command (Claude Code), but required by Claude Desktop, Cursor,
VSCode, and Antigravity — include it for maximum portability. Swap
npx for bunx for ≈10 ms cold-start instead of ≈200 ms.
Download kobsidian-<platform>.mcpb from the
latest release and
drag it into Claude Desktop. The installer prompts for vault path +
optional API URL / key. Every release asset is scanned — the VirusTotal
links are in the release body.
Build one locally:
bun install
bun run build:compile # → dist/kobsidian (or .exe on Windows)
bun run bundle:mcpb # → kobsidian.mcpbsmithery.ai renders an install UI straight from
smithery.yaml and collects the three env vars for you.
git clone https://github.com/bezata/kObsidian
cd kObsidian
bun install
bun run dev:stdio # or dev:httpkObsidian is filesystem-first — 80+ of the 90 tools work against a bare vault directory with no Obsidian plugins installed. The plugins below only matter if you want the specific tool namespaces that depend on them.
Obsidian ships with community plugins disabled by default. Enable them once per vault:
- Open your vault in Obsidian.
- Settings (⚙️, bottom-left) → Community plugins.
- Click Turn on community plugins.
- Browse → search → Install → Enable.
Obsidian Local REST API (by Adam Coddington) — needed for:
workspace.*(activeFile, openFile, navigateBack/Forward, toggleEditMode)commands.*(execute, list, search)dataview.query/dataview.listByTag/dataview.listByFolder/dataview.table(runtime DQL — the offlinedataview.fields.*/dataview.index.read/dataview.query.readtools work without it)templates.renderTemplater/templates.createNoteTemplater/templates.insertTemplater
Setup after install:
- Enable the plugin.
- Open its settings — scroll to API key → click Copy (or Reset first if you want a fresh one).
- Paste that key as
OBSIDIAN_REST_API_KEYin your MCP client config'senv:block. TheOBSIDIAN_API_URLdefault (https://127.0.0.1:27124) works out of the box.
Leave the plugin running while you use the REST-bridged tools — the endpoint is local-only (127.0.0.1) so nothing leaves your machine.
| Plugin | Link | What it unlocks |
|---|---|---|
| Dataview | id=dataview |
All dataview.* tools still work on the raw markdown; Dataview plugin is what makes DQL queries in dataview.query* actually execute. Also renders your fields + queries visually inside Obsidian. |
| Templater | id=templater-obsidian |
Runtime template rendering via the REST API (templates.renderTemplater, etc.). The offline templates.expand / templates.list / templates.createNote work without it. |
| Marp | id=marp-slides |
Marp marp.* tools parse + edit Marp-front-matter markdown even without the plugin; the plugin is what renders slides / exports to PDF inside Obsidian. |
| Kanban | id=obsidian-kanban |
kanban.* tools read/write the plain markdown board format regardless of plugin; the plugin is what renders the board as draggable columns inside Obsidian. |
| Tasks | id=obsidian-tasks-plugin |
tasks.* tools understand the Tasks-plugin emoji syntax (📅 ⏳ 🛫 ✅ 🔼 🔁) regardless of plugin; the plugin is what provides filtering / querying / toggling inside Obsidian. |
The
obsidian://show-plugin?id=…links jump straight to the plugin in Obsidian's in-app browser — click one with Obsidian open and it deep-links to the install screen.
| You want to … | Minimum you need |
|---|---|
Use notes.* / tags.* / links.* / stats.* / tasks.* / wiki.* / kanban.* / mermaid.* / marp.* / canvas.* / templates.expand + list + createNote / offline dataview.* |
Just a vault path. No plugins required. |
Use workspace.* / commands.* |
+ Local REST API plugin + API key env var |
Run live DQL queries (dataview.query / dataview.listBy* / dataview.table) |
+ Local REST API + Dataview |
| Run Templater templates at runtime | + Local REST API + Templater |
No combination of plugins makes kObsidian depend on Obsidian being running — the REST-bridged tools just return a clear error if the plugin isn't reachable, and the filesystem-first tools keep working.
Before the first session — kObsidian works on a bare Obsidian vault, but enabling a few Obsidian plugins unlocks the full tool surface. See Obsidian plugins below for the 5-minute setup (Local REST API, Dataview, Templater, Marp, Kanban, Tasks). Skip it if you only need the 80+ filesystem-first tools.
Once installed, a typical session opens with three natural-language
prompts. The wiki.* tools + the .claude skills handle the rest.
You: "Set up a wiki in this vault."
LLM: wiki.init → wiki/{Sources,Concepts,Entities}/ + index.md + log.md + wiki-schema.md
You: "Ingest this: https://… (paper on Memex)"
LLM: wiki.ingest → creates wiki/Sources/as-we-may-think.md + log entry
returns proposedEdits:
- insertAfterHeading index.md#Sources
- createStub Concepts/memex.md
- createStub Entities/vannevar-bush.md
LLM applies each via notes.* (you see every write in the transcript)
You: "What does the wiki say about memex vs hypertext?"
LLM: wiki.query memex → top-ranked pages
notes.read on each → cited synthesis
offers to file the synthesis back via wiki.summaryMerge
You: "Audit the wiki."
LLM: wiki.lint → {orphans, brokenLinks, stale, missingPages, tagSingletons, indexMismatch}
proposes concrete fixes; applies after you confirm
Full loop, frontmatter contracts, and the proposedEdits design in
docs/wiki.md.
The same primitives cover several real-world flavors of knowledge base.
Three worked examples below; longer walkthroughs in docs/examples.md.
You: "Ingest this paper on in-context learning: <url or pasted markdown>"
LLM: wiki.ingest title="In-Context Learning — A Survey" sourceType=paper
tags=[icl, prompting] relatedConcepts=[In-Context Learning, Few-Shot Prompting]
relatedEntities=[Brown 2020]
→ wiki/Sources/in-context-learning-a-survey.md
→ proposedEdits:
• createStub wiki/Concepts/in-context-learning.md
• createStub wiki/Concepts/few-shot-prompting.md
• createStub wiki/Entities/brown-2020.md
• insertAfterHeading wiki/index.md#Sources
LLM applies each via notes.create / notes.insertAfterHeading.
Model each ADR as a Source, architectural patterns as Concepts, and services / teams / libraries as Entities. The wiki becomes your ADR archive with cross-links you never have to maintain by hand.
You: "Record ADR-004: we're switching internal service comms from REST
to gRPC. Context: <paste>"
LLM: wiki.ingest title="ADR-004 — gRPC for internal service comms"
sourceType=note tags=[adr, architecture, rpc]
relatedConcepts=[gRPC, Service Mesh, Internal RPC]
relatedEntities=[order-service, payment-service, inventory-service]
→ wiki/Sources/adr-004-grpc-for-internal-service-comms.md
→ proposedEdits:
• createStub wiki/Concepts/grpc.md
• createStub wiki/Concepts/service-mesh.md
• insertAfterHeading wiki/Entities/order-service.md#Notable Facts
• insertAfterHeading wiki/Entities/payment-service.md#Notable Facts
• …
Three weeks later —
You: "Why did we pick gRPC for internal comms?"
LLM: wiki.query "grpc internal comms"
notes.read top matches
→ "Per [[wiki/Sources/adr-004-grpc-for-internal-service-comms.md|ADR-004]],
chosen over REST because of native streaming + typed schemas; tradeoff
accepted: browser clients still use REST via an edge gateway
([[wiki/Concepts/service-mesh.md]])."
Engineering teams abandon wikis because nobody updates them. Let the LLM do it. Ingest design docs, RFCs, and post-mortems as Sources; architectural patterns become Concepts; services and teams become Entities.
You: "We had an incident today — payment-service timeouts cascaded
into order-service. Here's the post-mortem: <paste>"
LLM: wiki.ingest title="Postmortem 2026-04-10 — Payment timeouts cascade"
sourceType=other tags=[postmortem, incident, reliability]
relatedConcepts=[Circuit Breaker, Cascade Failure, Timeout Budget]
relatedEntities=[payment-service, order-service]
→ wiki/Sources/postmortem-2026-04-10-payment-timeouts-cascade.md
→ proposedEdits:
• createStub wiki/Concepts/circuit-breaker.md
• createStub wiki/Concepts/cascade-failure.md
• insertAfterHeading wiki/Entities/payment-service.md#Notable Facts
• insertAfterHeading wiki/Entities/order-service.md#Notable Facts
Periodic housekeeping —
You: "Audit the codebase wiki."
LLM: wiki.lint
→ 3 orphan RFCs (unlinked from any Concept; link or archive?)
→ 1 broken link: [[wiki/Entities/legacy-auth-service.md]]
(deprecated in Q1; remove the link from
[[wiki/Sources/adr-002-session-migration.md]]?)
→ 4 post-mortems past the 180-day stale threshold — tag with
"needs-review" or re-ingest with updated lessons-learned?
→ 2 tag singletons: `retry-logic` (merge into `retry-policy`?),
`observability` (first use; keep).
Why this works for engineering teams
- The
proposedEditscontract means every cross-reference write is visible in the transcript — no silent vault corruption from an LLM hallucination about which services a decision affects. - The greppable log format (
## [YYYY-MM-DD] ingest | ADR-004 …) makesgrep '^## \[' wiki/log.md | tail -20a valid "what did the team decide recently" query. wiki.lintsurfaces broken links to services that were deprecated months ago — the bookkeeping humans never get around to.
┌──────────────────────────────────────────────────────────────────────┐
│ MCP Clients │
│ Claude Code · Claude Desktop · Cursor · VSCode · Antigravity · Zed │
│ JetBrains AI · Cline · Continue · ChatGPT · Smithery · … │
└────────────────────────────┬─────────────────────────────────────────┘
│ JSON-RPC 2.0 · MCP 2025-11-25
┌───────────────────┴──────────────────────┐
▼ ▼
┌──────────────────┐ ┌─────────────────────────┐
│ stdio transport │ │ Streamable HTTP (Hono) │
│ │ │ + OPTIONS / CORS │
│ │ │ + MCP-Protocol-Version │
│ │ │ + Origin 403 / bearer │
└────────┬─────────┘ └────────┬────────────────┘
│ │
└──────────────────┬───────────────────┘
▼
┌──────────────────────────────────┐
│ McpServer │
│ ┌────────────┐ ┌─────────────┐ │
│ │ 90 Tools │ │ 4 Resources │ │
│ └────────────┘ └─────────────┘ │
│ ┌────────────┐ ┌─────────────┐ │
│ │ 3 Prompts │ │ structured │ │
│ │ │ │ content │ │
│ └────────────┘ └─────────────┘ │
└────────────┬─────────────────────┘
│
▼
┌──────────────────────────────────┐
│ Domain layer (pure) │
│ notes · links · tags · tasks │
│ dataview · canvas · kanban │
│ mermaid · marp · templates │
│ wiki/ orchestration │
└──────┬─────────────────┬─────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────────────┐
│ vault/ (FS) │ │ Obsidian Local REST │
│ authoritative│ │ API plugin (optional)│
└──────────────┘ └──────────────────────┘
Full module map in docs/architecture.md.
The tedious part of maintaining a knowledge base is not the reading or the thinking — it's the bookkeeping. Humans abandon wikis because the maintenance burden grows faster than the value. LLMs don't get bored.
kObsidian implements the LLM Wiki pattern from Andrej Karpathy's gist: a persistent, compounding knowledge base the LLM maintains. The vault becomes a private, curated Memex (Vannevar Bush, 1945) where cross-references, log-keeping, and lint are the LLM's job while you focus on curating sources and asking questions.
"Instead of just retrieving from raw documents at query time, the LLM incrementally builds and maintains a persistent wiki — a structured, interlinked collection of markdown files that sits between you and the raw sources." — Andrej Karpathy
User drops a source
│
▼
┌──────────────────────┐ proposedEdits
│ wiki.ingest │ ─────────────────────┐
└──────────┬───────────┘ │
│ creates 1 file ▼
│ ┌──────────────────────────────┐
▼ │ LLM applies edits via │
wiki/Sources/ │ notes.insertAfterHeading │
<slug>.md │ notes.update │
│ │ notes.create │
│ appends └──────────────────────────────┘
▼
wiki/log.md
Anytime: wiki.query → top pages → notes.read → cited synthesis
Periodic: wiki.lint → orphans · broken · stale · missing · tag-drift
Curate: wiki.summaryMerge — add cited section to concept/entity page
Default layout under the vault:
wiki/
├── Sources/ per-source summary pages
├── Concepts/ topic / idea pages (LLM-maintained)
├── Entities/ people / places / orgs / works
├── index.md categorized catalog (wiki.indexRebuild)
├── log.md greppable chronological log
└── wiki-schema.md vault-local copy of the contract
The key design decision is that wiki.ingest never rewrites
cross-references blindly. It creates exactly one file (the Sources
page), appends one file (log.md), and returns a proposedEdits array
the agent applies with existing notes.* tools. Every write is visible
in the transcript — so LLM hallucinations show up as reviewable edits
rather than silent vault corruption.
Full contract in docs/wiki.md.
Four skills at skills/ trigger on natural language:
wiki-bootstrap, wiki-ingest, wiki-query, wiki-lint. Copy or
symlink them into ~/.claude/skills/ — see
skills/README.md.
90 MCP tools across 12 namespaces. Always-current inventory at
docs/tool-inventory.json.
| Namespace | Count | Highlights |
|---|---|---|
notes.* |
16 | CRUD · search · move · smart-insert (after heading / block) |
tags.* |
6 | Add · remove · search · analyze |
links.* |
8 | Backlinks · broken · orphans · hubs · graph · health |
stats.* |
2 | Per-note + vault-wide metrics |
tasks.* |
5 | Tasks-plugin format (📅 ⏳ 🛫 ✅ 🔼 🔁) |
dataview.* |
13 | Fields · DQL · DataviewJS (source-preserving edits) |
mermaid.* |
3 | Fenced-block parse / read / update |
marp.* |
5 | Slide-level reads + edits |
kanban.* |
5 | Board + card mutations |
templates.* + canvas.* |
10 | Templates · Templater bridge · Canvas nodes/edges |
workspace.* + commands.* |
9 | Obsidian REST bridge (only tools needing Obsidian running) |
wiki.* |
7 | init · ingest · log · indexRebuild · query · lint · summaryMerge |
Client-safety annotations (MCP 2025-11-25):
| Hint | Tools |
|---|---|
readOnlyHint: true (clients can auto-approve) |
47 |
destructiveHint: true (clients prompt more firmly) |
6 |
idempotentHint: true (safe to retry) |
12 |
openWorldHint: true (reaches outside the vault) |
16 |
MCP resources (URI-addressable; any client can browse without tool calls):
kobsidian://wiki/index wiki/index.md
kobsidian://wiki/log wiki/log.md
kobsidian://wiki/schema wiki/wiki-schema.md
kobsidian://wiki/page/{+path} any Sources/Concepts/Entities page
MCP prompts (for clients that don't consume the skills/ files):
ingest-source, answer-from-wiki, health-check-wiki.
Details in docs/tools.md.
| Env var | Default | Purpose |
|---|---|---|
OBSIDIAN_VAULT_PATH |
— | Required. Absolute path to the vault. |
OBSIDIAN_API_URL |
https://127.0.0.1:27124 |
Obsidian Local REST API base; only for workspace.* / commands.* / dataview.query*. |
OBSIDIAN_API_VERIFY_TLS |
false |
Set true if you've trusted the REST API's self-signed cert. |
OBSIDIAN_REST_API_KEY |
— | Bearer key for the REST API plugin (if used). |
KOBSIDIAN_HTTP_HOST |
127.0.0.1 |
Bind host for dev:http. |
KOBSIDIAN_HTTP_PORT |
3000 |
Bind port for dev:http. |
KOBSIDIAN_HTTP_BEARER_TOKEN |
— | Optional bearer for the Streamable HTTP transport. |
KOBSIDIAN_ALLOWED_ORIGINS |
http://localhost,http://127.0.0.1 |
Comma-separated CORS allowlist. |
KOBSIDIAN_WIKI_ROOT |
wiki |
Wiki directory under the vault. |
KOBSIDIAN_WIKI_SOURCES_DIR |
Sources |
Per-source summary pages. |
KOBSIDIAN_WIKI_CONCEPTS_DIR |
Concepts |
Topic / idea pages. |
KOBSIDIAN_WIKI_ENTITIES_DIR |
Entities |
People / places / orgs / works. |
KOBSIDIAN_WIKI_INDEX_FILE |
index.md |
Wiki catalog filename. |
KOBSIDIAN_WIKI_LOG_FILE |
log.md |
Wiki log filename. |
KOBSIDIAN_WIKI_SCHEMA_FILE |
wiki-schema.md |
Seed schema filename. |
KOBSIDIAN_WIKI_STALE_DAYS |
180 |
wiki.lint stale-page threshold. |
Every wiki tool also accepts a per-call wikiRoot override.
| architecture.md | Stack, module map, layering rules |
| wiki.md | LLM-Wiki contract, loop, frontmatter, lint categories |
| examples.md | Personal research wiki · engineering ADRs · codebase wiki — end-to-end |
| tools.md | Namespace table, annotations, resources, prompts |
| SECURITY.md | Origin/CORS, VirusTotal scans, env hygiene |
| TESTING.md | bun run … commands + coverage |
| ENVIRONMENT.md | Every env var with defaults |
| MIGRATION.md | Upgrade notes |
bun install
bun run typecheck
bun run lint
bun run test # 56 tests across 14 files
bun run build # node-target stdio.js + bun-target http.js
bun run inventory # regenerate docs/tool-inventory.jsonProject conventions in AGENTS.md.
-
Every
.mcpbrelease asset is VirusTotal-scanned. TheReleaseworkflow uploads eachkobsidian-<platform>.mcpbbundle to VirusTotal viacrazy-max/ghaction-virustotal@v4right after the release is published, then appends the analysis links to the release body. Any user installing from a GitHub release can click through to the public VirusTotal report for their platform's bundle before they run it — no trust in the maintainer required. -
Transport hardening. Streamable HTTP validates
Originagainst an allowlist (403 on mismatch), implements CORS preflight (OPTIONS /mcp→ 204 +Access-Control-*), requires or defaultsMCP-Protocol-Version, and supports optional bearer auth viaKOBSIDIAN_HTTP_BEARER_TOKEN. stdio has no network surface. -
Pinned SDK floor.
@modelcontextprotocol/sdk@^1.26.0— mitigatesGHSA-345p-7cg4-v4c7(cross-client response leak) andCVE-2026-0621(UriTemplate ReDoS). This repo pins1.29.0. -
npm Trusted Publishing. No long-lived
NPM_TOKENis stored in the repo. GitHub Actions mints a short-lived OIDC token on every tag push and the npm CLI exchanges it for a one-time publish token scoped to this exact workflow file (.github/workflows/release.ymlon thebezata/kObsidianrepo). Provenance attestations are automatic — every published version has a cryptographically-linked build statement pointing at the exact Actions run that produced it. Forks, other branches, or modified workflow files cannot publish — the OIDC audience claim won't match.
Full notes in docs/SECURITY.md.
- Protocol version —
2025-11-25(current MCP spec). HTTP clients withoutMCP-Protocol-Versionfall back to2025-03-26per spec; explicit-but-unsupported versions return 400. - Dataview split — offline tools index frontmatter / inline / list /
task / fenced
dataview/ fenceddataviewjsblocks. Runtime DQL is delegated to Obsidian + Dataview through the Local REST API. DataviewJS is source-preserving but not executed inside this server. - Mermaid + Marp — source-preserving parse/edit only; rendering is the client's job.
- SDK floor —
@modelcontextprotocol/sdk@^1.26.0(mitigatesGHSA-345p-7cg4-v4c7cross-client response leak +CVE-2026-0621UriTemplate ReDoS). This repo pins1.29.0.
- LLM Wiki pattern — Andrej Karpathy's gist. kObsidian is one concrete, filesystem-first TypeScript implementation of the idea.
- Memex — Vannevar Bush, As We May Think, 1945. The associative-trails concept is what the wiki's cross-reference graph tries to be.
- Model Context Protocol — Anthropic + the Agentic AI Foundation.
- Obsidian — obsidian.md. The vault format is authoritative; kObsidian respects it, doesn't migrate it.
MIT — see LICENSE. Contributions welcome; open an issue first for anything non-trivial.