aliasunder/vault-cortex
БесплатноНе проверенMCP server for Obsidian vaults — search, memory, link graph, 23 tools, OAuth-protected.
Описание
MCP server for Obsidian vaults — search, memory, link graph, 23 tools, OAuth-protected.
README
Vault Cortex is a standalone MCP server that gives any AI agent hybrid search, task management, structured memory, and read/write access to your Obsidian vault. No plugins, no running Obsidian, no separate bridge. One Docker container, your vault folder, a full tool suite + guided prompts. 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 · Hybrid Search · Memory · Tasks · Tools · Prompts · Config · Data Integrity · Auth · Deployment
What you get
| Search the vault | Reason over notes | Write back to Obsidian |
![]() |
![]() |
![]() |
All three demos run on Claude mobile. The vault is on a remote server, not the phone.
- 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. - Hybrid search — FTS5 keyword matching + vector semantic similarity via RRF fusion, refined by cross-encoder reranking for intent-heavy queries. Keywords stay precise on exact terms and jargon; vectors find notes even when your words differ from the vault's.
- Structured memory — dated, append-only entries accumulate into a personal knowledge layer, auto-initialized for AI personalization. Topic recall answers "what do I think about X?" with the current take and the dated history behind it — evolution included.
- Tasks — Kanban-aware task queries and updates: triage by status, dates, or priority, then complete, reprioritize, or move tasks between lanes in one call. Parses both Tasks plugin emoji and Dataview inline-field formats.
- Link graph — backlinks, outgoing links, and orphan detection across the vault
- Obsidian-native — understands frontmatter, wikilinks, tags, headings, and daily notes
- Guided workflows — built-in prompts for vault health, memory review, and daily reconciliation — assembled from live vault data each time
Tested across a 15-day trip through Europe. 30+ sessions from a phone, 216 tool calls, zero laptop access needed. Writes in one session were immediately available in the next, across cities and days.
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 init
That'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.
Set up with the CLI? Upgrade later with npx vault-cortex upgrade (details →)
Manual setup (no Node.js needed)
# 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 up
Full 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 remote
That'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.
Set up with the CLI? Upgrade later with npx vault-cortex upgrade (details →)
Manual setup (no Node.js needed)
# 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 -d
Connect your MCP client
| Setup | Server URL |
|---|---|
| Local | http://localhost:8000/mcp |
| Remote | <PUBLIC_URL>/mcp |
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.
Claude Desktop (localhost requires mcp-remote bridge)
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["MCP server"]
Server -->|read/write| Vault[("/vault<br/>.md files")]
Server -->|FTS5 + vector| SQLite[("SQLite\nFTS5 + sqlite-vec")]
Sync["Obsidian Sync service"] <-->|Obsidian Sync| Vault
The search index is rebuildable derived state — FTS5 keyword tables rebuild on startup, vector embeddings persist across restarts with content-hash gating (only changed notes re-embed). A file watcher keeps both current, and queries fuse both signals via Reciprocal Rank Fusion. The sync service keeps the vault in sync with your Obsidian apps — it ships inside the same container in the :remote image variant (remote deployments only; the default :latest image is the MCP server alone).
See ARCHITECTURE.md for the full design, auth flow diagrams, and component breakdown.
Hybrid Search
Keyword search alone fails when your vocabulary doesn't match the vault's — "aspirations" won't find a note about "targets", "coworkers" won't surface your "references" file. In testing against a real vault, 30% of natural-language queries returned zero or tangential results with keywords alone. Hybrid search eliminated those misses — vectors bridge the vocabulary gap, and the reranker rescues intent-heavy queries where neither signal is strong on its own.
Hybrid search combines three ranking signals via Reciprocal Rank Fusion:
- Keywords (FTS5) stay precise on exact terms, jargon, and property values
- Vectors (sqlite-vec) bridge the vocabulary gap by matching on meaning
- Reranker (cross-encoder) refines ordering by scoring each query-document pair jointly — rescues intent-heavy queries where keywords and vectors both miss
All models run locally (~45MB total, no external API). Set EMBEDDING_ENABLED=false for keyword-only search, or RERANK_MODE=none to skip reranking for lower latency.
See ARCHITECTURE.md → Hybrid Search for model details, blend weights, and the full pipeline breakdown.
Memory
A memory layer that only grows is only useful if agents can retrieve the right entries without dumping everything into context. Once you have hundreds of dated entries across multiple files — preferences, principles, communication style, ongoing commitments — reading whole files wastes context on irrelevant material and buries the signal. The memory system is designed for targeted retrieval: agents accumulate knowledge over time and recall exactly what's relevant to the task at hand.
The layer is a folder of plain Markdown files (default: About Me/) holding dated entries under topic headings — auto-created with starter templates on first run, grown by agents through vault_update_memory. Three properties make it work:
- Append-only — entries are never overwritten; corrections arrive as new dated entries. The layer becomes a personal knowledge base that captures your current state and the evolution behind it
- Topic recall —
vault_memory_recallretrieves every relevant entry across all memory files at once, keyword- and semantically-matched, oldest first. Ask "what do I think about X?" and get the current take plus the dated history of how it developed — no need to read entire files or guess which file holds what - Grows without degrading — capping results (
max_results) drops the least-relevant entries, never a slice of the timeline. A memory layer with 500 entries serves a targeted query as well as one with 50
Files that describe what's current rather than what has been true (routines, active commitments) can declare entry-policy: living in frontmatter — their expired entries are prunable rather than preserved, keeping the current-state picture accurate.
See templates/memory for the file format, entry-policy convention, and starter templates.
Tasks
Task metadata lives in plain markdown — scattered across files, encoded in emoji signifiers or inline fields, organized under Kanban headings. An agent answering "what's overdue?" would need to parse every file and understand your chosen format; completing a task on a Kanban board means knowing the board's lane structure, the date syntax, and which heading is the done lane.
The task layer handles this so agents don't have to:
- Find — filter by status, six date fields (due, scheduled, start, created, done, cancelled), priority, folder, or Kanban lane. Each result carries its lane, note path, heading, and line number — no follow-up reads needed to locate a task
- Update — complete, reprioritize, and move tasks between Kanban lanes in a single call. Marking a task done auto-detects the done lane and stamps the completion date; reversing it removes the date. All three changes can happen at once
- Both formats — whichever format you use, Tasks plugin emoji signifiers or Dataview inline fields, the server reads both and writes in the format your Tasks plugin is configured for
See ARCHITECTURE.md → Tasks for the indexing model, date cascade sorting, and Kanban lane detection.
Tools
| Category | Tool | Description |
|---|---|---|
| Vault CRUD | vault_read_note |
Read a note — full body, properties, outline, or a section |
vault_write_note |
Create a note (fails if it already exists; set overwrite to replace) |
|
vault_patch_note |
Heading-targeted edit (append, prepend, replace, insert) | |
vault_replace_in_note |
Find-and-replace text in a note | |
vault_delete_span |
Delete a block of lines by short anchors, no full re-quote | |
vault_list_notes |
List notes with optional glob/folder filter | |
vault_delete_note |
Delete a note (protected paths enforced) | |
vault_move_note |
Move or rename a note, rewriting links across the vault | |
| Search | vault_search |
Hybrid search with tag/folder/property/date filters |
vault_search_by_tag |
Find notes by tag (exact or prefix match) | |
vault_search_by_folder |
Browse notes in a folder with metadata | |
vault_recent_notes |
Recently modified or created notes | |
vault_list_tags |
All tags with usage counts | |
| Tasks | vault_list_tasks |
Vault-wide task index — Kanban-aware, 6 date fields, priority, folder/heading scope |
vault_update_task |
One-call status, priority, and lane changes — auto-detects done lanes on Kanban boards | |
| Memory | vault_get_memory |
Read structured memory (file, section, or all) |
vault_update_memory |
Append a dated entry to a memory section | |
vault_delete_memory |
Remove a specific memory entry by date | |
vault_list_memory_files |
Discover memory files, their sections, and each file's entry policy | |
vault_memory_recall |
Entry-granular hybrid recall of a topic across memory files, oldest-first | |
| Properties | vault_list_property_keys |
All property keys with sample values |
vault_list_property_values |
Distinct values for a property key | |
vault_search_by_property |
Find notes by property key-value | |
vault_update_properties |
Add or update properties without touching the body | |
| Links | vault_get_backlinks |
Notes linking to a given path |
vault_get_outgoing_links |
Links from a given note | |
vault_find_orphans |
Notes with no incoming links | |
| Daily Notes | vault_get_daily_note |
Today's (or any date's) daily note |
Prompts
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 |
|---|---|---|
vault-orientation |
— | 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 |
memory-review |
file?, max_chars? |
Structural overview (scope callouts, section entry counts) + dated content as a timeline. Guided reflection: evolution narrative, scope-fit, backfill gaps, and coverage analysis — append-only by default, pruning proposed only for entry-policy: living files. Hidden when MEMORY_ENABLED=false. |
daily-review |
date?, max_chars? |
Reconciles a day — daily note, vault-wide task status (due/overdue, scheduled), modified notes, outgoing links (broken-link detection), and backlinks — surfaces what happened, what's open, and what needs follow-up |
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 |
|---|---|
title |
Display name in search results; falls back to the filename when missing |
tags |
Search and filter by tag, including parent-child hierarchies (project matches project/vault-cortex) |
type |
Filter by note type — meeting, person, session-log, or any value your vault uses |
created |
Sort by creation date and see when each note was created alongside every search result |
related |
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 |
|---|---|---|---|
MCP_AUTH_TOKEN |
Yes | — | Bearer token for authentication (also the JWT signing key) |
VAULT_PATH |
Local only | — | Host path to your vault (bind mount source; remote uses a named volume) |
PUBLIC_URL |
Remote only | — | Public URL for OAuth discovery metadata |
EMBEDDING_ENABLED |
— | true |
Set false to disable the embedding pipeline — skips model download, vector tables, embedding passes, and hybrid search. Search falls back to FTS5 keyword matching. |
RERANK_MODE |
— | blended |
Cross-encoder reranking mode: blended applies position-aware score blending after RRF fusion (~200ms added latency), none skips reranking. Only takes effect when EMBEDDING_ENABLED is true. |
MEMORY_ENABLED |
— | true |
Set false to fully disable the memory layer — hides memory tools, skips bootstrap, omits memory from server metadata. MEMORY_DIR is ignored when false. |
MEMORY_DIR |
— | About Me |
Vault folder for structured memory files |
PROTECTED_PATHS |
— | MEMORY_DIR, Daily Notes |
Folders that vault_delete_note refuses to touch |
ORPHAN_EXCLUDE_FOLDERS |
— | Daily Notes, Templates, MEMORY_DIR |
Folders excluded from orphan detection |
TZ |
— | UTC |
IANA timezone for timestamps and daily note resolution |
SERVICE_DOCUMENTATION_URL |
— | GitHub repo URL | URL returned in OAuth discovery metadata |
LOG_LEVEL |
— | info |
Logging verbosity: debug, info, warn, error |
LOG_DIR |
— | /data/logs (remote), unset (local) |
Directory for persistent log files. When set, logs are written to date-stamped files there alongside stdout. Unset means stdout only. |
LOG_RETENTION_DAYS |
— | 30 |
Days to keep log files before automatic cleanup on startup |
WINDOWS_MODE |
— | false |
On Windows? Set true. Switches the file watcher to polling and note moves to rename-based writes so a vault on a C: drive works through Docker Desktop. Safe to leave on for any Windows setup; unneeded on macOS/Linux/WSL2. |
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.
Data Integrity
Vault Cortex writes to personal notes — the file safety layer is built to prevent corruption, not just errors.
- Atomic writes — every file write stages to a temp file, then renames. Readers never see a partial or 0-byte note. Exclusive creates use
link()(POSIX no-clobber) to close the TOCTOU window on note moves. - Per-file mutex — concurrent MCP tool calls serialize or fail-fast per file. Moves lock the source, destination, and every backlink source as one unit.
- Path traversal blocked —
resolveSafePath()resolves then prefix-checks every path. Protected-path deletion is refused after normalization. Memory file names reject separators at the boundary. - Injection prevention — search queries are parameterized and FTS5-sanitized; prompt content is wrapped in XML data markers with closing-tag escaping to prevent tag-breakout injection.
- Container hardening — non-root user, PID 1 init (
tini), no package managers in the runtime image, digest-pinned base, log rotation.
See ARCHITECTURE.md → Data Integrity for mechanism details and SECURITY.md → Runtime Hardening for the full attack-surface inventory.
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 MCP_AUTH_TOKEN |
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
Local runs on your machine. Remote deployments run on a VPS — your vault is accessible even when your laptop is closed.
| Path | What | Guide |
|---|---|---|
| Local | Your vault on your machine — free, no cloud | deploy/local/ |
| Remote | VPS + Obsidian Sync — access from any device | deploy/remote/ |
| AWS (SST) | IaC reference deployment — automated infra, defense-in-depth auth | DEPLOY.md |
The AWS path includes CI/CD workflows built for this repo — forkers need to configure their own credentials and stage before deploying.
All three paths run the same image, ghcr.io/aliasunder/vault-cortex — :latest is the MCP server alone (local), :remote bundles Obsidian Sync in the same container under s6-overlay supervision (remote and AWS). One container means any OCI runtime works: docker run, Podman, nerdctl — Docker Compose is optional.
Also on Docker Hub: the same images are mirrored to aliasunder/vault-cortex. GHCR is the primary source; Hub tags are identical.
Cost: A remote setup needs a VPS and $5/mo for Obsidian Sync. A 2 GiB instance handles semantic search fine for a typical vault; 4 GiB adds headroom for concurrent search and larger vaults. Skip semantic search entirely to go smaller still. Local-only is free. The reference AWS deployment runs ~$18–30/mo all-in.
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 build
MCP 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 token
See 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-vault
Roadmap
| Phase | What | Status |
|---|---|---|
| 1 | Vault CRUD, full-text search (FTS5), memory layer, OAuth 2.1 | Complete |
| 2a | Hybrid search — FTS5 + vector + RRF fusion, heading-aware chunking | Complete |
| 2b | Reranker — cross-encoder reranking, position-aware score blending | Complete |
| 3a | Task layer — vault-wide task index, structured queries, and one-call task updates (Tasks plugin emoji + Dataview formats) | Complete |
| 3b | Memory recall — entry-granular retrieval across the memory layer's dated history | Complete |
| 3c | Graph queries — multi-hop traversal over the vault's existing wikilink graph (paths, neighborhoods) | Exploring |
Acknowledgments
Obsidian sync is powered by obsidian-headless — containerization approach inspired by @Belphemur's obsidian-headless-sync-docker. The :remote image's s6-overlay supervision scaffolding was absorbed from that project's maintained fork and now lives in this repo.
The hybrid search pipeline draws on patterns from @tobi's qmd — RRF fusion with rank bonuses, position-aware score blending for cross-encoder reranking, content-hash gating, and heading-aware chunking.
Contributing
See CONTRIBUTING.md for development setup, code conventions, and PR guidelines.
License
The :remote image bundles obsidian-headless
(the ob CLI), which is proprietary — its package.json declares "license": "UNLICENSED"
(© Dynalist Inc. / Obsidian). It is installed from public npm at build time; the MIT license here
does not cover it, and using it requires an active Obsidian Sync subscription. The :latest
(local) image contains no proprietary components.
Security
Report vulnerabilities privately — see SECURITY.md.
Установка aliasunder/vault-cortex
У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.
▸ github.com/aliasunder/vault-cortexFAQ
aliasunder/vault-cortex MCP бесплатный?
Да, aliasunder/vault-cortex MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для aliasunder/vault-cortex?
Нет, aliasunder/vault-cortex работает без API-ключей и переменных окружения.
aliasunder/vault-cortex — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить aliasunder/vault-cortex в Claude Desktop, Claude Code или Cursor?
Открой aliasunder/vault-cortex на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare aliasunder/vault-cortex with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development



