# obsidian-mcp: a local MCP server for letting assistants edit your vault

> obsidian-mcp is a Model Context Protocol server that gives an AI assistant read and write access to explicitly configured Obsidian vaults, working directly on Markdown files so Obsidian need not be open. Its distinguishing feature is the safety layer: vault-relative paths, revision preconditions, transactional edits and a recoverable trash.

**StevenStavrakis/obsidian-mcp** — A simple MCP server for Obsidian

- Repository: https://github.com/StevenStavrakis/obsidian-mcp
- Stars: 742 · Forks: 95
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/stevenstavrakis-obsidian-mcp

## A local server over files, not over a running app

obsidian-mcp is a local Model Context Protocol server that lets MCP-compatible assistants safely read and modify explicitly configured Obsidian vaults. The word local is doing real work in that sentence, because the server never listens on a network interface and never sends telemetry.

The mechanism is deliberately unremarkable. It works directly with Markdown files, so Obsidian does not need to be open. That is a design decision with two consequences: an assistant can work in a vault on a machine where you have not started the app, and the vault's state is whatever is on disk rather than whatever the app has in memory. For an assistant that is editing notes, the second point is usually what you want, since the files are the durable state.

Version 2 supports both the 2026-07-28 MCP protocol and 2025-era clients by default, and requires Node.js 22 or newer. The legacy protocol and the v1 positional-path compatibility are deprecated, and rather than failing silently they print exact migration instructions to stderr, which is a thoughtful way to handle a breaking change in a tool that assistants call.

The project is MIT licensed, the default branch is main, the last push was on 2026-10-08, and the single release listed is 2.0.0 from 2026-08-14. The runtime dependencies are three: the Model Context Protocol server package, yaml and zod.

## Configuring the vault allowlist, and the protocol era switch

Vault access is explicitly allowlisted at process startup, and that is the design principle the whole server is built around. The quick start runs it with npx and no global install:

```bash
npx -y obsidian-mcp@2 serve --vault notes=/absolute/path/to/vault
```

Pinning the major version receives compatible 2.x updates without automatically crossing a future major version, which is the right way to pin something an assistant invokes for you.

An MCP client is configured to launch the same command over stdio:

```json
{
  "mcpServers": {
    "obsidian": {
      "command": "npx",
      "args": ["-y", "obsidian-mcp@2", "serve", "--vault", "notes=/absolute/path/to/vault"]
    }
  }
}
```

There are two rules about the vault itself. Each vault must already contain an .obsidian directory, which is how the server tells a real vault from a folder of Markdown files, and it must be configured using an absolute path. The id is the part the assistant sees, and vault ids use lowercase letters, digits, underscore and hyphen characters, must begin with a letter, and are the values assistants pass to tools. Up to ten vaults may be configured, and you repeat the --vault flag to expose more than one:

```bash
obsidian-mcp serve \
  --vault work=/Users/me/Documents/WorkVault \
  --vault personal=/Users/me/Documents/PersonalVault
```

One more allowance is worth knowing. Network, removable, hidden and synced locations are allowed because an explicit --vault is treated as authorization, and the same containment protections apply to every location. So the server does not second guess where you point it, it just refuses to go outside what you pointed it at.

## Twelve tools, and a strict schema for each of them

The tool list is the substance of the server, and it is a fairly complete vault API. There is obsidian_list_vaults, which lists the configured vault ids without exposing host paths, and obsidian_read_note, which reads a bounded page of a note and returns its SHA-256 etag.

The write side is transactional. obsidian_create_note creates a note atomically without overwriting, obsidian_edit_note appends, prepends or replaces exact note content, and obsidian_delete_note moves a note to an MCP trash or permanently deletes it with explicit confirmation. obsidian_move_note moves or renames a note and updates unambiguous backlinks transactionally, and obsidian_create_directory creates a directory inside a vault transactionally.

Tag handling is the most detailed corner. obsidian_add_tags and obsidian_remove_tags work atomically on one or more notes, with removal covering exact, nested or wildcard-selected tags. obsidian_rename_tag renames a tag across the vault atomically, and obsidian_manage_tags is a unified add and remove workflow using the same implementation underneath.

Search is obsidian_search_vault, which covers content, filenames or tags with bounded cursor pagination.

Two details apply across the board. All the schemas are strict JSON Schema 2020-12 contracts generated from Zod, so the tool definitions an assistant sees are the same contracts the server validates against. And mutating results include a transaction id, while tool failures return isError: true with an actionable error code rather than a vague message.

## Etags, transactions and how a failed edit rolls back

The concurrency model is the part that makes this more than a file-writing wrapper.

obsidian_read_note returns an etag, and you pass it as if_match to an edit, move or delete when avoiding lost updates matters. Batch tag operations accept an expected_etags map. If the note changed in the meantime, the operation returns REVISION_CONFLICT rather than overwriting what someone else wrote. That is the HTTP conditional request pattern applied to a file, and it is the difference between an assistant that clobbers a concurrent edit and one that notices.

The underlying mechanism is that file mutations are journaled, conflict-checked, atomically replaced, and rolled back as one transaction. So an edit that fails partway through does not leave a half-written note.

Deletion is recoverable by default. Trash is the default behaviour, and deleted note bytes and metadata are stored separately under .obsidian-mcp/trash, with the metadata never injected into the note itself, so a deleted note does not come back carrying a metadata header. Permanent deletion requires confirm_path to exactly match the canonical relative path, which is a deliberate speed bump on the one irreversible operation.

Transactions and recovery records live in .obsidian-mcp/transactions. Completed data is retained for 30 days by default and pruned oldest first above 1 GiB, and both numbers are configurable:

