Search...Search plugins and themes...
⌘K
Sign in
  • Get started
  • Download
  • Pricing
  • Enterprise
  • Account
  • Obsidian
  • Overview
  • Sync
  • Publish
  • Canvas
  • Mobile
  • Web Clipper
  • CLI
  • Learn
  • Help
  • Developers
  • Changelog
  • About
  • Roadmap
  • Blog
  • Resources
  • System status
  • License overview
  • Terms of service
  • Privacy policy
  • Security
  • Community
  • Plugins
  • Themes
  • Discord
  • Forum / 中文论坛
  • Merch store
  • Brand guidelines
Follow us
DiscordTwitterBlueskyThreadsMastodonYouTubeGitHub
© 2026 Obsidian

Local REST API with MCP

Adam CoddingtonAdam Coddington656k downloads

Unlock your automation needs by interacting with your notes over a secure REST API.

Add to Obsidian
  • Overview
  • Scorecard
  • Updates72

Give your scripts, browser extensions, and AI agents a direct line into your Obsidian vault via a secure, authenticated REST API.

  • Interactive API docs: https://coddingtonbear.github.io/obsidian-local-rest-api/
  • Obsidian Community page: https://community.obsidian.md/plugins/obsidian-local-rest-api/
  • What you can do
  • Quick start
    • REST API
    • MCP clients
      • Claude Code
      • Claude Desktop
      • Cursor
      • Other clients
  • API overview
  • Patching notes
    • Raw-content mode
  • Targeting specific sections
  • Searching
  • MCP (Model Context Protocol)
    • Connecting a client
    • Available tools
    • Available resources
  • API Extensions
    • Typed extension API
    • Known extensions
  • Contributing
  • Credits

What you can do

Access your vault through the REST API or the built-in MCP server — both interfaces expose the same core capabilities, so scripts, browser extensions, and AI agents all speak the same language.

  • Read, create, update, or delete notes — full CRUD on any file in your vault, including binary files
  • Surgically patch specific sections — target a heading, block reference, or frontmatter key and append, prepend, replace, delete, or move just that section without touching the rest of the file
  • Search your vault — simple full-text search or structured JsonLogic queries against note metadata (frontmatter, tags, path, content)
  • Access the active file — read or write whatever note is currently open in Obsidian
  • List and execute commands — trigger any Obsidian command as if you'd used the command palette
  • Query tags — list all tags across your vault with usage counts
  • Open files in Obsidian — tell Obsidian to open a specific note in its UI
  • Extend the API — other plugins can register their own routes via the API extension interface

All requests are served over HTTPS with a self-signed certificate and gated behind API key authentication.

Quick start

After installing and enabling the plugin, open Settings → Local REST API to find your API key and certificate.

REST API

# Check the server is running (no auth required)
curl -k https://127.0.0.1:27124/

# List files at the root of your vault
curl -k -H "Authorization: Bearer <your-api-key>" \
  https://127.0.0.1:27124/vault/

# Read a note
curl -k -H "Authorization: Bearer <your-api-key>" \
  https://127.0.0.1:27124/vault/path/to/note.md

# Read a specific heading (URL-embedded target)
curl -k -H "Authorization: Bearer <your-api-key>" \
  https://127.0.0.1:27124/vault/path/to/note.md/heading/My%20Section

# Append a line to a specific heading (PATCH with a JSON instruction)
curl -k -X PATCH \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  --data '{"targetType":"heading","target":["My Section"],"operation":"append","content":"New line of content"}' \
  https://127.0.0.1:27124/vault/path/to/note.md

To avoid certificate warnings, you can download and trust the certificate from https://127.0.0.1:27124/obsidian-local-rest-api.crt, or point your HTTP client at it directly.

MCP clients

The MCP server runs at https://127.0.0.1:27124/mcp/ and requires that you provide your bearer token for authentication via an Authorization header (i.e. Authorization: Bearer <your-api-key>). Because the plugin uses a self-signed certificate, you may need to either trust the certificate in your OS/client, or use the plain HTTP endpoint at http://127.0.0.1:27123/mcp/ (enable it under Settings → Local REST API → Enable HTTP server).

Claude Code

Claude Code has native HTTP MCP support. The quickest way to add the server is via the CLI:

claude mcp add --transport http obsidian https://127.0.0.1:27124/mcp/ \
  --header "Authorization: Bearer <your-api-key>"

Or add it manually to .mcp.json in your project root (project-scoped) or configure it user-wide via claude mcp add --scope user:

{
  "mcpServers": {
    "obsidian": {
      "type": "http",
      "url": "https://127.0.0.1:27124/mcp/",
      "headers": {
        "Authorization": "Bearer <your-api-key>"
      }
    }
  }
}

