Skip to main content
Glama
apaulineoliveira

obsidian-mcp

Obsidian MCP Server

Article on Medium: https://paulineoliveira.medium.com/por-que-eu-fiz-o-claude-e-o-cursor-lerem-meus-to-dos-no-obsidian-4f0ab55eed84?postPublishedType=initial

An MCP server that connects your Obsidian vault to Claude Desktop and Cursor, so the AI can search your notes, read and update their metadata, and manage your to-dos without you copying and pasting anything.

🇧🇷 Versão em português

What it can do

Tool

Description

search_notes

Searches notes by text or regex, by tags and by frontmatter fields (all combinable), returning matching lines with their line numbers

list_tags

Lists every tag in the vault (inline and frontmatter) with how many notes use it

get_frontmatter

Returns a note's YAML frontmatter as JSON

update_frontmatter

Creates, changes or removes frontmatter keys, keeping comments, key order and the note body intact

get_todos

Lists to-dos (- [ ] / - [x]), filterable by folder, tag, priority, completed and language

update_todo

Marks a to-do as done/undone (by note path and line number)

get_note_content

Returns the full content of a note

create_note

Creates a new note (and any missing folders), never overwriting an existing note

list_projects

Lists projects found in notes' frontmatter

get_supported_languages

Lists languages accepted for priority keywords

Example prompts:

  • "Find notes mentioning OAuth in Projects" · "Search for TODO\(\w+\) as a regex"

  • "Which notes are tagged #project and have status: draft?"

  • "Set status: done in the frontmatter of Projects/oloroke.md"

  • "Show my high-priority #backend tasks" · "Mark line 5 of Projects/x.md as done"

  • "Save this summary as a note in Study/mcp.md"

Organizing your notes (all optional, can be combined)

  • Inline tags: - [ ] Fix login #urgent #backend. Nested tags work like in Obsidian: filtering by project also matches #project/api. Tags inside code blocks, URLs (page#anchor) and links ([[Note#Heading]]) are ignored.

  • Priority emoji: 🔴 high · 🟡 medium · 🟢 low · ⚫ blocked

  • YAML frontmatter: projeto/project, prioridade/priority, tags (list or "a, b") and any custom field you want to search on

---
project: oloroke
priority: high
status: draft
tags: [backend]
---
- [ ] 🔴 Implement OAuth #urgent

Priority keywords work in pt, en, es, fr, de, it. To add another language, add its keywords to PRIORITY_KEYWORDS in src/core/priorities.py; src/examples/add_custom_language.py shows ready-made keywords for ja, zh, ru, el and ko.

Safety

The server only touches files inside OBSIDIAN_VAULT_PATH:

  • Absolute paths, .. that leave the vault, and symlinks pointing outside it are rejected.

  • .obsidian/, .trash/ and .git/ are never read or written; only .md notes can be opened or edited.

  • Edits are atomic (temp file + rename), keep the file's line endings, and are refused if the existing frontmatter is invalid YAML.

  • A new note is only created when nothing exists at that path yet: create_note never overwrites.

Related MCP server: obsidian-mcp

Requirements

  • Python 3.11+

  • Claude Desktop or Cursor

  • An Obsidian vault

Setup

1. Install

git clone git@github.com:apaulineoliveira/obsidian-mcp.git
cd obsidian-mcp
python3.11 -m venv venv
source venv/bin/activate          # Windows: venv\Scripts\activate
pip install -e .

Get the absolute paths you will need in the next step:

echo "$PWD/venv/bin/python3"      # command
echo "$PWD/src/obsidian_mcp.py"   # script

2a. Claude Desktop

Open the config file (or go to Settings → Developer → Edit Config):

OS

Path

macOS

~/Library/Application Support/Claude/claude_desktop_config.json

Windows

%APPDATA%\Claude\claude_desktop_config.json

Add the server under mcpServers (keep any servers already there):

{
  "mcpServers": {
    "obsidian-mcp": {
      "command": "/abs/path/to/obsidian-mcp/venv/bin/python3",
      "args": ["/abs/path/to/obsidian-mcp/src/obsidian_mcp.py"],
      "env": { "OBSIDIAN_VAULT_PATH": "/abs/path/to/your/vault" }
    }
  }
}

