Run Vault Cortex on your machine against a local Obsidian vault. No cloud, no
Obsidian Sync — just Docker and a folder of .md files.
Contents — Prerequisites · Setup · Connect · Verify · Updating · Stop · Windows · Memory · File Tools · Config · Troubleshooting
- Docker (v20.10+)
- Node.js >= 20.12 — only for the CLI setup below; the manual setup needs just Docker
- An Obsidian vault (or any folder of Markdown files)
npx vault-cortex@latest initThe 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 (CLI reference →).
What happens on first start:
- The image is pulled (~150MB)
- The keyword index builds in seconds — search works right away
- The semantic (embedding) index builds in the background — expect a few minutes on a large vault, with search served keyword-only until it finishes
On Windows? Set
WINDOWS_MODE=truein your.env— thenVAULT_PATHcan point at a normal Windows path likeC:\Users\you\MyVault. With the CLI, edit the generated.envafterinitand apply withnpx vault-cortex@latest upgrade. See Windows (Docker Desktop) below.
Manual setup (no Node.js needed)
1. Get the files. Download this directory, or clone the repo and cd deploy/local.
2. Create your .env file:
cp .env.example .env3. Fill in the two required values:
| Variable | Value |
|---|---|
MCP_AUTH_TOKEN |
Generate with openssl rand -hex 32 |
VAULT_PATH |
Absolute path to your vault (e.g. /Users/you/Documents/MyVault) |
4. Start the server:
docker compose upAdd -d to run in the background.
The server listens at http://localhost:8000/mcp.
- "Remote" refers to the connection type (HTTP, as opposed to a stdio process the client launches itself) — this server still runs entirely on your machine.
- Claude Mobile and claude.ai web can't reach localhost — use the remote quickstart for access from other devices.
-
Add the server:
claude mcp add --scope user --transport http vault-cortex http://localhost:8000/mcp
--scope userregisters it for every project; drop it to scope the server to the current directory only. -
Approve the consent page with your
MCP_AUTH_TOKEN(a browser tab opens automatically). -
Done. The client receives auto-refreshing access tokens, so the token itself never sits in client config.
The "Add custom connector" dialog only accepts https URLs, so a localhost
server can't be added there. Register it in claude_desktop_config.json
(Settings → Developer → Edit Config) through
mcp-remote — a small helper that lets
Claude Desktop talk to a local HTTP server:
{
"mcpServers": {
"vault-cortex": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"http://localhost:8000/mcp",
"--header",
"Authorization: Bearer <your MCP_AUTH_TOKEN>"
]
}
}
}On Windows, spaces inside args can be mangled — move the header value into
an env var instead: "--header", "Authorization:${AUTH_HEADER}" with
"env": { "AUTH_HEADER": "Bearer <your MCP_AUTH_TOKEN>" }.
- Add
http://localhost:8000/mcpas a remote MCP server, leaving OAuth Client ID and Secret empty. - A consent page opens in your browser — approve with your
MCP_AUTH_TOKEN. - Done. The client receives auto-refreshing access tokens, so the token itself never sits in client config.
Enter http://localhost:8000/mcp as the server URL and your token as the
Bearer token.
curl:
curl -H "Authorization: Bearer <your-token>" http://localhost:8000/mcp# Health check (no auth required):
curl http://localhost:8000/healthz
# → {"ok":true}
# OAuth discovery (no auth required):
curl http://localhost:8000/.well-known/oauth-protected-resourceUpdate with the same method you set up with — the CLI and Compose manage the container independently.
Set up with the CLI?
npx vault-cortex@latest upgradeRun it from the same directory where you ran init — it pulls the new image
and re-creates the container for you. Nothing is deleted — see
upgrade in the CLI reference for what's preserved
and the --dir flag.
Set up with Docker Compose? Compose does not pull new images on
up, so pull explicitly:
docker compose pull && docker compose up -dSet up with the CLI?
# Stop (data persists in Docker volumes):
docker stop vault-cortexSet up with Docker Compose?
# Stop (data persists in Docker volumes):
docker compose down
# Stop and delete all volumes (index rebuilds on next start):
docker compose down -vvault-cortex runs in a Linux container, so on Windows it reaches your vault through
Docker Desktop's WSL2 bridge. Two things need a non-default code path across that
bridge: live re-indexing (the file watcher's native filesystem events don't cross it)
and vault_move_note (its atomic hard-link write isn't supported there). Setting
WINDOWS_MODE=true handles both — the watcher switches to polling and moves use a
rename-based write — so a vault on a C:\ drive works out of the box:
# in .env
VAULT_PATH=C:\Users\you\MyVault
WINDOWS_MODE=trueWINDOWS_MODE is safe to leave on for any Windows setup; reading, writing, and search
work with or without it — it only changes how re-indexing and moves are done.
For best performance, keep the vault inside the WSL2 filesystem (ext4) instead —
native filesystem events are lighter than polling, and you can leave WINDOWS_MODE
off:
# inside WSL (e.g. Ubuntu) — vault lives on ext4
mkdir -p ~/vaults/MyVault
# then in .env: VAULT_PATH=/home/you/vaults/MyVaultYou can still open and edit a WSL-hosted vault in Obsidian on Windows — it shows up in
File Explorer at \\wsl$\Ubuntu\home\you\vaults\MyVault.
The memory layer is enabled by default. Set MEMORY_ENABLED=false in your
.env to disable it — memory tools are hidden, no files are created, and the
server runs without it.
When enabled, the server creates a memory folder (default: About Me/) with
starter template files on first startup, and agents grow it from there. See
Memory in the main README for how the layer works,
and templates/memory for the file format.
File tools (vault_read_file, vault_list_files) are enabled by default. Set
FILE_TOOLS_ENABLED=false in your .env to hide them — useful when Obsidian
Sync has attachment syncing disabled and no files exist on disk.
Only MCP_AUTH_TOKEN and VAULT_PATH are required. For optional settings
(memory folder, protected paths, orphan exclusions, file tools, timezone), see
the Configuration section in the main README.
invalid_client / "Invalid client_id" when connecting. Your MCP client
saved login details from a previous server at this address, and the new server
doesn't recognize them. Recreating the server (docker compose down -v, or
scaffolding a fresh instance) resets oauth.db, so the cached client_id no
longer exists and /authorize rejects it. Clear the client's stored
authorization for this server and reconnect so it registers fresh:
- Claude Code:
claude mcp remove <name>, thenclaude mcp add --scope user --transport http <name> http://localhost:8000/mcp. - Claude Desktop / mcp-remote: delete
~/.mcp-authand restart the client. - Other clients: remove and re-add the server.
"Invalid token" on the consent page even with the correct token. The
consent form trims surrounding whitespace and line breaks from the token before
checking it, so a value copied out of a terminal (where a long token can wrap
across lines) still works. If you still see this error, double-check you copied
the full MCP_AUTH_TOKEN from your .env — a missing or extra character is the
usual cause.
"container name vault-cortex already in use" on start or upgrade. A
container from a different management method is still running. The CLI
(npx vault-cortex@latest upgrade) and Docker Compose (docker compose up -d)
manage the container independently — stop the existing one first with
docker rm -f vault-cortex, then retry with your preferred method.
If you want to modify vault-cortex and build from source, clone the repo and
use docker-compose.local.yml in the repo root instead. See
CONTRIBUTING.md for the full development setup.