Claude Desktop

Claude Desktop does not natively support remote HTTP MCP servers, but you can bridge it with mcp-remote (requires Node.js). Add the following to claude_desktop_config.json:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "obsidian": {
      "command": "npx",
      "args": [
        "mcp-remote@latest",
        "https://127.0.0.1:27124/mcp/",
        "--header",
        "Authorization: Bearer <your-api-key>"
      ]
    }
  }
}

Restart Claude Desktop after saving the file.

Cursor

Cursor supports the Streamable HTTP MCP transport. Add the following to ~/.cursor/mcp.json (global) or .cursor/mcp.json (project-specific):

{
  "mcpServers": {
    "obsidian": {
      "url": "https://127.0.0.1:27124/mcp/",
      "headers": {
        "Authorization": "Bearer <your-api-key>"
      }
    }
  }
}

Other clients

Any MCP client that supports the Streamable HTTP transport can connect to https://127.0.0.1:27124/mcp/ with an Authorization: Bearer <your-api-key> header. Consult your client's documentation for the exact configuration format.

API overview

Endpoint Methods Description
/vault/{path} GET PUT PATCH POST DELETE Read, write, or delete any file in your vault
/active/ GET PUT PATCH POST DELETE Operate on the currently open file
/search/simple/ POST Full-text search across all notes
/search/ POST Structured search via JsonLogic
/commands/ GET List available Obsidian commands
/commands/{commandId}/ POST Execute a command
/tags/ GET List all tags with usage counts
/open/{path} POST Open a file in the Obsidian UI
/ GET Server status and authentication check
/mcp/ GET POST MCP (Model Context Protocol) server — connect AI agents directly to your vault

For full request/response details, see the interactive docs.

Patching notes

The PATCH method is one of the most useful features of this API. It lets you make targeted edits without rewriting entire files.

Send a JSON instruction: an operation (replace, prepend, append, or delete) applied to a scope (content, marker, markerAndContent, or parent) of a target — a heading (addressed as an array of heading texts from the top level down), a block reference, or a frontmatter key. The payload rides in content (a string), value (JSON, for frontmatter values), or destination (a heading move):

# Replace the value of a frontmatter field
curl -k -X PATCH \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  --data '{"targetType":"frontmatter","target":"status","operation":"replace","value":"done"}' \
  https://127.0.0.1:27124/vault/path/to/note.md