```bash
obsidian-mcp serve --vault work=/path \
  --recovery-days 14 \
  --recovery-max-bytes 536870912
```

And you can inspect or restore a completed transaction while the server is stopped:

```bash
obsidian-mcp recovery list --vault work=/path
obsidian-mcp recovery restore --vault work=/path --id <transaction-id>
```

Recovery refuses to overwrite content that has changed since the selected transaction, and the records for a permanent deletion are purged after the commit and cannot be restored.

## Path handling, symlinks and the reserved directories

The path and filesystem safety section is the longest in the README, and each line closes off a specific way an assistant could reach outside the vault.

The server canonicalizes configured vault roots and rejects duplicate or nested roots. Tool paths are rejected if they are absolute, UNC, Windows-drive, NUL, backslash, empty or contain dot segments. The directories .obsidian, .obsidian-mcp, .git, .backup and .trash are reserved from tool access, so an assistant cannot go poking at the vault's own configuration or at another tool's state directory.

Existing targets and the nearest existing ancestor for new targets are both checked, which closes the gap where a path does not exist yet and so cannot be resolved. Symlinks, junctions and reparse-point paths are rejected and skipped during scans, and there is no shell execution for filesystem validation at all. UTF-8 is decoded strictly, and invalid bytes are not silently replaced.

The link handling is Obsidian-aware rather than generic. Moves recognise Wikilinks, embeds, Markdown links, aliases, URL-encoded destinations, headings and block anchors. A link is rewritten only when it resolves unambiguously to the source note, and ambiguous links are reported and left unchanged, which is the right call since guessing would corrupt notes.

Two operational details finish the picture. The process needs read and write access to each configured vault, and there is a doctor command, obsidian-mcp doctor --vault id=/path, which validates startup readiness and the recovery state.

## Where obsidian-mcp is the wrong choice

The first wrong case is a vault you cannot lose. The README itself opens with an important note saying that MCP clients can invoke destructive tools, and advises backing up important vaults, reviewing client permission prompts and using revision preconditions for concurrently edited notes. If your vault is a decade of notes with no backup, this server is a sharp tool pointed at it, and the safety features reduce the risk rather than removing it.

The second is a workflow that needs Obsidian's own plugins. Because the server works on files directly, anything Obsidian knows and the server does not is invisible to it. Plugin-maintained metadata, a database view, a canvas file, a plugin's own cache, a note's position in a graph, and a workspace layout are all things that live outside the Markdown. If your vault's value is in what Obsidian has computed rather than in what you have written, an assistant reading the files is reading part of the picture.

The third is a shared or multi-user vault. The concurrency model is optimistic, with etags and conflict detection, which handles two people editing at once reasonably well. It is not a real-time collaborative editor, and the recovery transaction store is local to the machine running the server.

The fourth is a case where the assistant should not have write access. The server gives one binary decision, whether the vault is configured, and then every tool is available. There is no read-only mode in the design principles, so if you want an assistant that can search and summarise but not edit, you would configure a separate read-only mechanism.

The alternative worth weighing is the Obsidian Local REST API plugin, which exposes the vault through Obsidian's own API and therefore sees everything Obsidian sees, including plugin data. The trade is direct: that route has fuller access to the vault's real state, and this route has stronger containment, transactions and recovery.

## Conclusion

Adopt obsidian-mcp if you want an AI assistant to work inside a specific Obsidian vault with real safety guarantees, since the allowlist, the etag preconditions, the transactional writes and the recoverable trash are the parts other vault integrations tend to skip. Keep away if you want the assistant to read notes through Obsidian's own plugin API with the app running, because this server works on the files directly and does not need Obsidian open. Before you run it, back up the vault as the README insists, review the permission prompts your client shows, and check the version you install, since 2.0.0 was published on 2026-08-14 and the last push was on 2026-10-08.

## FAQ

### What is obsidian-mcp and how do I run it?

It is a local Model Context Protocol server that lets MCP-compatible assistants read and modify explicitly configured Obsidian vaults. You run it with npx -y obsidian-mcp@2 serve --vault notes=/absolute/path/to/vault, or install it globally with npm install -g obsidian-mcp@2, and you point your MCP client at the same command over stdio.

### Does obsidian-mcp need Obsidian to be running?

No. It works directly with the Markdown files, so Obsidian does not need to be open. Each vault must already contain an .obsidian directory and must be configured with an absolute path, and vault ids use lowercase letters, digits, underscore and hyphen characters and must begin with a letter.

### How does obsidian-mcp avoid overwriting a note someone else changed?

obsidian_read_note returns a SHA-256 etag, which you pass as if_match to an edit, move or delete. Batch tag operations take an expected_etags map, and a note that has changed since returns REVISION_CONFLICT instead of being overwritten. File mutations are journaled, conflict-checked, atomically replaced and rolled back as one transaction.

### Can I recover a note that obsidian-mcp deleted?

Yes, by default. Trash is the default behaviour, with deleted note bytes and metadata stored separately under .obsidian-mcp/trash, and completed transactions are retained for 30 days. You can list and restore a transaction with the recovery subcommand while the server is stopped, and recovery refuses to overwrite content changed since the selected transaction.

## Sources

- [Issues](https://github.com/StevenStavrakis/obsidian-mcp/issues)
- [License: MIT](https://github.com/StevenStavrakis/obsidian-mcp/blob/main/LICENSE)
- [README](https://github.com/StevenStavrakis/obsidian-mcp/blob/main/README.md)
- [Releases](https://github.com/StevenStavrakis/obsidian-mcp/releases)
- [StevenStavrakis/obsidian-mcp on GitHub](https://github.com/StevenStavrakis/obsidian-mcp)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/stevenstavrakis-obsidian-mcp
