Vault Cortex
vault-cortex gives MCP clients full, headless access to an Obsidian vault through 23 tools — no Obsidian instance required. Capabilities include:
Vault CRUD: Read, write, patch (heading-targeted edits), find-and-replace, list, and delete notes.
Full-text search: BM25/FTS5-ranked search with phrase matching, stemming, and filters (tags, folder, properties). Also search by tag (hierarchical prefix match), browse by folder with metadata, and list recent notes.
Tag management: List all tags with usage counts; search notes by tag.
Structured memory: Read, update (append dated entries), and delete entries in
About Me/memory files; discover memory files and their sections.Properties (frontmatter): List all property keys with counts/sample values, enumerate distinct values per key, search notes by key-value pair, and update properties without touching the note body.
Link graph: Find backlinks (notes linking to a given note), outgoing links (with broken-link detection), and orphan notes (no incoming links).
Daily notes: Resolve and read today's or any date's daily note using the vault's configured settings.
Auth: Supports OAuth 2.1 (JWT) and static bearer token.
Provides full access to an Obsidian vault, allowing AI agents to search, read, write, manage structured memory, query backlinks, and work with daily notes.
Vault Cortex is a standalone MCP server that gives any AI assistant full-text search, structured memory, and read/write access to your Obsidian vault. No plugins, no running Obsidian, no separate bridge. One Docker container, your vault folder, 25 tools. Deploy on a VPS with Obsidian Sync and the same vault is accessible from your phone, claude.ai, or any remote MCP client, secured with OAuth 2.1.
Contents — What you get · Quick Start · How It Works · Tools · Prompts · Config · Auth · Deployment
What you get
Remote access — works from your phone, a remote server, or any MCP client via OAuth 2.1. Deploy on a VPS with Obsidian Sync for access from anywhere.
Plugin-free — Obsidian doesn't need to be running. The server works directly with
.mdfiles on disk. Headless sync keeps the vault current.Ranked search — SQLite FTS5 with BM25 scoring, stemming, phrase matching, and tag/property/folder filtering
Structured memory — dated entries, section targeting, auto-initialization for AI personalization
Link graph — backlinks, outgoing links, and orphan detection across the vault
Obsidian-native — understands frontmatter, wikilinks, tags, headings, and daily notes
Guided workflows — three built-in prompts that surface vault health (orphans, broken links, property adoption), review your memory layer's structure and coverage, or reconcile a day's work with outgoing links, backlinks, and date-specific activity. Assembled from live vault data each time you run them.
Tested across a 15-day trip through Europe. 30+ sessions from a phone, 70+ tool calls, zero laptop access needed. Writes in one session were immediately available in the next, across cities and days.
Related MCP server: Vault MCP Server (mschuchard)
Quick Start
Local (2 minutes — Docker + your vault folder)
Prerequisites: Docker, Node.js >= 20.12 (only for the CLI — the server itself runs in Docker), and an Obsidian vault (or any folder of .md files).
npx vault-cortex@latest initThat's it — the CLI asks for your vault path, generates the auth token and config files, starts the server, and prints the connection details for your MCP client.
# 1. Get the quickstart files
curl -O https://raw.githubusercontent.com/aliasunder/vault-cortex/main/deploy/local/docker-compose.yml
curl -O https://raw.githubusercontent.com/aliasunder/vault-cortex/main/deploy/local/.env.example
# 2. Configure
cp .env.example .env
# Edit .env — set MCP_AUTH_TOKEN (openssl rand -hex 32) and VAULT_PATH
# 3. Start
docker compose upFull local guide → (includes Windows setup)
Remote (access from anywhere — Docker + Obsidian Sync)
Prerequisites: a VPS with Docker, an Obsidian Sync subscription, and Node.js >= 20.12 (only for the CLI — the server itself runs in Docker).
# On your VPS:
npx vault-cortex@latest init --mode remoteThat's it — the CLI walks through the public URL, Obsidian Sync token (it can run the token generator for you), and auth config, then starts the server.
# On your VPS:
mkdir -p /opt/vault-cortex && cd /opt/vault-cortex
curl -O https://raw.githubusercontent.com/aliasunder/vault-cortex/main/deploy/remote/docker-compose.yml
curl -O https://raw.githubusercontent.com/aliasunder/vault-cortex/main/deploy/remote/.env.example
cp .env.example .env
# Edit .env — set MCP_AUTH_TOKEN, PUBLIC_URL, OBSIDIAN_AUTH_TOKEN, VAULT_NAME
docker compose up -dConnect your MCP client
Setup | Server URL |
Local |
|
Remote |
|
Add the server URL in any MCP client — Claude Code, Claude Desktop, Cursor, OpenCode, or any other. OAuth clients open a consent page in your browser — approve with your token, and the client handles token renewal from then on. Clients without OAuth (MCP Inspector, scripts) send the token directly as an Authorization: Bearer header.
Claude Code:
claude mcp add --scope user --transport http vault-cortex http://localhost:8000/mcp # local (or <PUBLIC_URL>/mcp)--scope user registers the server for every project; omit it to scope it to the current directory only.
The "Add custom connector" dialog only accepts https URLs. With an https PUBLIC_URL, add it directly in the connector dialog; for a localhost server, register it in claude_desktop_config.json through the mcp-remote stdio bridge instead:
{
"mcpServers": {
"vault-cortex": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:8000/mcp",
"--header",
"Authorization: Bearer <your MCP_AUTH_TOKEN>"
]
}
}
}claude.ai (web and mobile) connects to the remote setup only — its connectors are fetched server-side and can never reach localhost.
"Remote MCP server" refers to the connection type (HTTP) — in the local setup the server still runs entirely on your machine.
See Authentication for both methods and token lifetimes.
How It Works
graph LR
Client["MCP Client"] -->|OAuth 2.1 / Bearer| Server["vault-mcp"]
Server -->|read/write| Vault[("/vault<br/>.md files")]
Server -->|query| SQLite[("SQLite FTS5")]
Sync["obsidian-sync"] <-->|Obsidian Sync| VaultThe vault .md files are the source of truth. SQLite FTS5 is rebuildable derived state — the index is built on startup and kept current by a file watcher. obsidian-sync keeps the vault in sync with your Obsidian apps (remote deployments only).
See ARCHITECTURE.md for the full design, auth flow diagrams, and Phase 1/2 boundaries.
Tools (25)
Category | Tool | Description |
Vault CRUD |
| Read a note — full body, properties, outline, or a section |
| Create or overwrite a note with properties | |
| Heading-targeted edit (append, prepend, replace, insert) | |
| Find-and-replace text in a note | |
| Delete a block of lines by short anchors, no full re-quote | |
| List notes with optional glob/folder filter | |
| Delete a note (protected paths enforced) | |
| Move or rename a note, rewriting links across the vault | |
Search |
| Full-text search with tag/folder/property filters |
| Find notes by tag (exact or prefix match) | |
| Browse notes in a folder with metadata | |
| Recently modified or created notes | |
| All tags with usage counts | |
Memory |
| Read structured memory (file, section, or all) |
| Append a dated entry to a memory section | |
| Remove a specific memory entry by date | |
| Discover memory files and their sections | |
Properties |
| All property keys with sample values |
| Distinct values for a property key | |
| Find notes by property key-value | |
| Add or update properties without touching the body | |
Links |
| Notes linking to a given path |
| Links from a given note | |
| Notes with no incoming links | |
Daily Notes |
| Today's (or any date's) daily note |
Prompts (3)
Tools are model-driven — the assistant calls them. Prompts are workflows you trigger. Each one queries the search index, link graph, and memory layer at invocation time, then assembles the results with guided instructions — so the session starts grounded in your vault's actual state, not assumptions.
Prompt | Arguments | What it does |
| — | Surveys vault stats, folder distribution, property adoption rates (flags low adoption), orphans, broken link count, tags, recent notes, and the memory layer — with contextual tool suggestions |
|
| Structural overview (scope callouts, section entry counts) + dated content as a timeline. Guided reflection: evolution narrative, scope-fit, backfill gaps, and coverage analysis. Hidden when |
|
| Reviews a day's daily note with outgoing links (broken-link detection), backlinks, and date-specific activity — guides reconciliation, link following, and pattern recognition |
Prompts adapt to your configuration (MEMORY_DIR, daily-notes settings) and work for any vault out of the box. Pass max_chars to cap embedded content if your client has payload limits.
Client support: Prompts work in Claude Desktop (Chat and Cowork — via the + menu under your connector), Claude Code (slash commands), and OpenCode. Support in other clients (Cursor, Windsurf) varies — see the MCP clients matrix for the latest.
Properties
Vault Cortex indexes every property in your notes, but five get promoted treatment — dedicated columns for fast filtering, and top-level fields in every search and discovery result:
Property | What you can do |
| Display name in search results; falls back to the filename when missing |
| Search and filter by tag, including parent-child hierarchies ( |
| Filter by note type — |
| Sort by creation date and see when each note was created alongside every search result |
| Filter for notes that cross-reference a specific link — surfaces connections invisible without a graph query |
All other properties are still fully queryable — use vault_search with filters.properties for combined text + metadata queries, or vault_search_by_property for metadata-only lookups. vault_list_property_keys and vault_list_property_values discover what properties exist across your vault.
These are conventions, not requirements — Vault Cortex works with any property schema. Promoted properties just give you richer filtering and cleaner results out of the box.
Leading callouts get the same treatment. When a note's first body content is an Obsidian callout (> [!type]) — either right after frontmatter or right after the title heading — it's indexed and surfaced alongside every search and discovery result. This makes notes self-describing: an agent scanning results can see what each note is for before deciding which to read. The memory templates use > [!info] Scope of this file callouts for this, and any note in your vault can use the same pattern.
Configuration
All settings are environment variables with sensible defaults.
Variable | Required? | Default | Description |
| Yes | — | Bearer token for authentication (also the JWT signing key) |
| Local only | — | Host path to your vault (bind mount source; remote uses a named volume) |
| Remote only | — | Public URL for OAuth discovery metadata |
| — |
| Set |
| — |
| Vault folder for structured memory files |
| — |
| Folders that |
| — |
| Folders excluded from orphan detection |
| — |
| IANA timezone for timestamps and daily note resolution |
| — | GitHub repo URL | URL returned in OAuth discovery metadata |
| — |
| Logging verbosity: |
| — |
| Directory for persistent log files. Logs survive container restarts. |
| — |
| Days to keep log files before automatic cleanup on startup |
| — |
| On Windows? Set |
Smart defaults: Setting MEMORY_DIR automatically updates the defaults for PROTECTED_PATHS and ORPHAN_EXCLUDE_FOLDERS. You only set those explicitly for a fully custom list. When MEMORY_ENABLED is false, the memory layer is fully disabled — memory tools are hidden and the memory folder is not auto-created.
See templates/memory/ for memory file examples and the dated-entry design philosophy.
Authentication
For a server with read/write access to personal notes, authentication is not optional. Vault Cortex implements the full OAuth 2.1 specification, including PKCE and refresh-token rotation. The AWS (SST) deployment adds defense-in-depth: requests are validated at two independent layers (API Gateway Lambda authorizer + Express middleware). Per BlueRock's 2026 MCP security analysis, only 8.5% of MCP servers implement OAuth; 41% have no authentication at all.
Two methods:
Method | Used by | Token format |
OAuth 2.1 | Claude Desktop, Claude Code, claude.ai, any OAuth client | JWT (HS256, 24h) |
Static bearer | Claude Code, MCP Inspector, curl | Raw |
OAuth uses dynamic client registration — no Client ID/Secret needed. A consent page opens in your browser; enter your MCP_AUTH_TOKEN to approve. Refresh tokens have a 60-day sliding expiry (daily users never re-authenticate).
See ARCHITECTURE.md → Auth for the full flow diagram.
Deployment Options
Path | What | Guide |
Local | Docker on your machine, vault bind-mounted | |
Remote | VPS + Obsidian Sync, access from anywhere | |
AWS (SST) | Full IaC: Lightsail + API Gateway + Lambda + CI/CD |
Development
# Run locally with hot reload
PUBLIC_URL=http://localhost:8000 MCP_AUTH_TOKEN=local-dev-token VAULT_PATH=~/Vault npm run dev:mcp
# Tests
npm test
# Full check suite
npm run prettier:check && npm run lint && npm test && npm run buildMCP Inspector — interactive browser UI for testing tools:
# Start server (terminal 1), then:
npx @modelcontextprotocol/inspector
# Enter http://localhost:8000/mcp as URL, local-dev-token as Bearer tokenSee CONTRIBUTING.md for the full development setup.
Companion: obsidian-vault skill
The MCP server works on its own with any client. For agents that support skills (Claude Code, Cursor, Windsurf, Cline, and 70+ others), the obsidian-vault skill adds deeper knowledge of Obsidian-flavored markdown — frontmatter conventions, callout syntax, and plugin-specific formats like Dataview, Tasks, and Kanban.
npx skills add aliasunder/agent-skills --skill obsidian-vaultRoadmap
Phase | What | Status |
1 | Vault CRUD, full-text search (FTS5), memory layer, OAuth 2.1 | Complete |
2 | Hybrid search (FTS5 + vector) | In discovery |
Acknowledgments
Vault Cortex's remote capability exists because of @Belphemur's obsidian-headless-sync-docker — a headless Obsidian Sync client that runs in Docker without a display server. It's the piece that makes "access your vault from anywhere" possible. The remote stack runs a small fork that adds a build-time config chown and --device-name on the initial Sync registration (upstream PR #8 remains open).
Contributing
See CONTRIBUTING.md for development setup, code conventions, and PR guidelines.
License
Security
Report vulnerabilities privately — see SECURITY.md.
Maintenance
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/aliasunder/vault-cortex'
If you have feedback or need assistance with the MCP directory API, please join our Discord server