Heading levels inside a content string are relative to the target (a leading # becomes a direct child). Advisory warnings (e.g. a heading rebased past level 6) come back as percent-encoded JSON in the Markdown-Patch-Warnings response header — decode with decodeURIComponent before parsing. Pass ifMatch (the version from a document map) for optimistic concurrency.

Note: Whitespace is library-owned — your content is reduced to trimmed, canonical form (leading and trailing blank lines are meaningless), and the API itself supplies the blank line wherever inserted content faces body text, so an append or prepend always lands as its own block and never merges into an existing paragraph. Heading lines, existing blank lines, and each document's spacing style are preserved as-is. See the interactive docs for worked examples.

To continue an existing block instead of starting a new one — say, extending a list — add within to a heading instruction: an index selecting one of the section's top-level body blocks (0-based in document order, negative counting from the end, so -1 is the last block). A within edit splices literally, so you own the joint:

# Add an item to the last list under "Log" (the leading \n continues the block)
curl -k -X PATCH \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: application/json" \
  --data '{"targetType":"heading","target":["Log"],"within":-1,"operation":"append","content":"\n- new item"}' \
  https://127.0.0.1:27124/vault/path/to/note.md

With markerAndContent scope, prepend/append instead insert a new block beside the indexed one. Indices are positional, so read the document map first and pair the edit with ifMatch.

Raw-content mode

If your client templates markdown into the request body (Shortcuts, Tasker, curl from a template), JSON-escaping that content into an instruction is fragile. Raw-content mode moves the instruction's fields out of the body — target in the URL (or in Target-Type/Target headers with an explicit Markdown-Patch-Version: 2), operation and options in headers — and the body is the raw payload, no JSON escaping required:

# Append a templated line under a heading — no JSON escaping anywhere
curl -k -X PATCH \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Operation: append" \
  -H "Content-Type: text/markdown" \
  --data "- $TEMPLATED_CONTENT" \
  https://127.0.0.1:27124/vault/notes/daily.md/heading/Log

A text/* body is the content carrier, an application/json body the value carrier, and no body at all carries nothing (a delete, or a move via a Destination header). Target-Scope, Within (the instruction's within index as a plain integer, e.g. -1), Create-Target-If-Missing, Reject-If-Content-Preexists, and If-Match headers round out the instruction. See the interactive docs for the header encodings and the full details.

Already using the older header-driven PATCH format? It spread the instruction across request headers instead of a JSON body, and is deprecated and will be removed in 6.0. It still works — send Markdown-Patch-Version: 1 to opt back into it (the same header also selects the legacy ::-joined document map on GET), and responses served by it carry a Deprecation: true; sunset-version="6.0" header. To upgrade, drop that header and move each header into the JSON body; the interactive docs have the field-by-field mapping table.

See the interactive docs for the full instruction schema and options.

Targeting specific sections

You can read or write a specific part of a note — a heading, block reference, or frontmatter field — without fetching or replacing the whole file. This works on GET, PUT, POST, and PATCH requests (for PATCH this is raw-content mode — add an Operation header).

Append /<target-type>/<target> after the filename. Each nested heading level is its own path segment, so a heading whose text contains :: needs no escaping:

# Read the content under a specific heading
curl -k -H "Authorization: Bearer <your-api-key>" \
  https://127.0.0.1:27124/vault/path/to/note.md/heading/My%20Section

# Read a nested heading (one path segment per level)
curl -k -H "Authorization: Bearer <your-api-key>" \
  https://127.0.0.1:27124/vault/path/to/note.md/heading/Work/Meetings

# Read a frontmatter field
curl -k -H "Authorization: Bearer <your-api-key>" \
  https://127.0.0.1:27124/vault/path/to/note.md/frontmatter/status

# Replace the content of a heading via PUT (heading levels are normalized for you)
curl -k -X PUT \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: text/markdown" \
  --data "Updated content" \
  https://127.0.0.1:27124/vault/path/to/note.md/heading/My%20Section

# Append to a heading via POST
curl -k -X POST \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Content-Type: text/markdown" \
  --data "Appended content" \
  https://127.0.0.1:27124/vault/path/to/note.md/heading/My%20Section

Supported target types: heading, block, frontmatter.

On a GET, a Target-Scope header selects which part of the target comes back, mirroring the PATCH scopes: content (the default), marker (the label — a heading's raw text, a block's bare id, a frontmatter key), or markerAndContent (the whole node, in exactly the shape a PATCH replace at that scope consumes — a heading subtree reads back with its own line as # Title, levels relative to its parent):

# Read a whole section — heading line included — ready to edit and write back
curl -k -H "Authorization: Bearer <your-api-key>" \
  -H "Target-Scope: markerAndContent" \
  https://127.0.0.1:27124/vault/path/to/note.md/heading/My%20Section

Deprecated: header-based targeting. Earlier releases targeted a section with Target-Type, Target, and Target-Delimiter headers (plus Target-Scope/Trim-Target-Whitespace). That form is deprecated and will be removed in 6.0; it is only processed when you also send Markdown-Patch-Version: 1 (responses then carry a Deprecation header). Without it, supplying those targeting headers is rejected with 400. Supplying both URL-path targeting and the header form on one request returns 422 Unprocessable Entity.

Searching

POST /search/simple/?query=your+terms runs Obsidian's built-in fuzzy search and returns matching filenames with scored context snippets.

POST /search/ accepts a JsonLogic expression (content type application/vnd.olrapi.jsonlogic+json) and evaluates it against each note's metadata (frontmatter, tags, path, content).

MCP (Model Context Protocol)

[!NOTE] Several third-party MCP servers for Obsidian exist, but they are no longer necessary — this plugin ships a built-in MCP server that runs inside Obsidian and has direct access to your vault's live metadata, active file, and command palette. If you are currently using a third-party server, switching to this one is likely to give you better results.

The plugin includes a built-in MCP server at /mcp/ so AI agents and MCP-compatible clients can interact with your vault without hand-crafting HTTP requests.

Transport: Streamable HTTP — API key authentication required.

Connecting a client

Connect your MCP client to https://127.0.0.1:27124/mcp/. Authentication uses a bearer token — find your API key under Settings → Local REST API, then pass it as:

Authorization: Bearer <your-api-key>

The exact config syntax varies by client; see the Quick start examples above or consult your client's documentation for Streamable HTTP remote MCP servers.

[!WARNING] To connect to the MCP server securely, your client must trust the plugin's self-signed certificate. You can download and trust it from https://127.0.0.1:27124/obsidian-local-rest-api.crt, or configure your client to skip TLS verification for 127.0.0.1.

If trusting a self-signed certificate is not possible in your environment, you can connect insecurely using http://127.0.0.1:27123/mcp/ instead of https://127.0.0.1:27124/mcp/ if you have enabled the HTTP endpoint under Settings → Local REST API → Enable HTTP server.

Available tools

Tool Description
vault_list List files and subdirectories inside a vault directory
vault_read Read a file's content, frontmatter, tags, and stat
vault_write Create or overwrite a vault file
vault_append Append content to the end of a vault file
vault_patch Patch a specific heading, block reference, or frontmatter field
vault_delete Delete a vault file (moves to trash by default)
vault_move Move (rename) a vault file to a new path
vault_copy Copy a vault file to a new path
vault_get_document_map List the headings, block references, and frontmatter fields in a file
active_file_get_path Return the vault path of the file currently open in Obsidian
search_query Search using a JsonLogic query against note metadata
search_simple Full-text search using Obsidian's built-in search
tag_list List all tags across the vault with usage counts
command_list List all registered Obsidian commands
command_execute Execute an Obsidian command by ID
open_file Open a file in the Obsidian UI

Available resources

URI Description
obsidian://local-rest-api/openapi.yaml Full OpenAPI specification for this REST API

API Extensions

Other plugins can register their own authenticated routes, public routes, and MCP tools against this plugin's server. See Adding your own API Routes via an Extension for a walkthrough.

Typed extension API

Install this package as a development dependency to get getAPI and the types for everything it returns:

npm install --save-dev obsidian-local-rest-api

This package declares obsidian, zod, and @types/express as peer dependencies, because its types refer to all three — addRoute returns express's IRoute, and addMcpTool takes zod schemas. npm installs peers for you; if you pin them yourself, keep them resolvable. Without them, TypeScript quietly widens those positions to any instead of reporting an error, so a project that suppresses the missing-types diagnostic gets no warning that it has lost type checking exactly where it matters most.

import { getAPI, type LocalRestApiPublicApi } from "obsidian-local-rest-api";

const api: LocalRestApiPublicApi | undefined = getAPI(this.app, this.manifest, 2);

The package entry point is a small standalone module — it resolves the running host plugin out of Obsidian's plugin registry rather than pulling the plugin bundle into your build. Passing an extension API version (2 above) makes getAPI throw ApiVersionUnsupportedError when the installed host is older than the surface you need; omit it to accept whatever is installed and feature-detect yourself. getAPI returns undefined when the plugin isn't installed or hasn't loaded yet.

publicApi.d.ts is generated from src/publicApi.ts, which the implementation is compile-time-checked against, so the published types cannot drift from what the plugin actually offers.

Known extensions

  • Periodic Notes: Adds support for periodic notes

Contributing

See CONTRIBUTING.md. If you want to add functionality without modifying core, consider building an API extension instead — extensions can be developed and released independently.

Credits

Inspired by Vinzent03's advanced-uri plugin, with the goal of expanding automation options beyond the constraints of custom URL schemes.

HealthExcellent
ReviewSatisfactory
About
Expose a secure local REST API over HTTPS for full CRUD on vault files (including binaries) and surgical edits of headings, block refs, and frontmatter. Search the vault, access active or periodic notes, run commands, open notes in the UI, and let other plugins register custom API routes while requiring API-key authentication.
IntegrationsFilesDevelopers
Details
Current version
5.1.0
Last updated
Last week
Created
5 years ago
Updates
72 releases
Downloads
656k
Compatible with
Obsidian 1.13.1+
Platforms
Desktop only
License
MIT
Report bugRequest featureReport plugin
Author
Adam CoddingtonAdam Coddingtoncoddingtonbear
adamcoddington.net/
GitHubcoddingtonbear
  1. Community
  2. Plugins
  3. Integrations
  4. Local REST API with MCP

Related plugins

Claudian

Embeds Claude Code/Codex and other local Agents as AI collaborators in your vault.

BRAT

Easily install a beta version of a plugin for testing.

Sync Engine

The next-generation syncing plugin: Fast · Free · Extend with Modules. Supports WebDAV and S3.

Claude Code IDE

Connect your vault to Claude Code and share editor context with the CLI.

Google Drive Sync

Syncs a vault into Google Drive for cross-platform use (works for iOS).

Notebook Navigator

A better file browser and calendar inspired by Apple Notes, Bear, Evernote and Day One.

Advanced URI

Control everything with URI.

Custom Frames

Turn web apps into panes using iframes with custom styling. Also comes with presets for Google Keep, Todoist and more.

Fast Note Sync

Real-time sync of your vaults across server, mobile, and web; shareable with anyone; supports REST and MCP integrations to build your personal AI knowledge base.

Find orphaned files and broken links

Find files that are not linked anywhere and would otherwise be lost in your vault. In other words: files with no backlinks.