Run Vault Cortex on your machine against a local Obsidian vault. No cloud, no
Obsidian Sync — just Docker and a folder of .md files.
Fastest path:
npx vault-cortex@latest initdoes all of the below interactively — generates the token and config files, starts the server, and prints the connection details. The steps below are the manual equivalent.
- Docker (v20.10+)
- An Obsidian vault (or any folder of Markdown files)
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) |
On Windows? Set
WINDOWS_MODE=truein your.env— thenVAULT_PATHcan point at a normal Windows path likeC:\Users\you\MyVault. See Windows (Docker Desktop) below.
4. Start the server:
docker compose upAdd -d to run in the background. First start pulls the image (~150MB) and
builds the search index — this takes a few seconds depending on vault size.
The server listens at http://localhost:8000/mcp.
Claude Code:
- Run
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 in your browser with your
MCP_AUTH_TOKEN. - Done. The client receives auto-refreshing access tokens, so the token itself never sits in client config.
Claude Desktop: 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 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>"
]
}
}
}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>" }.
Other OAuth clients (Cursor and most MCP clients):
- 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.
- "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.
Bearer token (MCP Inspector, scripts, clients without OAuth): 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-resource# Stop the server (search index is preserved in a Docker volume):
docker compose down
# Stop and delete all data (index rebuilds on next start):
docker compose down -vinvalid_client / "Invalid client_id" when connecting. Your MCP client
cached an OAuth registration from a previous server at this address. 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.
vault-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.
On first startup, if your vault doesn't already have a memory folder (default:
About Me/), the server creates one with template files (Me.md, Opinions.md,
Principles.md). Agents can also create new memory files and sections on the fly
via vault_update_memory — no manual setup needed.
Only MCP_AUTH_TOKEN and VAULT_PATH are required. For optional settings
(memory folder, protected paths, orphan exclusions, timezone), see the
Configuration section in the main README.
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.