π§ Obsidian Everywhere
Your Obsidian vault, as a graph, in every Claude client.
Local Claude Code Β· Claude Desktop Β· a remote box over Tailscale Β· claude.ai web & mobile β one server, every surface.
This is a graph server, not a markdown file server. Claude shouldn't seeyour vault as "a folder of .md files" β it should see notes and links as agraph: backlink traversal, n-hop neighborhoods, and topic-centered contextbundles are first-class tools, not an afterthought bolted onto a filereader. Unresolved links stay in the graph (that's a real signal about yourvault, same as it is in Obsidian itself), and every response is structuredfor what an LLM actually needs β explicit link relationships, not just rawtext.
Contents
- Features
- Where does this actually run?
- Quickstart
- Configuration
- Development
- Project status
- Contributing
- License
Features
vault (.md files)
β parse Β· watch
βΌ
SQLite index (FTS5) β in-memory graph (graphology)
β n-hop Β· shortest path Β· PageRank
βΌ
14 MCP tools
β
βΌ
stdio Β· bearer-token HTTP Β· OAuth HTTP
- π§© Real graph engine β a markdown parser (wikilinks, embeds,frontmatter, nested tags, headings, block references), a SQLite indexwith full-text search, and an in-memory graphologylayer for n-hop traversal, shortest paths, and PageRank β kept in syncincrementally as files change, never rebuilt from scratch.
- π οΈ 14 graph-native MCP tools β 12 read-only, 2 write.
- π Three ways to connect β stdio for local Claude clients,Streamable HTTP with a static bearer token for a remote Claude Code overTailscale, and Streamable HTTP with OAuth 2.1 (PKCE + Dynamic ClientRegistration) for the claude.ai custom connector.
Read
| Tool | What it does |
|---|---|
vault_overview |
Note counts, top tags, PageRank hub notes, recently modified β a starting orientation |
search_notes |
Full-text search with tag/folder filters, each result annotated with link counts and tags |
read_note |
Full note + graph context header (outlinks/backlinks/tags/frontmatter); optional heading-scoped read |
get_backlinks |
Every note linking to a given note, with the linking sentence |
get_neighborhood |
Explicit n-hop node/edge list around a note (links treated as undirected) |
get_context_bundle |
The killer feature. Center note + prioritized 1-hop neighbors packed into a token budget |
list_tags |
Full nested tag hierarchy with counts |
get_notes_by_tag |
Notes carrying a given tag (nested-aware) |
find_orphans |
Notes with no incoming or outgoing links |
find_unresolved |
Links that don't resolve to any note, grouped by target |
find_path |
Shortest connection path between two notes, with a one-line summary per hop |
get_related |
Similar notes that aren't directly linked yet (Jaccard similarity over shared tags/neighbors) |
Write
| Tool | What it does |
|---|---|
create_note |
Create a new note (with frontmatter); reindexed immediately β the next tool call already sees it |
append_to_note |
Append to a note, optionally under a specific heading; fails closed if the heading isn't found |
create_note/append_to_note are on by default for stdio and thebearer-token HTTP transport, and off by default for the public OAuthconnector transport (opt in with OAUTH_ENABLE_WRITE_TOOLS=true) β seeConfiguration and DECISIONS.md D15.
See docs/architecture.md for how it's built anddocs/deploy.md for the full deployment topology(LaunchAgent, Docker, Cloudflare Tunnel).
Where does this actually run?
The obsidian-everywhere process needs direct filesystem access to yourvault's .md files (to parse them, watch for changes, etc.) β so itmust always run on the machine where your vault physically lives("the vault machine": your laptop, most likely). It does not matter whereyou're typing claude from β the server always runs on the vaultmachine; only the client connection method changes.
Where you run claude from |
What you need |
|---|---|
| The same machine as the vault | stdio. Nothing else β Claude Code/Desktop spawns the server directly. |
| A different machine you control (a lab/work server, another laptop, an SSH box) | Bearer-token HTTP + a private network between the two machines (we recommend Tailscale β free, five-minute setup, works across NAT/firewalls without port forwarding). |
| claude.ai (web app or mobile app) | OAuth HTTP + a public HTTPS URL (via Cloudflare Tunnel). claude.ai runs in Anthropic's cloud, not your network, so it can't reach Tailscale or localhost β it needs a real public address. |
You can run more than one of these at once (e.g. stdio on your laptopand bearer-token HTTP for your work server) β they're independentprocesses that all index the same vault.
Quickstart
Run this on the vault machine (wherever your .md files live):
git clone https://github.com/junnnnnw00/obsidian-everywhere.git
cd obsidian-everywhere
npm install
npm run build
Option A β Claude Code, same machine as the vault (stdio)
Still on the vault machine:
claude mcp add obsidian-everywhere -- node "$(pwd)/dist/cli.js" /path/to/your/vault
Or with environment variables instead of a positional arg:
OBSIDIAN_VAULT_PATH=/path/to/your/vault claude mcp add obsidian-everywhere -- node "$(pwd)/dist/cli.js"
Option Aβ² β Claude Desktop, same machine as the vault
Add to claude_desktop_config.json on the vault machine:
{
"mcpServers": {
"obsidian-everywhere": {
"command": "node",
"args": ["/absolute/path/to/obsidian-everywhere/dist/cli.js", "/absolute/path/to/your/vault"]
}
}
}
Option B β Claude Code on a different machine (a lab/work server, etc.)
Step 1 β set up a private network between the two machines, if youdon't have one already. Easiest option is Tailscale:
# on BOTH the vault machine and the machine you'll run `claude` from
curl -fsSL https://tailscale.com/install.sh | sh # or: brew install tailscale (macOS)
tailscale up # opens a browser to log in / join your "tailnet"
tailscale status # confirm both machines can see each other
Note the vault machine's Tailscale hostname/IP from tailscale status(something like my-macbook.tailnet-name.ts.net or 100.x.y.z).
Step 2 β start the server, on the vault machine:
OBSIDIAN_VAULT_PATH=/path/to/vault OBSIDIAN_EVERYWHERE_TOKEN=$(openssl rand -hex 32) \
node dist/http-cli.js
Keep this token β you'll need it in step 3. (To keep this runningpersistently instead of in a foreground terminal, see the LaunchAgentsetup in docs/deploy.md,or run it in Docker via docker-compose.yml if the vault machine is a server.)
Step 3 β connect from the other machine (the lab server, etc. βwherever you actually type claude), using the vault machine's Tailscaleaddress from step 1:
claude mcp add --transport http obsidian-everywhere \
http://<vault-machine-tailscale-name>:3737/mcp \
--header "Authorization: Bearer <the token from step 2>"
That's it β claude on the second machine now has full access to thevault indexed on the first. Full walkthrough (Docker, LaunchAgent):docs/deploy.md.
Option C β claude.ai web/mobile app (custom connector, OAuth)
This needs a public HTTPS endpoint β claude.ai's servers can't reach yourTailscale network or localhost. Seedocs/deploy.mdfor the full Cloudflare Tunnel walkthrough (including the no-domain-neededQuick Tunnel option for testing). Once your server is reachable athttps://your-domain:
- claude.ai β Settings β Connectors β Add custom connector
- Server URL:
https://your-domain/mcp - claude.ai auto-discovers the OAuth flow and shows this server's sign-inpage β enter the
OAUTH_LOGIN_SECRETyou configured.
You only need this if you actually want claude.ai's web/mobile apps toread your vault. If you only ever use Claude Code (locally or fromanother machine), skip this entirely β Option A/B already fully coversthat with no Cloudflare/OAuth involved.
Configuration
| Env var | Used by | Meaning |
|---|---|---|
OBSIDIAN_VAULT_PATH |
all | Vault path (or pass as a positional CLI arg) |
OBSIDIAN_EVERYWHERE_DB |
all | SQLite index path (default: <vault>/.obsidian-everywhere/index.db) |
OBSIDIAN_EVERYWHERE_TOKEN |
http-cli.js |
Static bearer token |
PORT |
http-cli.js, oauth-http-cli.js |
HTTP port (defaults 3737 / 3738) |
OAUTH_ISSUER_URL |
oauth-http-cli.js |
Public HTTPS origin (e.g. your Cloudflare Tunnel hostname) |
OAUTH_LOGIN_SECRET |
oauth-http-cli.js |
Single-user login secret |
OBSIDIAN_EVERYWHERE_READONLY |
cli.js, http-cli.js |
Set to true to disable create_note/append_to_note (default: write tools on) |
OAUTH_ENABLE_WRITE_TOOLS |
oauth-http-cli.js |
Set to true to enable create_note/append_to_note on the public connector (default: off) |
Development
npm run dev:stdio # tsx, no build step
npm run dev:http
npm run dev:oauth-http
npm test # vitest, runs against fixtures/test-vault
npm run typecheck
npm run lint
npm run format:check
fixtures/test-vault/ is a 30+ note fixture vault exercising every linkand parsing edge case the parser needs to handle (piped aliases, headingand block links, embeds, frontmatter-embedded wikilinks, nested tags,duplicate filenames across folders, unresolved links, code-blockexclusion, and Korean filenames/tags/wikilinks). It's what every test insrc/**/*.test.ts runs against.
Project status
v0.1, feature-complete: full graph engine, all three transports (stdio,bearer-token HTTP, OAuth HTTP), 14 MCP tools including write tools. A fewthings need a human to finish (registering the claude.ai connector, anactual Cloudflare Tunnel account) since they require a browser/account βsee docs/deploy.md. Tested against both the fixture vault and a real58-note personal vault with Korean content.
Contributing
Bug reports, feature requests, and PRs are welcome β seeCONTRIBUTING.md for dev setup, testing conventions,and how the fixture vault relates to the test suite. Security issues:please see SECURITY.md rather than opening a public issue.
License
MIT β see LICENSE.