obsidian-cli-mcp
# obsidian-cli-mcp
An [MCP](https://modelcontextprotocol.io) server that wraps the **official Obsidian CLI**
(`obsidian`, bundled with the Obsidian desktop app) instead of the Local REST API plugin.
Each server instance is pinned to a **single vault**, so you run one entry per vault.
## Why the CLI instead of the REST API?
The REST-API MCP (`mcp-obsidian`) needs the Local REST API community plugin, an API key,
and a dedicated port per vault. This server drives the Obsidian app through its built-in
CLI, which needs **no plugin and no API key**, and exposes a much richer surface:
tasks, frontmatter properties, backlinks, search-with-context, vault metadata, and more.
> **Requirement:** the Obsidian desktop app must be running with the target vault open.
> The CLI talks to the live app, not the files on disk.
## Install
The server is a [`uv`](https://docs.astral.sh/uv/) project. No global install is needed —
MCP clients launch it on demand with `uv run`.
```bash
git clone <this repo> && cd obsidian-cli-mcp
uv sync # install dependencies
uv run pytest # run the test suite (no live Obsidian needed)
```
## Configure (per vault)
Add one entry per vault to your MCP client config (e.g. Claude Desktop's
`claude_desktop_config.json`). The vault is selected with the `OBSIDIAN_VAULT`
environment variable — run `obsidian vaults` to see the exact names.
```jsonc
{
"mcpServers": {
"obsidian-cli-void": {
"command": "uv",
"args": ["run", "--directory", "/ABSOLUTE/PATH/TO/obsidian-cli-mcp", "obsidian-cli-mcp"],
"env": { "OBSIDIAN_VAULT": "void" }
},
"obsidian-cli-notebook": {
"command": "uv",
"args": ["run", "--directory", "/ABSOLUTE/PATH/TO/obsidian-cli-mcp", "obsidian-cli-mcp"],
"env": { "OBSIDIAN_VAULT": "notebook" }
}
}
}
```
### Environment variables
| Variable | Required | Default | Purpose |
| --- | --- | --- | --- |
| `OBSIDIAN_VAULT` | **yes** | — | Vault name this instance targets (injected as `vault=` on every call). |
| `OBSIDIAN_CLI_PATH` | no | `obsidian` | Path to the CLI binary if it isn't on `PATH`. |
| `OBSIDIAN_VERIFY_READS` | no | `true` | Run the vault guard before reads too (not just writes). |
| `OBSIDIAN_ALLOW_PERMANENT_DELETE` | no | `false` | Allow `delete_note(permanent=True)` to bypass trash. |
| `OBSIDIAN_TIMEOUT` | no | `30` | Per-command subprocess timeout (seconds). |
| `OBSIDIAN_GUARD_TTL` | no | `5` | Seconds to cache a successful vault-guard check. |
| `OBSIDIAN_LOG_LEVEL` | no | `INFO` | Log level (logs go to stderr). |
## Tools
**Read / navigate:** `read_note`, `search_vault`, `list_files`, `list_folders`,
`note_info`, `list_backlinks`, `list_tags`, `list_tasks`, `list_properties`,
`read_property`, `vault_info`, `list_vaults`
**Write / organise:** `create_note`, `add_to_note`, `set_property`,
`remove_property`, `move_note`, `rename_note`, `delete_note`, `update_task`
**Escape hatch:** `run_obsidian` — run any other CLI command (e.g. `bookmarks`,
`wordcount`, `history`). Disruptive commands (`restart`, `reload`, `eval`,
`devtools`, `plugins:restrict`, and all `dev:*`) are blocked.
Notes are addressed by **`file`** (resolve by name, like a wikilink) or **`path`**
(exact `folder/note.md`). Most read tools fall back to the active note when both
are omitted; write tools require an explicit target.
## Safety: the vault guard
The Obsidian CLI **silently falls back to the active vault** when `vault=<name>`
names a vault that isn't currently open. To prevent acting on the wrong vault,
this server verifies — via `vault info=name` — that the configured vault is the
one actually responding before every write (and before reads, by default). If it
isn't, the tool fails with a clear message instead of touching another vault.
This also means the CLI reports failures on **stdout with exit code 0**; the
server detects them by inspecting the output, so genuine errors surface as MCP
tool errors rather than being mistaken for success.
## License
MIT © digster
TDQS
Scored across 21 tools
Each tool targets a distinct action and resource. The list_* family (files, folders, tags, etc.) has clear boundaries, and CRUD operations are separate. No two tools could be easily confused.
All tool names follow a consistent verb_noun or list_noun pattern (e.g., create_note, list_tags). The few exceptions like note_info and vault_info are clearly compound nouns and do not break the pattern.
21 tools is slightly above the typical 3-15 range, but each tool addresses a specific need. The list_* tools could be simplified, but the count is still reasonable for a comprehensive Obsidian CLI interface.
The tool set covers most common operations: CRUD on notes, properties, tasks, search, and vault management. The run_obsidian fallback fills gaps. Missing a dedicated 'replace note content' tool is a minor gap that can be worked around.