obsidian-mcp
# obsidian-mcp
An MCP server that gives Claude a per-project notes folder inside one local Obsidian vault.
Each project gets its own subfolder under `<vault>/Projects/<project-slug>/`. There is still a
single vault, so cross-project links and the graph view keep working — you never have to switch
vaults in Obsidian.
## Tools
| Tool | What it does |
| --- | --- |
| `resolve_project` | Report which project folder notes will go to, and how that was decided. |
| `write_note` | Create a note. Refuses to clobber an existing one unless `overwrite: true`. |
| `read_note` | Read a note's full contents. |
| `append_note` | Append to the end of a note, creating it if absent. |
| `list_notes` | List notes in the project, or across the whole vault with `scope: "vault"`. |
| `search_notes` | Case-insensitive text search returning `note:line: text` matches. |
Every tool takes an optional `project` argument that overrides inference.
## How the project is chosen
1. An explicit `project` argument, if given.
2. Otherwise, walk up from the server's working directory to the nearest `.git` and use that
directory's name — so a call made from `~/Developer/Projects/foo/src/lib` still resolves to
`foo`.
3. Otherwise, use the working directory's own name.
Names are slugified: `Job Search` becomes `job-search`.
If inference lands on a container directory (`Developer`, `Projects`, `src`, `$HOME`, …) the
server refuses to guess and asks for an explicit `project`. That is the intended behavior, not a
bug — guessing there would scatter notes into a folder named after nothing in particular.
**In Claude Desktop, always pass `project` explicitly.** Desktop spawns MCP servers with an
arbitrary working directory, so there is nothing meaningful to infer from. Claude Code inherits
its own working directory, so inference works there.
## Configuration
| Variable | Default |
| --- | --- |
| `OBSIDIAN_VAULT_PATH` | `~/Documents/Obsidian Vault` |
| `OBSIDIAN_PROJECTS_DIR` | `Projects` (relative to the vault root) |
The vault itself must already exist — the server will not create one, since a bare directory is
not a vault. Project subfolders are created on first write.
## Development
```bash
npm install
npm run build
npm test
```
`npm test` runs unit tests for path handling and project resolution, plus an end-to-end suite
that speaks real JSON-RPC to the built server over stdio against a temporary vault.
## Registration
Claude Code (user scope, so it applies to every project):
```bash
claude mcp add --scope user obsidian -- node /path/to/obsidian-mcp/dist/index.js
```
Claude Desktop — in `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"obsidian": {
"command": "node",
"args": ["/path/to/obsidian-mcp/dist/index.js"]
}
}
}
```
Rebuild after changing `src/`; both clients run `dist/`.
## macOS folder protection
A vault under `~/Documents` (also `~/Desktop`, `~/Downloads`) sits in a TCC-protected
location. A sandboxed host can end up able to write into folders it created while still
being denied a listing of the vault root — which breaks `scope: "vault"` for
`list_notes` and `search_notes` while everything project-scoped works fine.
The server raises `Permission denied reading …` rather than reporting an empty vault, so
this is visible instead of silent. Two ways out:
- Grant Full Disk Access to whatever runs the server (System Settings → Privacy &
Security → Full Disk Access).
- Or move the vault somewhere unprotected and set `OBSIDIAN_VAULT_PATH`, e.g.
`~/Vaults/main`.
## Safety
Note names are resolved and checked against the project folder, so `../../etc/passwd` and
absolute paths are rejected rather than written. Writes never leave `<vault>/Projects/<slug>/`.
TDQS
Scored across 6 tools
Each tool serves a clearly distinct purpose: resolving project routing, writing, reading, appending, listing, and searching notes. Even write_note and append_note are well differentiated by their overwrite and append semantics.
All tool names follow a consistent verb_noun snake_case pattern: resolve_project, write_note, read_note, append_note, list_notes, search_notes. This makes the API predictable and easy to navigate.
Six tools is a well-scoped set for an Obsidian note management server. Each tool covers a distinct operation without redundancy or bloat.
The core note lifecycle is well covered: create/write, read, append, list, and search. Missing delete, move, or rename operations are noticeable gaps, but agents can still accomplish most note workflows.