经 AI Skill Hub 精选评估,obsidian-local-rest-api MCP工具 获评「强烈推荐」。已获得 2.2k 颗 GitHub Star,这款MCP工具在功能完整性、社区活跃度和易用性方面表现出色,AI 评分 8.2 分,适合有一定技术背景的用户使用。
为Obsidian笔记库提供安全的REST API和MCP服务器。支持远程访问vault数据,集成AI模型上下文协议,适合开发者构建笔记自动化工具和AI应用。
obsidian-local-rest-api MCP工具 是一款遵循 MCP(Model Context Protocol)标准协议的 AI 工具扩展。通过 MCP 协议,它可以让 Claude、Cursor 等主流 AI 客户端直接访问和操作外部工具、数据源和服务,实现 AI 能力的无缝扩展。无论是文件操作、数据库查询还是 API 调用,都可以通过自然语言在 AI 对话中直接触发,极大提升生产效率。
为Obsidian笔记库提供安全的REST API和MCP服务器。支持远程访问vault数据,集成AI模型上下文协议,适合开发者构建笔记自动化工具和AI应用。
obsidian-local-rest-api MCP工具 是一款遵循 MCP(Model Context Protocol)标准协议的 AI 工具扩展。通过 MCP 协议,它可以让 Claude、Cursor 等主流 AI 客户端直接访问和操作外部工具、数据源和服务,实现 AI 能力的无缝扩展。无论是文件操作、数据库查询还是 API 调用,都可以通过自然语言在 AI 对话中直接触发,极大提升生产效率。
# 方式一:通过 Claude Code CLI 一键安装
claude skill install https://github.com/coddingtonbear/obsidian-local-rest-api
# 方式二:手动配置 claude_desktop_config.json
{
"mcpServers": {
"obsidian-local-rest-api-mcp--": {
"command": "npx",
"args": ["-y", "obsidian-local-rest-api"]
}
}
}
# 配置文件位置
# macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
# Windows: %APPDATA%/Claude/claude_desktop_config.json
# 安装后在 Claude 对话中直接使用 # 示例: 用户: 请帮我用 obsidian-local-rest-api MCP工具 执行以下任务... Claude: [自动调用 obsidian-local-rest-api MCP工具 MCP 工具处理请求] # 查看可用工具列表 # 在 Claude 中输入:"列出所有可用的 MCP 工具"
// claude_desktop_config.json 配置示例
{
"mcpServers": {
"obsidian-local-rest-api_mcp__": {
"command": "npx",
"args": ["-y", "obsidian-local-rest-api"],
"env": {
// "API_KEY": "your-api-key-here"
}
}
}
}
// 保存后重启 Claude Desktop 生效
After installing and enabling the plugin, open Settings → Local REST API to find your API key and certificate.
The API refuses to read or write any file inside Obsidian's configuration directory (app.vault.configDir, normally .obsidian) — for both REST and MCP, reads as well as writes. A request for such a path is rejected with 403 (error code 40321) at the REST layer or a path error from an MCP tool.
That directory holds plugin code and each plugin's data.json — including this plugin's own, where your API key is stored. Writing into it is effectively remote code execution, since Obsidian runs an enabled plugin's main.js; reading from it leaks those secrets. Blocking it keeps a credential documented as "vault file access" from silently granting more (see GHSA-66m9-r757-qvq7).
The check is against where a path lands on disk, not just how it is spelled: a Windows 8.3 short name such as OBSIDI~1, a differently cased spelling on a case-insensitive filesystem, or a symlink that points into the configuration directory is refused the same way. Search and the tag listing skip any indexed note that lives there too, so a symlinked folder cannot hand the contents out by another route.
If you deliberately manage your Obsidian configuration through the API, turn on Settings → Local REST API → Advanced settings → Allow access to the configuration directory. It is off by default, and turning it on grants every holder of your API key that access.
Give your scripts, browser extensions, and AI agents a direct line into your Obsidian vault via a secure, authenticated REST API.
```sh
| 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.
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 — sendMarkdown-Patch-Version: 1to opt back into it (the same header also selects the legacy::-joined document map on GET), and responses served by it carry aDeprecation: 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. If your content contains headings, adjust their levels too: 1.x wrote them literally, and 2.x treats them as relative to the target (see the migration guide there).
See the interactive docs for the full instruction schema and options.
curl -N "<url>" ```
It takes two steps because a browser's EventSource can only make GET requests, which have no body to carry a filter.
The events are Obsidian's own, and only these can be streamed:
| Emitter | Events |
|---|---|
vault | create, modify, delete, rename |
metadataCache | changed, deleted, resolve, resolved |
workspace | file-open, active-leaf-change, layout-change |
Each event is serialized by code written for it. That code decides exactly what is sent: the path, the file's NoteJson (the same shape /search/ evaluates), and a few event-specific fields such as oldPath on a rename. Note content is sent only when the filter reads file.content. Events whose payloads are keystrokes, clipboard data, or UI objects (editor-change, quick-preview, editor-paste, the menu events, …) can't be streamed. To react to frontmatter changes, use metadataCache changed: vault modify fires before Obsidian has re-read the file's metadata.
Each message's id is <epoch>-<counter>. A new epoch, or a gap in the counter, means events were missed. Nothing is replayed. A stream URL expires after the signed-URL lifetime (or ?ttl=<seconds>), but a stream opened before then stays open. At most 16 streams can be open at once. Anyone holding a signed stream URL sees the paths and metadata of every event its filter matches, so treat it like the notes themselves. See the API docs for the full message format.
Other plugins can register their own authenticated routes, public routes, MCP tools, streamable events, and state against this plugin's server. See Adding your own API Routes via an Extension for a walkthrough.
Public routes (addPublicRoute) are answered before the API key is checked, so they can't sit under a prefix the plugin serves its own routes from: /vault/, /active/, /search/, /commands/, /events/, /mcp/, /open/, and /tags/, in any letter case, along with /, the OpenAPI documents, and the certificate. A path whose first segment is a pattern (/:name/, /*) is refused for the same reason. addPublicRoute throws when you register one of these, so start public routes with a literal segment of your own, such as your plugin's id. Authenticated routes (addRoute) and vault sub-resources are unaffected.
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.
From extension API version 3, an extension can add its own events to the event streams. Each one is streamed under the extension's plugin id as the emitter:
const api = getAPI(this.app, this.manifest, 3);
// Your plugin's own Events instance; call this.events.trigger("task-completed", ...)
// wherever the event happens.
this.events = new Events();
api.addStreamableEvent("task-completed", {
source: this.events,
serialize: (file, line) => ({ path: (file as TFile).path, line }),
});
// Now available at POST /events/<your plugin id>/task-completed/
Your serializer decides everything a stream sends. The host adds emitter and event and sends nothing else, so return only what someone holding a stream URL should see. Return null to skip an occurrence. unregister() closes any open streams for your events.
From extension API version 4, an extension can publish its own namespace in the state section of GET /, under its plugin id, for anything a client would read to decide whether to proceed: whether an index is built, when a sync last ran, how much work is queued.
const api = getAPI(this.app, this.manifest, 4);
api.addState({
description: "Whether the semantic index is ready to query, and how far along a rebuild is.",
schema: {
type: "object",
required: ["ready", "pending"],
properties: {
ready: { type: "boolean" },
pending: { type: "integer", description: "Notes not yet indexed." },
lastRunAt: { type: ["string", "null"], format: "date-time" },
},
},
read: async () => ({ ready: this.index.ready, pending: this.queue.length, lastRunAt: this.lastRunAt }),
});
// Now served as state["<your plugin id>"] on every authenticated GET /
read is called on every authenticated GET /, concurrently with every other extension's, and raced against the read budget from the plugin's advanced settings. A read that overruns, rejects, or resolves to anything but a JSON object is served as null for your extension and logged to the console, once, until a read succeeds again; nothing else in the response is affected. Keep it cheap: compute in the background and hand back the latest result. The schema, if you give one, is merged into the GET / response schema at /openapi.yaml, so clients can rely on the shape; without it the namespace is documented as a free-form object. Either way the published entry also admits null, since that is what a failed read is served as. unregister() removes both.
高质量MCP实现,填补Obsidian与AI应用集成的空白。代码活跃维护,设计理念先进。开发者友好,文档齐全。
AI Skill Hub 为第三方内容聚合平台,本页面信息基于公开数据整理,不对工具功能和质量作任何法律背书。
建议在沙箱或测试环境中充分验证后,再部署至生产环境,并做好必要的安全评估。
✅ MIT 协议 — 最宽松的开源协议之一,可自由商用、修改、分发,仅需保留版权声明。
AI Skill Hub 点评:obsidian-local-rest-api MCP工具 的核心功能完整,质量优秀。对于Claude Desktop / Claude Code 用户来说,这是一个值得纳入个人工具库的选择。建议先在非生产环境试用,再逐步推广。
| 原始名称 | obsidian-local-rest-api |
| 原始描述 | 开源MCP工具:A secure REST API and Model Context Protocol (MCP) server for your vault.。⭐2.2k · TypeScript |
| Topics | REST APIMCP服务器Obsidian笔记自动化TypeScript |
| GitHub | https://github.com/coddingtonbear/obsidian-local-rest-api |
| License | MIT |
| 语言 | TypeScript |
收录时间:2026-05-16 · 更新时间:2026-05-19 · License:MIT · AI Skill Hub 不对第三方内容的准确性作法律背书。
选择 Agent 类型,复制安装指令后粘贴到对应客户端