On Windows, use venv\\Scripts\\python.exe and escape backslashes (C:\\Users\\me\\vault).

Fully quit Claude Desktop (Cmd+Q / exit from the tray) and reopen it. The tools appear under the 🔨 / connectors menu in the chat box.

2b. Cursor

Use the same mcpServers block in one of these files:

  • ~/.cursor/mcp.json — available in every project

  • .cursor/mcp.json in a project — only for that project

Then open Cursor Settings → MCP: obsidian-mcp should show a green dot and its list of tools. Tools are used by the Agent mode in chat.

Configuring the vault path

OBSIDIAN_VAULT_PATH must be the absolute path of the vault folder (the one that contains .obsidian/). It is read, in order of priority, from:

  1. The env block of the client config (recommended)

  2. A .env file at the repository root (cp .env.example .env)

  3. Default: ~/Obsidian

Troubleshooting

  • Server doesn't show up: validate the config JSON, confirm both paths exist, and fully restart the client.

  • ModuleNotFoundError: mcp: command must point to the venv's Python, not the system one.

  • Vault não encontrado / Vault not found: OBSIDIAN_VAULT_PATH is wrong or not absolute.

  • Caminho fora do vault / path outside vault: use paths relative to the vault, e.g. Projects/x.md.

  • Logs: Claude Desktop writes them to ~/Library/Logs/Claude/mcp-server-obsidian-mcp.log (macOS) or %APPDATA%\Claude\logs (Windows); Cursor shows them in Output → MCP Logs.

  • Inspect the server by hand: npx @modelcontextprotocol/inspector venv/bin/python3 src/obsidian_mcp.py

Architecture

The code follows a layered (clean / hexagonal) architecture. Dependencies only point inward: adapters → application → core.

src/
├── obsidian_mcp.py      Composition root: wires adapters and services, starts the server
├── core/                Domain rules. Standard library only; no MCP, disk or YAML
│   ├── paths.py         Vault path rules (traversal, internal folders, .md only)
│   ├── frontmatter.py   Frontmatter block split/assemble, via the FrontmatterCodec port
│   ├── tags.py          Obsidian tag rules (nested, case-insensitive, code blocks)
│   ├── search.py        Query, matching, snippets and ranking
│   ├── todos.py         Checkbox parsing, filters and toggling
│   ├── priorities.py    Priority keywords per language and emoji
│   ├── ports.py         NoteRepository and FrontmatterCodec interfaces
│   └── errors.py        Domain errors
├── application/         Use cases that orchestrate the core through the ports
│   ├── vault_notes.py   Reads every note once, already split into metadata and body
│   ├── notes.py         Content, creation, frontmatter, tags and projects
│   ├── todos.py         List and complete to-dos
│   ├── search.py        Note search
│   └── languages.py     Supported languages
└── adapters/            The outside world
    ├── filesystem.py    NoteRepository on disk (symlinks, atomic writes)
    ├── yaml_codec.py    FrontmatterCodec with ruamel.yaml (round-trip)
    └── mcp_server.py    MCP tools: arguments → use cases → JSON

Where to put a change:

  • New rule about notes (e.g. parsing wikilinks): a function in core/, tested with plain strings.

  • New capability: a method in an application/ service, tested with an in-memory repository.

  • New tool: a method in VaultTools plus its name in TOOL_NAMES (adapters/mcp_server.py).

  • New storage (e.g. Obsidian REST API): a class implementing NoteRepository, wired in obsidian_mcp.py.

Development

pip install -e ".[dev]"
pytest

Tests mirror the layers: tests/core (pure functions), tests/application (in-memory repository) and tests/adapters (real disk, YAML and MCP).

Found a bug?

Open an issue with: what you did, what you expected, what happened, your OS/Python version, and any error output.

Contributing

  1. Fork the repo and create a branch (git checkout -b feature/my-change)

  2. Make your change, add tests and run pytest

  3. Commit using Conventional Commits (e.g. feat(search): ...)

  4. Open a pull request describing what and why

License

MIT — created by Pauline Oliveira.

Related MCP Connectors

Related MCP Servers