cyanheads avatar

Obsidian Mcp Server

cyanheads/obsidian-mcp-server

The Obsidian MCP Server provides AI agents and LLMs with comprehensive access to Obsidian vaults through the Model Context Protocol, enabling read, write, search, and management operations on notes and files via the Obsidian Local REST API plugin. It exposes specialized tools including obsidian_read_note, obsidian_update_note, obsidian_search_replace, and obsidian_global_search, with capabilities such as flexible content formatting, regex-based search-and-replace, case-insensitive path fallback, and metadata retrieval. The server solves the problem of integrating AI assistants and development tools with Obsidian knowledge bases by providing a standardized, secure interface for programmatic vault interaction.

GitHub stars
705
tools
12
auth
Required
transport
STDIO, HTTP
env vars
17
last updated
Nov 11, 2026

Install

From registry metadata
$ npx add-mcp obsidian-mcp-server --name obsidian --env 'OBSIDIAN_API_KEY=${OBSIDIAN_API_KEY}'

Run in your terminal. add-mcp asks which agents to add it to, then asks for each value it needs. Add -g to install it for every project.

Review the command, arguments and environment values before installing. MCP servers run with your local permissions.

Other ways

Claude Code

$ claude mcp add obsidian --env OBSIDIAN_API_KEY=YOUR_OBSIDIAN_API_KEY --env OBSIDIAN_BASE_URL=http://127.0.0.1:27123 --env OBSIDIAN_VERIFY_SSL=false --env OBSIDIAN_REQUEST_TIMEOUT_MS=30000 --env OBSIDIAN_ENABLE_COMMANDS=false --env OBSIDIAN_READ_PATHS=YOUR_OBSIDIAN_READ_PATHS --env OBSIDIAN_WRITE_PATHS=YOUR_OBSIDIAN_WRITE_PATHS --env OBSIDIAN_DENY_PATHS=YOUR_OBSIDIAN_DENY_PATHS --env OBSIDIAN_READ_ONLY=false --env OBSIDIAN_DELETE_ELICITATION=false --env OBSIDIAN_OMNISEARCH_URL=YOUR_OBSIDIAN_OMNISEARCH_URL --env MCP_LOG_LEVEL=info -- npx -y obsidian-mcp-server

Run in your terminal. Replace YOUR_* placeholders with real values; add --scope user to install for every project.

Tools

Verified live · 12 tools

Verified live against the running server on Jun 10, 2026.

obsidian_get_noteRead a note from the vault — by path, the active file, or a periodic note. Choose a `format` projection: raw body, full object, structural document map, or a single section.4 params

Read a note from the vault — by path, the active file, or a periodic note. Choose a `format` projection: raw body, full object, structural document map, or a single section.

Parameters* required
format*string
Which projection to return. `content` — raw markdown body. `full` — content plus parsed frontmatter, tags, and file metadata. `document-map` — catalog of headings, block IDs, and frontmatter field...one of content · full · document-map · section
includeLinksboolean
When true with `format: "full"`, parses outgoing wiki and markdown link references from the note body. Skipped for other formats.default: false
sectionobject
Required when `format` is `"section"`. Identifies the heading/block/frontmatter to extract.
target*value
Where the note lives.
obsidian_list_notesList notes and subdirectories at a vault path. Defaults to the vault root when `path` is omitted. Tune recursion with `depth`, or filter the walk with `extension` / `nameRegex`. Capped at 1000 entries per call — when reached, walking stops and `excluded` is set; narrow `path`...4 params

List notes and subdirectories at a vault path. Defaults to the vault root when `path` is omitted. Tune recursion with `depth`, or filter the walk with `extension` / `nameRegex`. Capped at 1000 entries per call — when reached, walking stops and `excluded` is set; narrow `path`...

