关于 Obsidian MCP Server
Obsidian MCP Server 通过 Local REST API 插件连接 Obsidian 库,提供笔记、标签和 frontmatter 操作。它支持按路径限制读写权限,并为 MCP 客户端提供 stdio 和 Streamable HTTP 传输方式。
主要功能
- 01以正文、章节或结构化数据读取笔记
- 02按文本、JSONLogic 或 Omnisearch 搜索
- 03创建、追加、局部修改和替换笔记内容
- 04管理标签和 frontmatter 字段
- 05提供库、标签和状态资源
适用场景
- 01查找符合文本或结构化条件的笔记
- 02原位编辑标题章节或 frontmatter 字段
- 03将笔记访问限制在配置的库路径内
MCP 相关
该 MCP 服务提供 14 个工具和 3 个资源,用于操作 Obsidian 笔记、标签及状态,并支持 stdio 和 Streamable HTTP 传输。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
npx -y obsidian-mcp-serverOBSIDIAN_API_KEY密钥Bearer token for the Obsidian Local REST API plugin (Settings → Community Plugins → Local REST API).OBSIDIAN_BASE_URLBase 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_SSLWhether to verify the TLS certificate on the Obsidian endpoint. Default false because the plugin uses a self-signed cert.OBSIDIAN_REQUEST_TIMEOUT_MSPer-request timeout in milliseconds.OBSIDIAN_ENABLE_COMMANDSOpt-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_PATHSOptional comma-separated vault-relative folder allowlist for reads. Prefix-based with implicit recursion; case-insensitive; trailing slashes normalized. Unset = full vault. Write paths are implicitly readable. Example: 'public/,projects/'.OBSIDIAN_WRITE_PATHSOptional 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. Example: 'projects/,scratch/'.OBSIDIAN_READ_ONLYGlobal 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_ELICITATIONOpt-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 delete runs on the first call, bounded by OBSIDIAN_WRITE_PATHS and OBSIDIAN_READ_ONLY.OBSIDIAN_OMNISEARCH_URLOverride 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.MCP_LOG_LEVELSets the minimum log level for output (e.g., 'debug', 'info', 'warn').MCP_TRANSPORT_TYPESelects the HTTP transport.MCP_HTTP_HOSTThe hostname for the HTTP server.MCP_HTTP_PORTThe port to run the HTTP server on.MCP_HTTP_ENDPOINT_PATHThe endpoint path for the MCP server.MCP_AUTH_MODE密钥Authentication mode to use: 'none', 'jwt', or 'oauth'.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
12收录的工具列表 · 更新于 3 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| format | enum | 是 | 要返回的投影形式。`content` — 原始 Markdown 正文。`full` — 内容以及解析后的 frontmatter、标签和文件元数据。`document-map` — 标题、块 ID 和 frontmatter 字段名目录(用于发现补丁目标)。`section` — 单个标题、块或 frontmatter 区段(需要 `section`);标题区段包含该标题下的完整子树,嵌套时使用 `Parent::Child` 语法。content | full | document-map | section |
| target | any | 是 | 笔记所在的位置。 |
| section | object | 否 | 当 `format` 为 `"section"` 时必需。指定要提取的标题、块或 frontmatter。 |
| section.type | enum | 是 | 按名称指定标题、按引用指定块,或按键指定 frontmatter 字段。heading | block | frontmatter |
| section.target | string | 是 | 标题名称——完整路径(`"Parent::Child"`)或与唯一一个标题完全匹配的叶级名称——不带开头插入符的块引用(例如 "2d9b4a",而不是 "^2d9b4a"),或 frontmatter 字段名。 |
| includeLinks | boolean | 否 | 当 `format: "full"` 时为 true,会从笔记正文解析指向外部的 wiki 和 Markdown 链接引用。其他格式下会跳过。 |
详细介绍
obsidian-mcp-server
通过 MCP 读取、写入、搜索和精准编辑 Obsidian 知识库中的笔记、标签和 frontmatter。支持 STDIO 或 Streamable HTTP。
概述
通过 Local REST API 插件访问你的 Obsidian 知识库。读取、搜索和写入笔记,在原位置编辑单个标题、区块或 frontmatter 字段,并管理标签;同时内置按文件夹范围限定的读写权限。
工具
| 工具 | 描述 |
|---|---|
obsidian_get_note | 将笔记读取为原始内容、完整结构化形式、文档映射或单个部分 |
obsidian_list_notes | 递归列出 vault 路径下的笔记和文件夹,并按扩展名和名称筛选 |
obsidian_list_tags | 列出 vault 标签及其使用次数,按使用次数从高到低排序 |
obsidian_search_notes | 按文本、JSONLogic 搜索;如果 Omnisearch 插件可访问,也可使用 BM25 排序搜索 |
obsidian_write_note | 创建笔记、替换一个部分,或使用 overwrite: true 覆盖整个文件 |
obsidian_append_to_note | 向笔记追加内容(如果笔记不存在则创建),或追加到某个标题、块或 frontmatter 字段 |
obsidian_patch_note | 针对某个标题、块引用或 frontmatter 字段追加、前置或替换内容 |
obsidian_replace_in_note | 在单个笔记内执行字面值或正则搜索替换;默认仅搜索正文 |
obsidian_manage_frontmatter | 获取、设置或删除一个 frontmatter 键 |
obsidian_manage_tags | 在 frontmatter、行内或两者中添加、移除或列出笔记标签 |
obsidian_delete_note | 永久删除笔记;可选择在用户确认后删除(OBSIDIAN_DELETE_ELICITATION) |
obsidian_open_in_ui | 在 Obsidian 应用中打开文件,可选择在新窗格中打开 |
obsidian_list_commands | 列出命令面板命令(通过 OBSIDIAN_ENABLE_COMMANDS 选择启用) |
obsidian_execute_command | 按 ID 运行命令面板命令(通过 OBSIDIAN_ENABLE_COMMANDS 选择启用) |
资源
| 资源 | 描述 |
|---|---|
obsidian://vault/{+path} | 笔记的内容、frontmatter、标签和文件元数据 |
obsidian://tags | 所有 vault 标签及其使用次数,不设上限的快照 |
obsidian://status | 插件可访问性、身份验证状态、版本和已注册的 API 扩展 |
笔记和标签数据也可通过工具(obsidian_get_note、obsidian_list_tags)访问;obsidian://status 没有对应的工具。
功能参考
obsidian_get_note 工具
target可以是 vaultpath、active文件,或periodic笔记(从daily到yearly,date可选);format可以是content、full、document-map或section;full需使用includeLinks: true才会包含 vault 内部的出站链接result.format用于区分载荷;如果section读取结果匹配多个标题,则返回第一个匹配项,并在candidates中列出所有完整路径- 如果
path没有完全匹配项,但其文件夹中有一个不区分大小写的匹配项,则读取该文件:result.path是实际名称,requestedPath是传入的路径,notice会同时列出两者
obsidian_list_notes 工具
- 从
path(默认为 vault 根目录)开始遍历,深度为 1–20(默认为 2),并按extension和nameRegex(≤256 个字符)筛选;不符合nameRegex的文件夹不会被遍历 - 返回
entries[](file/directory)、totals和appliedFilters;遍历在 1,000 个条目处停止,并附带excluded.reason: "entry_cap";因深度限制而停止遍历的文件夹会带有truncated: true - 设置
OBSIDIAN_READ_PATHS后,列表中只包含可读取的条目以及通向作用范围的文件夹;这些文件夹会被遍历,并作为path接受
obsidian_list_tags 工具
- 使用
nameRegex(≤256 个字符)和minCount缩小范围,然后按次数对标签排序,并限制数量为limit(默认为 200,最大为 10000);层级父标签也会计数(work/tasks会计入work) - 如果有标签因数量上限而未显示,响应会包含
truncated、shown和cap - 设置
OBSIDIAN_READ_PATHS后,只列出来自可读取笔记的标签;count是包含该标签或其嵌套标签的可读取笔记数
obsidian_search_notes 工具
mode: "text"要求query中按空白拆分的每个词元都作为不区分大小写的子串出现在文件名或正文中(引号按字面处理);结果由contextLength(默认值为 100)、pathPrefix和maxMatchesPerHit(默认值为 10)控制;mode: "jsonlogic"则基于path、content、frontmatter.<key>、tags和stat评估logic树(在提供这些字段的插件版本中还包括links、backlinks和unresolvedLinks),其中glob/regexp接收[PATTERN, VALUE]result.mode用于区分负载;每种模式都会报告totalCount,并通过nextCursor分页;被maxMatchesPerHit截断的文本命中会带有truncated和totalMatches- 仅当启动时 Omnisearch 插件已响应,才会提供
mode: "omnisearch"(BM25 排名、带引号的短语、-exclusion、path:/ext:过滤器);其上游 50 条命中上限会将truncated设为true
obsidian_write_note 工具
- 接收
target和content,并可选接收section和contentType(markdown/json);将整份文件写入已有笔记时,若未设置overwrite: true,则会失败并返回file_exists - 在不区分大小写的文件系统(macOS、Windows)上,若要写入的整份文件路径与已有笔记仅字母大小写不同,则会失败并返回
case_variant_exists,且不会写入任何内容;当父文件夹的列表中恰好有一个大小写匹配项时,existingPath会标明该笔记;若存在多个匹配项,或该路径上有 Obsidian 不会索引的文件(点文件),则省略此字段 - 指定
section时,只替换对应的标题、块或 frontmatter 字段,并保留标题行;输出会报告created、sectionTargeted和解析后的sectionTarget
obsidian_append_to_note 工具
- 未指定
section时,追加到文件末尾或创建文件(created: true);指定section时,追加到已有笔记中对应的标题、块或 frontmatter 字段;设置createTargetIfMissing: true可创建该部分 - 若部分追加的内容已存在于目标位置,则会失败并返回
content_preexists;块目标不会添加分隔符,因此如需换行,请以换行符开头设置content - 在不区分大小写的文件系统上,若整份文件的路径与已有笔记仅字母大小写不同,则追加会失败并返回
case_variant_exists;当父文件夹的列表中恰好有一个大小写匹配项时,existingPath会标明该笔记
obsidian_patch_note 工具
- 对已有笔记的一个
section执行operation: "append" | "prepend" | "replace";patchOptions接受createTargetIfMissing、applyIfContentPreexists和trimTargetWhitespace(仅适用于插件 v4.x) - 返回解析后的
section和operation;若目标位置已存在相同内容,则会失败并返回content_preexists,除非设置了applyIfContentPreexists: true
obsidian_replace_in_note 工具
- 按顺序运行
replacements[],每项操作都会针对上一项的输出;每项接受useRegex(≤1024 个字符)、caseSensitive(默认值为true)、wholeWord、flexibleWhitespace(仅限字面模式)和replaceAll(默认值为true) - 返回
totalReplacements和包含bodyCount/frontmatterCount的perReplacement[] scope: "body"(默认值)会使 frontmatter 保持字节级不变;"frontmatter"和"both"会在之后重新解析 YAML,若解析失败(frontmatter_invalid),则不会写入任何内容
obsidian_manage_frontmatter 工具
- 对单个
key执行operation: "get" | "set" | "delete";set要求value为 JSON 类型 get会返回exists和value(不存在时为null);set和delete会返回变更后的完整frontmatter;若 YAML 无法解析,执行delete会失败并返回frontmatter_invalid,且不会写入任何内容
obsidian_manage_tags 工具
operation: "add" | "remove" | "list",并搭配tags;location: "frontmatter"(默认,即tags:数组)、"inline"(正文中的#tag;add会追加到文件末尾),或"both"add/remove会报告applied、skipped和生成的tags;list会返回frontmatter、inline和all- 内联标签检测遵循 Obsidian 的标签语法:跳过代码、双链、图片、链接目标、HTML 和数学内容,并会读取
%% … %%注释
obsidian_delete_note 工具
- 接受
target(路径、当前文件或周期笔记),并首先检查其是否位于写入范围内;文件夹路径会报错path_is_directory。API 层面不提供撤销功能,只能使用 Obsidian 的本地垃圾箱 - 路径必须完全匹配,包括字母大小写,即使文件系统不区分大小写也是如此。大小写不同或省略扩展名的路径会在删除任何内容前报错
note_missing,并在suggestions中列出相近路径 - 默认情况下,首次调用即会删除笔记,不需要确认;
OBSIDIAN_WRITE_PATHS和OBSIDIAN_READ_ONLY会限制其可访问范围 - 设置
OBSIDIAN_DELETE_ELICITATION=true后,首次调用会返回确认请求,其中包含路径和字节大小;只有用户接受后才会删除笔记。拒绝会报错cancelled,不支持征询确认的客户端无法删除笔记 - 在此模式下,回答只有与显示提示时存储的单次使用同意记录匹配才有效;该记录绑定调用方、路径以及当时的笔记内容。预先提供或重放的回答,或在笔记更改后给出的回答,都会触发新的确认提示
- 同意记录存储在服务的存储提供程序中(
STORAGE_PROVIDER_TYPE,默认为in-memory,仅限当前进程)。这适用于 stdio 或单个 HTTP 实例;多个实例共用一个端点时,需要使用共享提供程序(filesystem、supabase或cloudflare-d1,不能使用cloudflare-kv)
obsidian_open_in_ui 工具
path、failIfMissing(默认true)和newLeaf(在拆分窗格中打开);当failIfMissing: false时,会创建不存在的文件,此操作需要写入权限createdIfMissing会报告执行了哪个分支- 如果
path的大小写不匹配,但存在一个不区分大小写的匹配项,则会打开该文件而不是创建另一个文件,并通过notice报告作为requestedPath发送的路径
obsidian_list_commands 工具
- 可选的
nameRegex(≤256 个字符),用于匹配每个命令的显示名称 - 返回包含
id和name的commands[],其中id可用于obsidian_execute_command - 仅当
OBSIDIAN_ENABLE_COMMANDS=true且OBSIDIAN_READ_ONLY未启用时才会列出
obsidian_execute_command 工具
- 使用来自
obsidian_list_commands的commandId;成功时返回executed: true,未注册的 ID 会报错command_unknown - 以键盘快捷键的权限运行,因此某些命令具有破坏性(删除文件、关闭库);其启用条件与
obsidian_list_commands相同
obsidian://vault/{+path} 资源
{+path}会捕获/vault/之后的所有内容,包括斜杠;字面路径和百分号编码路径会解析为同一篇笔记- 返回
path、content、frontmatter、tags和stat,结构与format: "full"的obsidian_get_note相同;失败时会报错path_forbidden、note_missing或path_is_directory
obsidian://tags 资源
- 返回每个标签及其
count,不设上限、不排序,并包含分层标签的父级 - 设置
OBSIDIAN_READ_PATHS后,仅包含可读取笔记中的标签,计数方式与obsidian_list_tags相同 - 不提供排序或筛选;
obsidian_list_tags提供按数量排序且有上限的视图
obsidian://status 资源
status、service、authenticated、versions、manifest和apiExtensions[];即使 API 密钥错误也会响应,并报告authenticated: false- 对于插件 v5.0.2 及更高版本,在使用
periodic目标前,请检查apiExtensions中是否包含local-rest-api-periodic-notes
功能
基于 @cyanheads/mcp-ts-core 构建:支持 stdio 和 Streamable HTTP 传输、可插拔身份验证(none / jwt / oauth)、可替换存储(in-memory、filesystem、Supabase、Cloudflare KV/R2/D1),以及带可选 OpenTelemetry 跟踪功能的结构化日志记录。
Obsidian 专属功能:
- 为 Obsidian Local REST API 插件提供类型化客户端;分节写入会根据插件报告的版本,向 v5.0 及更高版本发送 markdown-patch 2.0,向 v4.x 发送 1.x
- 标题目标可使用完整的
Parent::Child路径或不带父级的叶节点名称;若目标不明确,写入会返回ambiguous_section及其candidates,除非恰好只有一个匹配项是顶级标题。对于插件 v5.0 及更高版本,添加到标题下的内容会以空行分隔(列表项会接续相邻列表),且其中的标题必须低于该分节的层级(heading_outside_section) - 支持按文件夹限定的读写权限、只读开关,以及选择启用的一对命令面板命令(参见路径策略);服务器级别的
instructions会在initialize时报告当前生效的策略 obsidian_get_note和obsidian_open_in_ui会针对大小写不匹配的路径重试实际文件名,并通过requestedPath和notice说明;路径不存在时会提供Did you mean建议;写入和删除则要求路径完全匹配- 正则表达式输入长度受限(
nameRegex最多 256 个字符,useRegex最多 1024 个字符);包含嵌套量词时会以regex_unsafe拒绝 - 没有专用的反向链接工具;
obsidian_search_notes的jsonlogic模式可通过{"regexp": ["\\[\\[Target Note(\\\\?\\||#|\\]\\])", {"var": "content"}]}查找反向链接,该表达式也能匹配适用于表格的[[Target Note\|Alias]]
便于 Agent 使用的输出:
- 提供恢复指引的错误:每种声明的失败都包含
reason、JSON-RPC 代码以及针对该情况编写的recovery.hint - 大小变化量:每个变更类工具都会返回
previousSizeInBytes/currentSizeInBytes,调用方无需后续读取即可发现意外覆盖 - 将歧义作为数据呈现:共享标题名称会返回
candidates,标签操作会报告applied与skipped - 使用判别式输出约定:
obsidian_get_note使用format,obsidian_search_notes使用mode,obsidian_manage_frontmatter和obsidian_manage_tags使用operation
开始使用
将其添加到 Claude Code:
claude mcp add obsidian-mcp-server -e OBSIDIAN_API_KEY=your-api-key -- npx -y obsidian-mcp-server
对于其他客户端,将以下内容添加到 MCP 配置文件:
{
"mcpServers": {
"obsidian-mcp-server": {
"command": "npx",
"args": ["-y", "obsidian-mcp-server"],
"env": { "OBSIDIAN_API_KEY": "your-api-key" }
}
}
}
按照先决条件中的说明设置插件后,在 Obsidian 的 设置 → 社区插件 → Local REST API 中生成密钥。Docker 或从源码构建的相关说明,请参阅运行服务。
前置条件
- 在你的库中启用 Obsidian Local REST API 插件,版本为 v4.0.0 或更高。其 API 密钥为
OBSIDIAN_API_KEY。 - 服务默认使用
http://127.0.0.1:27123,因此请在插件设置中启用 "Non-encrypted (HTTP) Server",或设置OBSIDIAN_BASE_URL=https://127.0.0.1:27124,以使用始终开启的 HTTPS 端口(当OBSIDIAN_VERIFY_SSL=false(默认值)时,系统会接受其自签名证书)。 - 周期笔记目标在插件 v5.0.1 及更早版本中可原生使用。从 v5.0.2 起,需要安装 periodic-notes API extension;未安装时会报错
periodic_unsupported。 - 在插件 v4.x 中,向使用 CRLF(Windows)换行符的笔记写入标题段落时,内容会落在行中间:插件的 markdown-patch 1.x 引擎会将其放错位置,且服务无法修正。插件 v5.0 及更高版本可处理使用 CRLF 换行符的笔记。
- 插件 v6.0 移除了 markdown-patch 1.x,但以下两种表格行写入(
contentType: "json")仍会使用它:标题下方的行,以及通过表格下方独立一行的块 ID 定位的行。在 v6.0 中,请通过表格最后一行上的 ID 定位表格。 - 使用
OBSIDIAN_DELETE_ELICITATION=true时,需使用支持 elicitation 并能呈现其表单的 MCP 客户端,才能使用obsidian_delete_note。其他所有工具以及默认删除功能均无需此条件。
配置
| 变量 | 描述 | 默认值 |
|---|---|---|
OBSIDIAN_API_KEY | 必需。 Local REST API 插件的 Bearer 令牌。 | — |
OBSIDIAN_BASE_URL | Local REST API 基础 URL;https://127.0.0.1:27124 是始终启用的 HTTPS 端口。末尾的斜杠会被移除。如果没有响应,请求会以 obsidian_unreachable 失败。 | http://127.0.0.1:27123 |
OBSIDIAN_VERIFY_SSL | 验证插件的 TLS 证书。默认关闭,因为插件使用自签名证书;此放宽仅适用于 https: OBSIDIAN_BASE_URL。设为 true 时,不受信任的证书会导致请求以 certificate_rejected 失败。 | false |
OBSIDIAN_REQUEST_TIMEOUT_MS | 单次请求的超时时间,单位为毫秒。 | 30000 |
OBSIDIAN_ENABLE_COMMANDS | 启用 obsidian_list_commands 和 obsidian_execute_command。命令是不透明的,且可能具有破坏性。 | false |
OBSIDIAN_READ_PATHS | 以逗号分隔的读取文件夹允许列表。参见路径策略。 | 未设置(整个仓库) |
OBSIDIAN_WRITE_PATHS | 以逗号分隔的写入文件夹允许列表。参见路径策略。 | 未设置(使用读取范围;若未设置读取范围,则使用整个仓库) |
OBSIDIAN_READ_ONLY | 拒绝所有写入并禁用命令面板工具对。 | false |
OBSIDIAN_DELETE_ELICITATION | 删除前,通过征询表单请用户确认每次 obsidian_delete_note 调用。需要能够呈现征询的客户端,以及通过 HTTP 建立的有状态会话(当 OBSIDIAN_READ_ONLY=true 禁用该工具时则不需要)。关闭时,首次调用就会执行删除。 | false |
OBSIDIAN_OMNISEARCH_URL | Omnisearch HTTP 服务 URL。未设置时,会根据 OBSIDIAN_BASE_URL 的主机名推导,并使用端口 51361。启动时探测一次;只有在有响应时才会显示 omnisearch 搜索模式。 | 推导得出 |
MCP_TRANSPORT_TYPE | 传输方式:stdio 或 http。 | stdio |
MCP_HTTP_PORT | HTTP 服务端口。 | 3010 |
MCP_SESSION_MODE | HTTP 会话模式:stateful、stateless 或 auto。当 OBSIDIAN_DELETE_ELICITATION=true 且 OBSIDIAN_READ_ONLY 关闭时,服务需要有状态会话,因为在 2025 年的客户端上确认操作需要会话,因此通过 HTTP 启动时,stateless 会失败。对 stdio 无影响。 | stateful |
MCP_AUTH_MODE | 身份验证:none、jwt 或 oauth。 | none |
MCP_LOG_LEVEL | 日志级别(RFC 5424)。 | info |
LOGS_DIR | 日志文件目录(仅限 Node.js)。 | <project-root>/logs |
OTEL_ENABLED | 启用 OpenTelemetry。 | false |
完整的可选覆盖项列表请参见 .env.example。
路径策略
三个可选环境变量可限制工具能够访问的保险库路径。未设置时,读写范围覆盖整个保险库。
| 目标 | 配置 |
|---|---|
随处读取,仅在 projects/ 和 scratch/ 中写入 | OBSIDIAN_WRITE_PATHS=projects/,scratch/ |
仅读取 public/,仅在 public/inbox/ 中写入 | OBSIDIAN_READ_PATHS=public/、OBSIDIAN_WRITE_PATHS=public/inbox/ |
| 禁止在任何位置写入 | OBSIDIAN_READ_ONLY=true |
- 匹配方式为前缀匹配,递归且不区分大小写;末尾的斜杠会被规范化。写入路径也可读取。
OBSIDIAN_READ_ONLY=true会从tools/list中移除所有写入工具和命令面板工具对,包括obsidian_manage_frontmatter和obsidian_manage_tags(因此它们的get/list也会一并移除)。obsidian_open_in_ui仍可打开现有文件,但不会创建文件。- 拒绝访问时会返回
path_forbidden,并在data.activeScope中回显当前生效的范围和恢复提示。若对active或periodic目标的访问被拒绝,会指出目标((active file)、daily note for 2026-10-01),而不是它解析到的笔记。obsidian_list_notes只列出可读条目以及通往范围的文件夹,因此可以从根目录逐级浏览到嵌套范围。 - 设置
OBSIDIAN_READ_PATHS后,搜索只会返回可读笔记,JSONLogic 树也不会读取范围之外的笔记:服务会在可读笔记上计算该树,其中links、backlinks和unresolvedLinks仅包含可读条目。链接指向哪篇笔记仍由 Obsidian 在整个保险库范围内解析,因此在范围外创建或删除笔记时,这三个字段可能会变化;如有需要,请在content中匹配链接文本。该计算有上限:嵌套最多 1,000 层;对树构建的值设有每篇笔记的工作预算,对保留的结果设有每次搜索的工作预算;超时为 10 秒。超出任一上限的树会以logic_too_costly失败。若可读笔记的数据嵌套过深,无法交给计算器处理(在 Node 下约为 3,500 层),搜索会以note_too_deep失败。未设置读取范围时,树会原样传给插件。 - 设置
OBSIDIAN_READ_PATHS后,标签列表(obsidian_list_tags、obsidian://tags)仅统计可读笔记,按笔记数量而非出现次数计数。仅设置写入路径或只读模式时,标签列表仍覆盖整个保险库。 - 服务的
instructions会说明生效的范围:可读范围为读取路径加写入路径;可写范围为写入路径,或者仅限制读取时的读取范围。启动日志会打印已配置的列表。
运行服务
本地开发
需要 Bun v1.4.0 或更高版本(或 Node.js v24+)。
-
克隆并安装:
git clone https://github.com/cyanheads/obsidian-mcp-server.git cd obsidian-mcp-server && bun install cp .env.example .env # set OBSIDIAN_API_KEY -
构建并运行生产版本:
# One-time build bun run rebuild # Run the built server bun run start:stdio # or, listening at http://127.0.0.1:3010/mcp bun run start:http -
运行检查和测试:
bun run devcheck # Lint, format, typecheck, security, changelog sync bun run test # Vitest test suite bun run lint:mcp # Validate MCP definitions against spec
Docker
docker run --rm -e OBSIDIAN_API_KEY=your-key -p 3010:3010 ghcr.io/cyanheads/obsidian-mcp-server:latest
镜像默认使用 0.0.0.0 上的 HTTP 传输、有状态会话,并将日志写入 /var/log/obsidian-mcp-server。在容器内,默认的 OBSIDIAN_BASE_URL(http://127.0.0.1:27123)指向容器自身的回环地址:若要访问主机上的插件,请将其指向 http://host.docker.internal:27123(Docker Desktop),或使用 --network host(Linux)。若要通过 MCP 客户端使用 stdio 运行,请使用 "command": "docker" 和 "args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "-e", "OBSIDIAN_API_KEY=your-key", "-e", "OBSIDIAN_BASE_URL=http://host.docker.internal:27123", "ghcr.io/cyanheads/obsidian-mcp-server:latest"]。若要在本地构建,请运行 docker build -t obsidian-mcp-server .;默认会安装 OpenTelemetry 对等依赖,若要省略,请使用 --build-arg OTEL_ENABLED=false 进行构建。
如果其他机器能够访问该端口,请设置 MCP_AUTH_MODE=jwt(并设置 MCP_AUTH_SECRET_KEY)或 oauth。若使用默认值 none,每个调用方都能使用你的 OBSIDIAN_API_KEY 操作你的保险库。
项目结构
| 目录 | 用途 |
|---|---|
src/index.ts | createApp() 入口:注册工具和资源,探测 Omnisearch,并应用只读和命令门控。 |
src/config | 使用 Zod 解析服务特定的环境变量(OBSIDIAN_*)。 |
src/services/obsidian | 本地 REST API 客户端、路径策略、Markdown 补丁格式处理、frontmatter/章节/标签解析、领域类型。 |
src/mcp-server/tools | 工具定义(*.tool.ts)以及共享的架构和辅助函数。 |
src/mcp-server/resources | 资源定义(*.resource.ts)。 |
src/mcp-server/prompts | 提示词定义(未注册)。 |
tests/ | 针对工具、资源、服务和配置的 Vitest 测试。 |
docs/ | 本地 REST API OpenAPI 规范和生成的 tree.md。 |
changelog/ | 各版本的发布说明;CHANGELOG.md 是重新生成的汇总文件。 |
开发指南
开发指南和架构规则请参阅 CLAUDE.md。简要来说:
- 处理程序抛出异常,由框架捕获——工具逻辑中不要使用
try/catch - 使用
ctx.log记录请求范围内的日志;所有本地 REST API 调用都必须通过getObsidianService()路由 - 通过
src/mcp-server/*/definitions/index.ts中的汇总文件注册新工具和资源 - 封装外部 API 调用:验证原始数据 → 规范化为领域类型 → 返回输出架构;绝不伪造缺失字段
贡献
Bug、功能请求和文档缺漏请提交 issue;关于哪些内容有助于采取行动,请参阅 CONTRIBUTING.md,关于我们的协作方式,请参阅 CODE_OF_CONDUCT.md。安全报告请通过 SECURITY.md 提交,切勿发布到公开 issue。
提交前请运行检查和测试:
bun run devcheck
bun run test
许可证
Apache-2.0 — 详情请参阅 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。