Skip to main content
Glama
digster

obsidian-cli-mcp

by digster
README.md
# 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

A3.6/5.0

Scored across 21 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count4/5

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.

Completeness4/5

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.

Maintenance

ActivityInactive
ResponsivenessNo issues