Install
$ agentstack add mcp-markfive-proto-obsidian-brain-vault ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Brain Vault — a knowledge base that writes itself
obsidian-brain-vault · CLI: obs · MCP: obs-mcp
The free, community-built implementation of Andrej Karpathy's LLM Wiki pattern: drop raw sources in, an LLM compiles them into an interlinked wiki, answers you save compound over time. Built to give AI agents persistent context that goes beyond a single chat session.
AI-first. Headless. MCP-ready. Works with Claude Desktop, Cursor, Windsurf, Claude Code. Any markdown folder — Obsidian-compatible today, vendor-neutral by design.
[](LICENSE) [](LICENSE) [](./README.md#connect-it-to-claude-desktop--cursor--windsurf-mcp)
The problem
Every AI chat starts from zero. You re-explain who you are, what you're building, what you already know. The session ends and your best thinking disappears.
Meanwhile you have 20 browser tabs you meant to read, a folder of PDFs you never opened, and 500 notes that never link to each other. RAG retrieves the same chunks forever — nothing accumulates. Note apps are graveyards you have to maintain yourself.
Your AI agents need persistent, compounding context. That's what obs gives them.
The KB loop
RAW sources → obs kb ingest → raw/
raw/ → obs kb compile → compiled/ concept pages
compiled/ → obs kb ask → outputs/ answers (filed back as new context)
Every ingest adds to the wiki. Every answer becomes part of the next answer. Source #50 links to ~10 existing pages and updates them — it doesn't sit alone.
obs kb ingest https://example.com/article # fetch + file to raw/
obs kb compile # LLM compiles raw/ → concept pages
obs kb ask "what do I know about X?" # query + save to outputs/
What obs gives you
- A wiki that compounds. Drop a URL, PDF, repo, transcript, or image. The LLM extracts concepts, cross-references everything you already have, and files it.
- Answers that stick. Ask a question. The answer is saved as a new note with wikilinks. Next question uses it as context.
- A built-in MCP server. Plug into Claude Desktop, Cursor, Windsurf, Claude Code. Your agents query the wiki natively — no copy-pasting context.
- Remote MCP hosting. Expose your vault over HTTPS so Claude.ai, mobile clients, or any AI tool can reach it from anywhere.
- Headless by design. Runs on a server, in CI, in a cron job. Obsidian doesn't need to be open.
- A Unix tool. Pipeable, scriptable,
--jsonon every command. Compose it with anything. - Three ways to use it. CLI for scripts and automation. Claude Code slash commands (
/clip,/compile,/ask,/lint) for conversational use. Claude Desktop MCP prompts for team workflows — all three speak the same underlying vault. - AutoDream. A nightly
compile → lint → statsjob that keeps your wiki fresh while you sleep. One script, works on macOS (launchd) and Linux (cron). - Ready-to-use scaffold. The [
knowledgebase/](./knowledgebase/) folder in this repo is a drop-in template — pre-structuredraw/,compiled/,outputs/,skills/(all packs included), with AutoDream tools. See [knowledgebase/README-KB.md](./knowledgebase/README-KB.md) for the quickstart.
Why obs — and how it differs from Obsidian's official CLI
Obsidian shipped their own official CLI in early 2026 (now free). It's excellent at what it does: remote-controlling the Obsidian app, triggering plugins, deploying vaults, integrating Obsidian into team toolchains. It requires Obsidian to be running.
obs is a different category of tool:
| | Official Obsidian CLI | obs (this project) | |---|---|---| | Requires Obsidian running | Yes | No — fully headless | | LLM knowledge compilation | No | Yes — the core feature | | ingest → compile → ask loop | No | Yes | | Built-in MCP server | No | Yes (obs-mcp) | | Remote MCP (HTTPS, mobile) | No | Yes (supergateway + cloudflared) | | Claude Code skill pack | No | Yes | | Works on a server / in CI | No | Yes | | Vendor-neutral (no Obsidian dep) | No | Yes | | Vault ops (tags, links, search…) | Via Obsidian's API | Direct file I/O, no app needed |
If you want to script Obsidian's UI — use their CLI. If you want an AI agent knowledge base that runs anywhere and accumulates context over time — that's obs.
2-minute quickstart
Option A — Use the scaffold (recommended)
Clone this repo and copy the pre-built scaffold into your Obsidian vault:
git clone https://github.com/markfive-proto/obsidian-brain-vault.git
cp -r obsidian-brain-vault/knowledgebase /path/to/your/vault/
Then open [knowledgebase/README-KB.md](./knowledgebase/README-KB.md) — it's the complete quickstart from inside the vault.
Option B — Fresh install
1. Install
# Requires Node 18+
pnpm add -g obsidian-brain-vault # or: npm i -g obsidian-brain-vault
# Verify
obs --version
2. Point obs at your vault
obs init # Auto-detects Obsidian vaults
# or
obs vault config defaultVault /path/to/vault
3. Start the loop
obs kb init # Scaffold raw/ compiled/ outputs/
obs kb ingest https://karpathy.ai/... # Add a source
obs kb compile # Fold it into the wiki
obs kb ask "what does my KB say about X?" # Query — answer saved to outputs/
obs kb stats # See the shape of your KB
You now have a vault structured like this:
your-vault/
├── raw/ sources you ingested (immutable)
│ ├── articles/
│ ├── papers/
│ ├── repos/
│ └── INGEST-LOG.md
├── compiled/ LLM-written wiki
│ ├── 00-INDEX.md
│ ├── concepts/ cross-referenced concept pages
│ ├── people/
│ └── orgs/
└── outputs/ answers, slides, charts, lint reports
├── answers/
├── slides/
└── lint/
Open the vault in Obsidian — everything is plain markdown with [[wikilinks]].
Three ways to use the KB loop
There are three interfaces to the same underlying vault — pick the one that fits your workflow:
| Interface | Best for | How | |---|---|---| | CLI | Scripts, automation, headless runs | obs kb ingest / compile / ask / lint | | Claude Code skills | Conversational coding sessions | /clip, /compile, /ask, /lint slash commands | | Claude Desktop prompts | Team workflows, Claude.ai, mobile | MCP prompt picker — select prompt, fill args |
All three write to the same vault. The wiki you build with the CLI is queryable via Claude Desktop and vice versa.
Use it with Claude Code
obs ships with a Claude Code skill pack. Every obs kb CLI command has a slash-command twin you can invoke in Claude Code conversations.
Install the skill pack
# Clone and link if you haven't already
git clone https://github.com/markfive-proto/obsidian-brain-vault.git
cd obsidian-brain-vault && pnpm install && pnpm build && pnpm link --global
# npm works too: npm install && npm run build && npm link
# Install a pack globally (available in all Claude Code projects)
obs skills install knowledge-base # The Karpathy pack (ingest/compile/qa/lint/render)
obs skills install capture # Brain-dump + quick-capture cognitive pack
# Or install to the current project only
obs skills install knowledge-base --local
Available slash commands
Once installed, in any Claude Code session:
| You type | Claude does | |---|---| | /clip | Fetches the page, cleans it to markdown, files it in raw/articles/ | | /paper | Extracts text + figures from a PDF into raw/papers/ | | /repo | Fetches README + key files into raw/repos/ | | /transcript | Pulls auto-captions into raw/transcripts/ | | /compile | Scans raw/ for new sources, generates/updates concept pages | | /ask | Queries the wiki, saves the answer to outputs/answers/ | | /deep | Multi-step research dive across the wiki | | /lint | Finds broken links, orphans, missing frontmatter, gaps | | /slides | Renders a Marp slide deck | | /brief | Renders a 1-page executive brief | | /chart | Renders a matplotlib chart |
Connect it to Claude Desktop / Cursor / Windsurf (MCP)
obs includes a built-in MCP server (obs-mcp) so any AI tool that speaks MCP can use your vault as a tool.
One-command setup (recommended)
obs setup --vault /absolute/path/to/your/vault
This auto-detects every AI editor you have installed (Claude Desktop, Claude Code, Cursor, Windsurf, Codex, OpenCode) and patches each config in one shot. Preview what it will do first:
obs setup --dry-run --vault /absolute/path/to/your/vault
Restart any editors that were patched. You'll see an 🔨 icon (Claude Desktop) or equivalent — click it to confirm obs_* tools are listed.
Manual setup (if you prefer)
Claude Desktop
# macOS
open ~/Library/Application\ Support/Claude/claude_desktop_config.json
# Windows
notepad %APPDATA%\Claude\claude_desktop_config.json
Add to mcpServers:
{
"mcpServers": {
"obs": {
"command": "obs-mcp",
"args": ["--vault", "/absolute/path/to/your/vault"]
}
}
}
Restart Claude Desktop.
Cursor
Add to ~/.cursor/mcp.json (or Settings → MCP → Add Server):
{
"mcpServers": {
"obs": {
"command": "obs-mcp",
"args": ["--vault", "/absolute/path/to/your/vault"]
}
}
}
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"obs": {
"command": "obs-mcp",
"args": ["--vault", "/absolute/path/to/your/vault"]
}
}
}
Claude Code (CLI)
claude mcp add obs obs-mcp --vault /absolute/path/to/your/vault
Remote MCP — expose your vault to Claude.ai, mobile, or any HTTP client
By default obs-mcp speaks stdio — it only works on the same machine. To use your vault from Claude.ai web chat, a second device, or any tool that only supports HTTP MCP, you need three layers:
| Layer | What it does | |---|---| | supergateway (streamableHttp mode) | Wraps obs-mcp stdio as an HTTP MCP endpoint | | OAuth proxy | Serves OAuth 2.1 + PKCE discovery so Claude mobile / web will accept the server | | Cloudflare Tunnel | Exposes localhost over HTTPS with zero port-forwarding |
> Why streamableHttp and not SSE? > SSE keeps a single long-lived connection per client. When a reverse proxy or the client reconnects, supergateway tries to call connect() on the same internal MCP instance and crashes. streamableHttp spawns a fresh stdio process for every POST — no persistent connection, no crash loop, no buffering issues.
> Why OAuth? > Claude mobile and Claude.ai web enforce RFC 8414 OAuth 2.1 discovery (/.well-known/oauth-authorization-server) before accepting any custom MCP server. Without it the server is silently rejected. The proxy auto-approves every authorization — actual security comes from keeping the endpoint URL private.
1. Install dependencies
npm i -g supergateway
# Node 18+ built-ins only needed for the OAuth proxy — no extra packages
2. Create the OAuth proxy
Save the following as ~/bin/obs-oauth-proxy.mjs (no npm dependencies — uses Node built-ins only):
#!/usr/bin/env node
// Minimal OAuth 2.1 + PKCE proxy in front of supergateway.
// Handles /.well-known/oauth-authorization-server + /oauth/* endpoints.
// Proxies everything else to supergateway on MCP_PORT.
import http from 'node:http'
import crypto from 'node:crypto'
import { URL } from 'node:url'
const PORT = parseInt(process.env.OAUTH_PORT ?? '4321')
const MCP_PORT = parseInt(process.env.MCP_PORT ?? '4322')
const BASE_URL = process.env.BASE_URL ?? 'https://obs-mcp.yourdomain.com'
const pendingCodes = new Map()
const validTokens = new Set()
function sendJson(res, status, body) {
const data = JSON.stringify(body)
res.writeHead(status, { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) })
res.end(data)
}
function parseBody(req) {
return new Promise((resolve, reject) => {
let buf = ''
req.on('data', c => buf += c)
req.on('end', () => {
try {
resolve(req.headers['content-type']?.includes('application/x-www-form-urlencoded')
? Object.fromEntries(new URLSearchParams(buf))
: JSON.parse(buf || '{}'))
} catch { resolve({}) }
})
req.on('error', reject)
})
}
function proxyToMcp(req, res) {
const opts = {
hostname: '127.0.0.1', port: MCP_PORT, path: req.url,
method: req.method, headers: { ...req.headers, host: `localhost:${MCP_PORT}` },
}
const proxy = http.request(opts, up => { res.writeHead(up.statusCode, up.headers); up.pipe(res) })
proxy.on('error', err => {
if (!res.headersSent) sendJson(res, 502, { error: 'mcp_unreachable', detail: err.message })
else res.destroy()
})
req.pipe(proxy)
}
http.createServer(async (req, res) => {
const url = new URL(req.url, `http://localhost:${PORT}`)
const path = url.pathname
if (req.method === 'GET' && path === '/.well-known/oauth-authorization-server') {
return sendJson(res, 200, {
issuer: BASE_URL,
authorization_endpoint: `${BASE_URL}/oauth/authorize`,
token_endpoint: `${BASE_URL}/oauth/token`,
response_types_supported: ['code'],
grant_types_supported: ['authorization_code'],
code_challenge_methods_supported: ['S256'],
scopes_supported: ['mcp'],
})
}
if (req.method === 'GET' && path === '/oauth/authorize') {
const redirectUri = url.searchParams.get('redirect_uri')
const state = url.searchParams.get('state')
const codeChallenge = url.searchParams.get('code_challenge')
if (!redirectUri) return sendJson(res, 400, { error: 'invalid_request' })
const code = crypto.randomBytes(20).toString('hex')
pendingCodes.set(code, { redirectUri, codeChallenge, expires: Date.now() + 600_000 })
const redirect = new URL(redirectUri)
redirect.searchParams.set('code', code)
if (state) redirect.searchParams.set('state', state)
res.writeHead(302, { Location: redirect.toString() })
return res.end()
}
if (req.method === 'POST' && path === '/oauth/token') {
const { grant_type, code, code_verifier } = await parseBody(req)
if (grant_type !== 'authorization_code') return sendJson(res, 400, { error: 'unsupported_grant_type' })
const stored = pendingCodes.get(code)
if (!stored || Date.now() > stored.expires) return sendJson(res, 400, { error: 'invalid_grant' })
if (stored.codeChallenge) {
if (!code_verifier) return sendJson(res, 400, { error: 'invalid_grant' })
const hash = crypto.createHash('sha256').update(code_verifier).digest('base64url')
if (hash !== stored.codeChallenge) return sendJson(res, 400, { error: 'invalid_grant' })
}
pendingCodes.delete(code)
const token = crypto.randomBytes(32).toString('hex')
validTokens.add(token)
return sendJson(res, 200, { access_token: token, token_type: 'bearer', expires_in: 31_536_000, scope: 'mcp' })
}
// GET on the MCP path → SSE keepalive stream (Claude mobile opens this for server-push)
if (req.method === 'GET' && path.endsWith('/mcp')) {
res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' })
res.write(': connected\n\n')
const ping = setInterval(() => { if (res.destroyed) return clearInterval(ping); res.write(': ping\n\n') }, 25_000)
req.on('close', () => clearInterval(ping))
return
}
proxyToMcp(req, res)
}).listen(PORT, '0.0.0.0', () => console.log(`[obs-oauth-proxy] :${PORT} → MCP :${MCP_PORT}`))
3. Create the gateway launch script
Save as ~/bin/run-obs-gateway.sh:
#!/bin/bas
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [markfive-proto](https://github.com/markfive-proto)
- **Source:** [markfive-proto/obsidian-brain-vault](https://github.com/markfive-proto/obsidian-brain-vault)
- **License:** MIT
- **Homepage:** https://supermarcus.ai/brain-os
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.