Parameters* required
depthinteger
How many directory levels to walk. `1` = target directory only (no recursion); `2` = target plus its immediate children — a structural overview; bump higher to drill in. Prefer narrowing `path` to...default: 2
extensionstring
Only include files matching this extension, with or without leading dot. Applies to files only — directories are returned regardless.
nameRegexstring
Optional ECMAScript regex (no flags) applied to entry names. Matches both files and directories; directories that fail the regex are skipped without recursing into them.
pathstring
Vault-relative directory path. Omit for the vault root.
obsidian_list_tagsList every tag found across the vault, with usage counts. Includes hierarchical parents — `work/tasks` contributes to both `work` and `work/tasks`. Filter to a subset with the optional `nameRegex`. To find notes by tag, use `obsidian_search_notes` in jsonlogic mode (e.g. `{"in...1 params

List every tag found across the vault, with usage counts. Includes hierarchical parents — `work/tasks` contributes to both `work` and `work/tasks`. Filter to a subset with the optional `nameRegex`. To find notes by tag, use `obsidian_search_notes` in jsonlogic mode (e.g. `{"in...

Parameters* required
nameRegexstring
Optional ECMAScript regex (no flags, ≤256 chars, no nested quantifiers like `(a+)+`) matched against the bare tag name (no leading `#`). Hierarchical tags like `work/tasks` are matched as the full...
obsidian_open_in_uiOpen a file in the Obsidian app UI. By default fails when the path does not exist; the `failIfMissing` flag controls the open-or-create behavior.3 params

Open a file in the Obsidian app UI. By default fails when the path does not exist; the `failIfMissing` flag controls the open-or-create behavior.

Parameters* required
failIfMissingboolean
When true (default), fails if the file does not exist. When false, allows Obsidian to create the file on open.default: true
newLeafboolean
Open in a new leaf (split pane) instead of the active one.default: false
path*string
Vault-relative path of the file to open.
obsidian_search_notesSearch the vault by text substring or JSONLogic predicate. Pick the mode that matches the query shape. Results paginate via opaque cursors: omit `cursor` for the first page, then pass `nextCursor` from the prior response. Text-mode hits additionally clip per file at `maxMatche...7 params

Search the vault by text substring or JSONLogic predicate. Pick the mode that matches the query shape. Results paginate via opaque cursors: omit `cursor` for the first page, then pass `nextCursor` from the prior response. Text-mode hits additionally clip per file at `maxMatche...

Parameters* required
contextLengthinteger
Characters of context on each side of the match (text mode only).default: 100
cursorstring
Opaque cursor from a prior response. Omit for the first page. Page size is server-determined; do not assume a fixed value.
logicobject
JSONLogic tree. Required for `jsonlogic` mode; ignored in `text` and `omnisearch` modes (use `query` instead — passing a string here will fail Zod validation since this field must be an object).
maxMatchesPerHitinteger
Cap on match contexts returned per file in text mode. When clipped, the hit carries `truncated: true` and `totalMatches`.default: 10
mode*string
Which search algorithm to run. `text` matches a substring case-insensitively across filenames and note bodies, returning surrounding context windows. `jsonlogic` evaluates a JSONLogic tree against...one of text · jsonlogic
pathPrefixstring
Filter returned filenames by prefix (text mode only, applied client-side).
querystring
The query string. Required for `text` and `omnisearch` modes; ignored in `jsonlogic` mode (use `logic` instead — passing a JSONLogic tree here will fail Zod validation since this field must be a st...
obsidian_write_noteCreate or overwrite a note. With `section`, replaces just that heading/block/frontmatter section in place; nested headings need `Parent::Child` syntax — use `obsidian_get_note` with `format: "document-map"` to discover available targets. Whole-file writes fail with `file_exist...5 params

Create or overwrite a note. With `section`, replaces just that heading/block/frontmatter section in place; nested headings need `Parent::Child` syntax — use `obsidian_get_note` with `format: "document-map"` to discover available targets. Whole-file writes fail with `file_exist...

Parameters* required
content*string
Body to write. For heading sections, the new section body — do not repeat the heading line (it stays in place). Markdown unless `contentType` is `json`.
contentTypestring
Content body format. Use "json" for typed frontmatter values or block-targeted table rows. JSON values must be valid JSON literals — strings need quoting (`"\"draft\""`, not `"draft"`), and numbers...one of markdown · jsondefault: markdown
overwriteboolean
Whole-file mode only (ignored when `section` is set). When `false` (default), the call fails with `file_exists` if the target note already exists — read it first and use `obsidian_patch_note` / `ob...default: false
sectionobject
Optional sub-document target. When set, only this section is replaced; rest of the note is untouched.
target*value
Where the note lives.
obsidian_append_to_noteAppend content to a note. **Without `section`: appends to the end of the file, or creates the file if it does not exist (your content becomes the full file).** With `section`: appends to the end of that heading/block/frontmatter; nested headings need `Parent::Child` syntax — u...5 params

Append content to a note. **Without `section`: appends to the end of the file, or creates the file if it does not exist (your content becomes the full file).** With `section`: appends to the end of that heading/block/frontmatter; nested headings need `Parent::Child` syntax — u...

Parameters* required
content*string
Body to append. Markdown unless `contentType` is `json`.
contentTypestring
Content body format. Use "json" for typed frontmatter values or block-targeted table rows. JSON values must be valid JSON literals — strings need quoting (`"\"draft\""`, not `"draft"`), and numbers...one of markdown · jsondefault: markdown
createTargetIfMissingboolean
When `section` is provided, create the section if it does not already exist (otherwise the call fails when the section is missing).default: false
sectionobject
Optional sub-document target. When set, content is appended to that section instead of the file.
target*value
Where the note lives.
obsidian_patch_noteEdit a heading, block reference, or frontmatter field in place — append to, prepend to, or replace the target's body. Use `obsidian_get_note` with `format: "document-map"` to discover available targets first; nested headings need `Parent::Child` syntax.6 params

Edit a heading, block reference, or frontmatter field in place — append to, prepend to, or replace the target's body. Use `obsidian_get_note` with `format: "document-map"` to discover available targets first; nested headings need `Parent::Child` syntax.

Parameters* required
content*string
Body to insert/replace. Markdown unless `contentType` is `json`.
contentTypestring
Content body format. Use "json" for typed frontmatter values or block-targeted table rows. JSON values must be valid JSON literals — strings need quoting (`"\"draft\""`, not `"draft"`), and numbers...one of markdown · jsondefault: markdown
operation*string
How to apply `content` relative to the targeted section. `append` — at the end of the target's body (for headings, before the next sibling/parent heading; for frontmatter array fields, as a new arr...one of append · prepend · replace
patchOptionsobject
Optional flags: createTargetIfMissing, applyIfContentPreexists, trimTargetWhitespace.
section*object
Which heading/block/frontmatter field to edit.
target*value
Where the note lives.
obsidian_replace_in_noteSearch and replace inside a single note, literally or by regex. Replacements run in array order, each over the previous one's output. Use for edits that don't fit `obsidian_patch_note`'s structural targets — e.g., body-wide find-and-replace.2 params

Search and replace inside a single note, literally or by regex. Replacements run in array order, each over the previous one's output. Use for edits that don't fit `obsidian_patch_note`'s structural targets — e.g., body-wide find-and-replace.

Parameters* required
replacements*array
Replacements to apply in array order over the evolving content.
target*value
Where the note lives.
obsidian_manage_frontmatterGet, set, or delete a single frontmatter key on a note, atomically. `set` requires a JSON-typed `value` (string, number, boolean, array, or object).4 params

Get, set, or delete a single frontmatter key on a note, atomically. `set` requires a JSON-typed `value` (string, number, boolean, array, or object).

Parameters* required
key*string
Frontmatter field name.
operation*string
Operation to perform on `key`. `get` — read the current value. `set` — write `value`, creating the key if absent. `delete` — remove the key from frontmatter.one of get · set · delete
target*value
Where the note lives.
valuevalue
Required when `operation` is `"set"`. JSON-typed value to write — strings, numbers, booleans, arrays, and objects all accepted.
obsidian_manage_tagsAdd, remove, or list a note's tags. Defaults to the frontmatter `tags:` array — set `location` to `inline` or `both` to mutate the note body. `add` ensures the tag is present in the requested location(s); `remove` strips it; `both` reconciles across both representations. Inlin...4 params

Add, remove, or list a note's tags. Defaults to the frontmatter `tags:` array — set `location` to `inline` or `both` to mutate the note body. `add` ensures the tag is present in the requested location(s); `remove` strips it; `both` reconciles across both representations. Inlin...

Parameters* required
locationstring
Where to apply the change. Defaults to `frontmatter` (the canonical Obsidian tag location, leaves the body untouched). `inline` mutates the note body — `add` appends `#tag` at end-of-file. `both` i...one of frontmatter · inline · bothdefault: frontmatter
operation*string
`add` and `remove` mutate the note; `list` reads the current tag set.one of add · remove · list
tagsarray
Tags to add or remove. Omit the leading `#`. Required for add/remove.
target*value
Where the note lives.
obsidian_delete_notePermanently delete a note from the vault. Confirms with the user before deleting when the client supports interactive confirmation. Recovery requires the local trash in Obsidian — there is no API-level undo.1 params

Permanently delete a note from the vault. Confirms with the user before deleting when the client supports interactive confirmation. Recovery requires the local trash in Obsidian — there is no API-level undo.

Parameters* required
target*value
Which note to delete.

Sponsors

Configuration

OBSIDIAN_API_KEY*

Bearer token for the Obsidian Local REST API plugin (Settings → Community Plugins → Local REST API).

OBSIDIAN_BASE_URLdefault: http://127.0.0.1:27123

Base URL of the Obsidian Local REST API. Default: http://127.0.0.1:27123 (enable "Non-encrypted (HTTP) Server" in plugin settings). Use https://127.0.0.1:27124 for the always-on HTTPS port (self-signed cert; pair with OBSIDIAN_VERIFY_SSL=false).

OBSIDIAN_VERIFY_SSLdefault: false

Whether to verify the TLS certificate on the Obsidian endpoint. Default false because the plugin uses a self-signed cert.

OBSIDIAN_REQUEST_TIMEOUT_MSdefault: 30000

Milliseconds one request attempt (headers and body) may take before it fails with obsidian_timeout. GET, PUT, and DELETE retry a timed-out attempt; all the requests of one tool call share a 45 s budget, or this value when it is longer.

OBSIDIAN_ENABLE_COMMANDSdefault: false

Opt-in flag for the command-palette pair (obsidian_list_commands + obsidian_execute_command). Off by default — Obsidian commands are opaque and can be destructive.

OBSIDIAN_READ_PATHS

Optional comma-separated vault-relative folder allowlist for reads. Prefix-based with implicit recursion; case-insensitive; backslashes read as slashes, repeated and trailing slashes and '.' segments dropped, and names normalized to Unicode NFC; an entry naming the vault root ('.

OBSIDIAN_WRITE_PATHS

Optional comma-separated vault-relative folder allowlist for writes. Same syntax as OBSIDIAN_READ_PATHS. Unset = full vault, or the read scope when reads are restricted; paths in OBSIDIAN_DENY_PATHS stay denied. Example: 'projects/,scratch/'.

OBSIDIAN_DENY_PATHS

Optional comma-separated vault-relative paths withheld from reads and writes. Same syntax as OBSIDIAN_READ_PATHS. Wins over both allowlists; denied paths are left out of listings, search results, and tag counts. Unset = nothing denied. Example: 'private/,journal/therapy/'.

OBSIDIAN_READ_ONLYdefault: false

Global read-only kill switch. When true, every write is denied regardless of OBSIDIAN_WRITE_PATHS, and the command-palette pair is suppressed (commands can mutate). Useful for shared or public-facing deployments.

OBSIDIAN_DELETE_ELICITATIONdefault: false

Opt-in delete confirmation. When true, obsidian_delete_note asks the user to confirm each delete through an elicitation round (the client must support elicitation), and HTTP startup requires a stateful session unless OBSIDIAN_READ_ONLY=true disables the tool. Off by default — the

OBSIDIAN_OMNISEARCH_URL

Override URL for the Omnisearch plugin HTTP server. Unset derives from OBSIDIAN_BASE_URL host with port 51361. Required only if the Omnisearch plugin is not on the default port. Under OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS the URL is never called and the omnisearch search mod

MCP_LOG_LEVELdefault: info

Sets the minimum log level for output (e.g., 'debug', 'info', 'warn').

MCP_TRANSPORT_TYPEdefault: http

Selects the HTTP transport.

MCP_HTTP_HOSTdefault: 127.0.0.1

The hostname for the HTTP server.

MCP_HTTP_PORTdefault: 3010

The port to run the HTTP server on.

MCP_HTTP_ENDPOINT_PATHdefault: /mcp

The endpoint path for the MCP server.

MCP_AUTH_MODEdefault: none

Authentication mode to use: 'none', 'jwt', or 'oauth'.

Readme

obsidian-mcp-server

Read, write, search, and surgically edit Obsidian vault notes, tags, and frontmatter via MCP. STDIO or Streamable HTTP.

14 Tools • 3 Resources

Version License Docker MCP SDK npm TypeScript Bun

Details

Repository
github.com/cyanheads/obsidian-mcp-server
Categories
Documents & Knowledge, Search & Web Crawling
Package
obsidian-mcp-server
Transport
STDIO, HTTP
Auth
Required
Registry
MCP registry, active
Resources
2
Tools verified
Jun 10, 2026

More from cyanheads

Related Documents & Knowledge MCP servers

View all
1diaaaj avatarA Mem Mcpdiaaaj/a-mem-mcpSelf-evolving memory system for AI agents34stars
2es617 avatarObsidian Sync Mcpes617/obsidian-sync-mcpGive AI agents access to your Obsidian vault via local files or Self-hosted LiveSync.21stars
3jubakitiashvili avatarContext Memjubakitiashvili/context-memPersistent memory for AI agents — 98%+ retrieval recall, 99% token savings, 44 tools13stars
4domdomegg avatarGoogle Drivedomdomegg/google-drive-mcpAllow AI systems to list, search, upload, download, and manage files and folders in Google Drive.7stars
5ravikant1918 avatarSharePoint MCP Serverravikant1918/sharepoint-mcpMCP server for Microsoft SharePoint — manage folders, documents, and metadata.7stars
6aaronsb avatarConfluence Cloudaaronsb/confluence-cloudMCP server for Confluence Cloud — page editing, navigation, and content management0stars