mcpField
O
Obsidian Mcp Server

Obsidian Mcp Server

本地服务
github.com/smith-and-web记忆与知识192 天前更新

关于 Obsidian Mcp Server

Obsidian MCP Server 通过 MCP 连接,让 AI 助手操作笔记及知识库结构。它提供笔记编辑、元数据和链接工具,并可选用 Postgres、pgvector 与 Ollama 实现本地语义搜索。

主要功能

  1. 01创建、编辑、移动和读取笔记
  2. 02管理标签与 YAML frontmatter
  3. 03搜索笔记并检查链接
  4. 04编辑章节与目录
  5. 05可选的本地语义搜索

适用场景

  1. 01通过 AI 助手创建和整理笔记
  2. 02按文本、标签或反向链接查找笔记
  3. 03审查标签及未解析的 wiki 链接
  4. 04使用本地嵌入搜索相关笔记

MCP 相关

该服务通过 HTTP 和 SSE 将 Obsidian 知识库操作作为 MCP 工具提供,不直接支持 stdio。配置 DATABASE_URL 后,可启用可选的语义搜索工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"obsidian-mcp-server-smith-and-web": {
"command": "npx",
"args": [
"-y",
"@smith-and-web/obsidian-mcp-server"
],
"env": {
"VAULT_PATH": "<VAULT_PATH>",
"PORT": "<PORT>"
}
}
}
}
启动命令npx -y @smith-and-web/obsidian-mcp-server
需要配置的环境变量
VAULT_PATH
PORT

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@smith-and-web/obsidian-mcp-server

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

Obsidian MCP 服务

CI npm Docker License Node.js MCP TypeScript Sponsor

一个 Model Context Protocol (MCP) 服务,可让 Claude 等 AI 助手与您的 Obsidian 知识库交互。通过自然对话访问笔记、创建内容、管理标签并搜索知识库。

功能

笔记管理
  • CRUD 操作:创建、读取、更新和删除笔记(需安全确认)
  • 写入模式:覆盖、追加或前置内容
  • 批量读取:在单个请求中读取多篇笔记
  • 文件信息:无需读取内容即可获取元数据(适用于大型知识库)
  • 移动/复制:重新整理知识库结构
  • 分节操作:按标题读取、追加或替换特定章节
Frontmatter 与标签
  • Frontmatter 解析:将 YAML frontmatter 作为结构化 JSON 获取/设置(由 gray-matter 提供支持)
  • 标签管理:添加/移除标签(frontmatter 或行内)
  • 标签审计:查找缺少必需标签的笔记
  • 标签搜索:列出所有标签及其使用次数
搜索与链接
  • 全文搜索:搜索内容和文件名,并显示上下文
  • 反向链接:查找所有指向指定笔记的笔记
  • 失效链接:检测无法解析的维基链接
  • 查找与替换:批量替换文本,支持正则表达式
语义搜索(可选)
  • 按含义搜索:在按标题感知方式拆分的文本块上进行混合向量 + 全文检索,由 Postgres + pgvector 和来自 Ollama 的本地嵌入提供支持
  • 相似笔记:根据整篇笔记的嵌入,查找与指定笔记最相似的笔记
  • 增量索引器:使用同一镜像运行的第二个进程,用于轮询知识库并仅重新嵌入发生变化的内容;适用于无法使用 inotify 的 NFS/SMB
  • 数据不会离开您的网络:嵌入在本地计算;除非设置了 DATABASE_URL,否则此功能完全关闭
目录操作
  • 创建/删除/重命名:全面的目录管理
  • 列出内容:浏览知识库结构
性能
  • 令牌优化:可选的精简响应模式(响应缩小 40-60%)
  • 高效扫描:无需读取内容即可获取文件信息
  • SSE 传输:无需本地安装即可远程访问

快速开始

客户端如何连接:该服务仅通过 HTTP + SSE 使用 MCP 通信(不支持 stdio 模式)。启动服务(使用 npx、Docker 或从源代码运行),然后让客户端连接到 http://HOST:PORT/sse。仅支持 stdio 服务的客户端可通过 mcp-remote 连接,如下所示。服务会监听 PORT 上的所有网络接口,因此请设置 API_KEY(参见身份验证),或将其限制在回环地址上(例如在 Docker 中使用 -p 127.0.0.1:3001:3000),除非您希望整个网络都能读写您的知识库。

npx(最快)

需要 Node.js 20.19 或更高版本。此命令会在前台启动服务(默认端口为 3000):

VAULT_PATH=/path/to/your/vault npx @smith-and-web/obsidian-mcp-server

使用选项:

VAULT_PATH=/path/to/vault PORT=3001 COMPACT_RESPONSES=true npx @smith-and-web/obsidian-mcp-server
Docker(生产环境推荐)

使用 GitHub Container Registry 中的预构建镜像:

docker run -d \
  --name obsidian-mcp \
  -v /path/to/your/vault:/vault:rw \
  -p 127.0.0.1:3001:3000 \
  -e VAULT_PATH=/vault \
  ghcr.io/smith-and-web/obsidian-mcp-server:latest

latest 会跟随最新版本;生产环境请固定版本标签(例如 :1.6.0)。只有在设置了 API_KEY 且希望其他机器连接时,才去掉 127.0.0.1:。

或使用 Docker Compose:

  1. 创建 docker-compose.yml:

    services:
      obsidian-mcp:
        image: ghcr.io/smith-and-web/obsidian-mcp-server:latest
        container_name: obsidian-mcp
        restart: unless-stopped
        volumes:
          - /path/to/your/vault:/vault:rw
        ports:
          - "127.0.0.1:3001:3000"
        environment:
          - VAULT_PATH=/vault
    
  2. 启动服务

    docker compose up -d
    
  3. 验证服务是否正在运行

    curl http://localhost:3001/health
    
本地开发
  1. 安装依赖

    npm install
    
  2. 设置环境变量

    export VAULT_PATH=/path/to/your/vault
    export PORT=3000
    
  3. 启动服务

    npm start
    # Or with auto-reload:
    npm run dev
    

AI 助手配置

Claude Desktop

将以下内容添加到 Claude Desktop 配置文件中:

  • macOS:~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows:%APPDATA%\Claude\claude_desktop_config.json

选项 1:本地服务(通过 mcp-remote)

{
  "mcpServers": {
    "obsidian": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://localhost:3001/sse"]
    }
  }
}

选项 2:使用 HTTPS 的远程服务

{
  "mcpServers": {
    "obsidian": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://your-domain.com/sse"]
    }
  }
}

服务必须已在运行(参见“快速入门”)。Claude Desktop 会启动 mcp-remote,将其 stdio 桥接到服务的 SSE 端点;Claude Desktop 无法直接启动此服务,因为该服务不使用 stdio 通信。

Cursor

将以下内容添加到 Cursor MCP 设置中(Settings → MCP):

{
  "mcpServers": {
    "obsidian": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://localhost:3001/sse"]
    }
  }
}
其他 MCP 客户端

Claude Code 直接支持 SSE 服务:

claude mcp add --transport sse obsidian http://localhost:3001/sse
# with an API key:
claude mcp add --transport sse obsidian https://your-host/sse --header "Authorization: Bearer your-secret-key"

任何其他兼容 MCP 的客户端都可以使用 mcp-remote 连接:

npx mcp-remote http://localhost:3001/sse

如果客户端原生支持 SSE 服务,也可以直接连接到 SSE 端点 http://localhost:3001/sse。

可用工具

笔记操作
工具描述
read-note读取笔记内容(支持使用 frontmatterOnly 提高效率)
read-multiple-notes批量读取多篇笔记
create-note创建新笔记
edit-note替换笔记内容
write-note以覆盖、追加或前置模式写入
delete-note删除笔记(需要确认)
move-note移动/重命名笔记
duplicate-note将笔记复制到新位置
get-notes-info获取文件元数据,而不读取内容
目录操作
工具描述
list-vault列出文件和目录
create-directory创建新目录
delete-directory删除目录(可递归)
rename-directory重命名/移动目录
Frontmatter 与标签
工具描述
get-frontmatter将 YAML frontmatter 作为 JSON 获取
update-frontmatter原地更新 frontmatter 字段(未修改的字段会保留原有文本;遇到无效 YAML 时会拒绝操作)
add-tags向 frontmatter 或行内添加标签
remove-tags从笔记中移除标签
list-tags列出所有标签及其数量
find-notes-by-tag查找带有特定标签的笔记
search-missing-tag查找缺少某个标签的笔记
audit-tags审查文件夹中是否包含必需标签
搜索与链接
工具描述
search-vault全文搜索并显示上下文
get-backlinks查找链接到某篇笔记的其他笔记
find-broken-links查找无法解析的 wiki 链接
find-replace批量查找和替换
语义搜索(仅在设置了 DATABASE_URL 时可用)
工具描述
semantic-search混合向量 + 全文搜索;按 directory、tags、frontmatter type 和 status 筛选;`mode: hybrid
similar-notes按质心嵌入查找与某条笔记最相似的笔记
index-status模型、计数、索引器上次运行时间和延迟
reindex-note立即重新索引一条笔记
search-feedback记录搜索评分以及已使用或预期的路径;仅在启用学习日志时可用
recommend-notes使用 best_score 或 average_vector 查找与正面示例相似、与负面示例不同的笔记;需要语义搜索
maintenance-decision记录对维护发现的明确接受或拒绝决定;需要语义搜索

请参阅语义搜索了解设置方法。

分节操作
工具描述
read-section读取标题下的内容
append-to-section在某个分节末尾追加内容
replace-section替换分节内容
append-to-file在文件末尾追加内容
insert-at-marker在文本标记处插入内容
list-headings列出笔记中的所有标题

架构

┌─────────────────┐     HTTPS/SSE      ┌──────────────────┐
│  Claude Desktop │ ◄────────────────► │   MCP Server     │
└─────────────────┘                    │   (Express.js)   │
                                       └────────┬─────────┘
                                                │
                                       ┌────────▼─────────┐
                                       │   VaultManager   │
                                       │   (File System)  │
                                       └────────┬─────────┘
                                                │
                                       ┌────────▼─────────┐
                                       │  Obsidian Vault  │
                                       │   (Markdown)     │
                                       └──────────────────┘

项目结构

obsidian-mcp-server/
├── src/
│   ├── index.ts              # Express server entry point
│   ├── vault/
│   │   ├── VaultManager.ts   # Core vault operations
│   │   └── frontmatter.ts    # YAML parsing utilities
│   ├── tools/
│   │   ├── definitions.ts    # MCP tool schemas
│   │   ├── handlers.ts       # Tool execution logic
│   │   └── index.ts          # Tool exports
│   ├── server/
│   │   ├── mcp.ts            # MCP protocol handlers
│   │   └── middleware.ts     # Express middleware
│   ├── index/                # Optional semantic search
│   │   ├── config.ts         # DATABASE_URL / OLLAMA_URL / EMBED_MODEL
│   │   ├── exclusions.ts     # What the indexer never reads
│   │   ├── chunker.ts        # Heading-aware chunking
│   │   ├── embedder.ts       # Ollama client (+ a fake for tests)
│   │   ├── ranking.ts        # Fusion, weights, per-note cap and env validation
│   │   ├── store.ts          # pgvector schema, upserts, hybrid search
│   │   ├── scanner.ts        # Vault walk and change detection
│   │   └── SearchService.ts  # What the MCP tools call
│   ├── maintain/             # Report configuration, decisions, renderer and worker
│   ├── maintain.ts           # Report-only maintenance CLI
│   ├── learn/                # Learn log, redaction, configuration and reports
│   ├── learn-report.ts       # Read-only learn-report CLI
│   ├── eval/                 # Golden validation, metrics and fixed ranking grid
│   ├── eval.ts               # Read-only brain-eval CLI entry point
│   ├── indexer.ts            # Indexer entry point (second container)
│   └── types/
│       └── index.ts          # TypeScript type definitions
├── sql/001_schema.sql        # Index schema (dimension substituted at start)
├── tests/                    # Vitest unit tests
├── Dockerfile
├── docker-compose.yml
├── package.json
└── README.md

环境变量

变量默认值描述
PORT3000服务端口
VAULT_PATH/vaultObsidian 知识库的路径
COMPACT_RESPONSESfalse启用精简响应键,令响应缩小 40%–60%
API_KEY(none)用于身份验证的 API 密钥。设置后,必须提供 Bearer 令牌(以恒定时间进行比较)
REQUIRE_TAILSCALE_LOGIN(none)可选。要求 Tailscale-User-Login 标头(由 tailscale serve 设置)与此登录名相同。只有在服务只能通过回环地址上的 tailscale serve 访问时,此设置才可信
SSE_KEEPALIVE_SECONDS30GET /sse 流中 : ping SSE 注释的发送间隔秒数;0 表示禁用。有些客户端会在约五分钟没有收到任何字节后丢弃流并重新连接,且不会再次发送 initialize,导致会话丢失客户端名称
MCP_INSTRUCTIONS_FILE(none)可选。文本或 Markdown 文件的路径;该文件会作为 MCP instructions 随 initialize 结果发送给客户端,用于说明此知识库的内容及适用场景。多数客户端会将其加入模型上下文。文件不存在会导致启动错误。请保持内容简短(有些客户端会在约 2 KB 处截断)
MCP_INSTRUCTIONS(none)相同内容,内联提供。若设置了 MCP_INSTRUCTIONS_FILE,则忽略此项
DATABASE_URL(none)Postgres + pgvector 连接字符串。启用语义搜索;未设置时,功能关闭
OLLAMA_URLhttp://localhost:11434用于生成嵌入的 Ollama 服务
EMBED_MODELnomic-embed-textOllama 嵌入模型;维度将从模型中自动获取
LEARN_LOGfalse启用可选的学习日志;配置无效时会禁用日志记录
LEARN_REDACT_PATTERNS_FILEunset启用日志记录时必需的、可读取的正则表达式文件
LEARN_RETENTION_DAYS30清除查询文本、嵌入和反馈备注前保留的天数;整数范围为 1–3650
INDEX_COLLECTIONdefault此知识库在共享数据库中的集合名称
MAINTAIN_REPORT_DIRdry 模式除外,必需用于维护报告的现有可写目录
MAINTAIN_REPORT_VAULT_DIRempty知识库内的报告目录,用于生成记录中的报告路径
MAINTAIN_TZUTC用于报告时间戳和 ISO 周数的 IANA 时区
MAINTAIN_LINK_COSINE0.85缺失链接的余弦阈值,必须严格介于 0 和 1 之间
MAINTAIN_DUP_COSINE0.92近似重复项的余弦阈值,必须严格介于 0 和 1 之间
MAINTAIN_DUP_TITLE_SIM0.6近似重复项的标题相似度,必须严格介于 0 和 1 之间
MAINTAIN_HUB_DAYS14用于判定过时中心笔记的关联笔记更新间隔;整数范围为 1–365
MAINTAIN_SUMMARY_DROP0.05摘要与正文的余弦相似度下降阈值,必须严格介于 0 和 1 之间
MAINTAIN_MAX_PER_CLASS10每次运行中每类新增发现的最大数量;整数范围为 1–100
SEARCH_FUSIONrrf融合方式:rrf(加权倒数排名)或 dbsf(基于分布的分数融合)
SEARCH_RRF_K60RRF 排名常数,整数范围为 1–1000;在 DBSF 模式下会验证此值,但不会使用
SEARCH_W_VECTOR1向量分支权重,有限数值,范围为 0–10
SEARCH_W_TEXT1全文搜索分支权重,有限数值,范围为 0–10;两项权重不能同时为零
SEARCH_PER_NOTE_CAP0每篇笔记的最大分块数,整数范围为 0–8;0 表示不设上限
INDEX_INTERVAL_SECONDS60仅用于索引器:知识库扫描间隔秒数
INDEX_VERBOSEfalse仅用于索引器:记录每个已索引或已移除文件的日志
EMBED_BATCH_SIZE16每次 Ollama 请求处理的文本数量
EMBED_PROVIDERollamaollama 或 fake(用于测试和冒烟运行的确定性哈希嵌入;不可用于实际搜索)
EMBED_DIM(auto)fake 提供程序的嵌入维度(默认值为 64);使用 Ollama 时会忽略此项,因为维度会从模型中自动获取

学习日志

可选的度量层需要语义搜索,默认关闭。它会记录三种搜索工具(semantic-search、similar-notes、search-vault)、成功的读取操作(read-note、read-multiple-notes、read-section)、明确反馈,以及包含客户端名称的会话开始和关闭事件。会话包括旧版 SSE 流(GET /sse + /message),以及自 1.10.1 起的 POST /sse 客户端:initialize 会返回一个 Mcp-Session-Id 标头,后续请求回传该标头时会记录在对应会话下,带该标头的 DELETE /sse 会关闭会话。不带该标头的 POST /sse 请求会以客户端名称 post 记录,且不关联会话。搜索排序不变;搜索绝不会读取这些日志。

设置 LEARN_LOG=true,并将 LEARN_REDACT_PATTERNS_FILE 指向可读取的 UTF-8 文件。空行和注释会被忽略,其余各行会去除首尾空白,并作为 JavaScript 正则表达式源代码进行编译,匹配时不区分大小写。示例文件如下:

# comment
\bexample-term\b

八种内置模式还会检测私钥标头、访问密钥格式、JWT、托管式 Git 令牌、密钥赋值、Bearer 凭据、URL 令牌参数和 64 位十六进制字符串。敏感查询(包括相似笔记路径)及其嵌入向量会在存储前清除。敏感字符串参数会替换为 [redacted];敏感反馈备注会清除,敏感反馈路径会丢弃,敏感读取路径绝不会记录。针对特定站点的模式应放在外部文件中。配置无效时会禁用日志记录,但不会禁用搜索,并会在启动时报告。

已记录的搜索会返回附加的 requestId。将其传递给读取操作的可选 requestId 参数,然后调用 search-feedback,并提供 requestId、rating(positive、negative、neutral)和 usedPaths。expectedPaths 和简短的 note 均为可选项。source 默认为 agent;只有在收到明确的人工反馈时才使用 user。未知 ID 会返回 { recorded: false, reason: 'unknown requestId' }。带有未知 ID 的读取操作会被记录,但不会关联搜索。

搜索、读取和会话写入均采用即发即弃方式:不会延迟工具响应,失败会以 learn-log: 记录。反馈操作会等待完成。索引器循环至多每天应用一次保留策略,--once 除外。超过 LEARN_RETENTION_DAYS(默认值为 30)后,查询文本、查询嵌入向量和反馈备注会被清除。路径、排名、时间戳、已检查的参数、客户端名称和反馈路径会保留。即使日志记录处于关闭状态,sql/002_learning.sql 也会创建四张 learn 表;维度重置后会重新创建嵌入向量列。如果需要保留查询数据,请勿将 learn 表数据纳入数据库转储,并在备份中排除原始数据库文件。

针对现有数据库运行只读报告:

node dist/learn-report.js --days 30 --out /existing-directory/learn-report.json

--days 默认为 30(范围为 1–365);输出目录必须已存在。报告使用只读连接,不受排序和日志记录环境设置影响,并输出计数和比率,不包含查询文本。标准输出会按报告顺序列出点分隔的键,最后显示 VOLUME GATE: pass|fail。 报告涵盖所选集合和时间范围。会话包括按客户端统计的数量,以及以分钟为单位的已关闭时长中位数。搜索包括按工具统计的数量和已脱敏内容占比。关联的语义读取采用读取路径中的最低排名:usedAt1、usedAt3、usedAt8 分别表示关联读取的占比,missRate 表示未出现在结果中的占比。linkedSearchRate 表示有相关读取的语义搜索占比,linkedSemanticPerDay 表示其每日数量。改写率和回退率统计会话关联的语义搜索后 120 秒内又进行语义搜索或文本搜索的情况。反馈覆盖率表示收到反馈的语义搜索占比;反馈来源数量和负面反馈率涵盖所有反馈。分母为零时的比率和空中位数均为 null;数字四舍五入到小数点后四位。每日关联语义搜索数量四舍五入后达到 30,即通过量级门槛。来自 Agent 的反馈用于衡量遵循情况;用户更正则提供独立标签。

语义搜索

默认关闭。设置 DATABASE_URL 后,服务器(增加四个工具)和索引器(作为第二个进程运行,以保持索引最新)都会启用语义搜索。所有组件均在本地运行:启用了 pgvector 扩展的 Postgres,以及用于生成嵌入的 Ollama。

工作原理
  • 知识库仍是真实数据的唯一来源。 索引是派生数据,可以删除后重建(--reindex)。
  • 分块会识别标题层级。 笔记按 H1–H3 标题拆分;超过约 800 个 token 的章节会进一步拆分,并保留重叠部分;每个块都带有其面包屑路径(Title › H2 › H3)。第 0 块包含标题和 frontmatter 中的 summary,因此,一行摘要是判断“哪篇笔记能回答这个问题”的最强信号。
  • 检索采用混合方式。 基于 HNSW 索引的余弦相似度检索与 Postgres 全文搜索并行运行,再通过可配置的加权倒数排名融合(默认方式)或基于分布的分数融合(DBSF)进行合并,因此改写表达和精确标识符(主机名、工单编号)都能奏效。
  • 变更检测采用轮询,而非文件监视器,因为 inotify 不会通过 NFS 或 SMB 传播。索引器每个间隔都会对每个文件执行 stat,仅对修改时间或大小发生变化的文件计算哈希,并且只对内容发生变化的文件重新生成嵌入。
  • 排除规则会在读取前按路径强制执行: .obsidian/、.trash/、.git/、Synology 的 #recycle/ @eaDir/ @tmp/、AppleDouble 文件 ._*、点文件、非 .md 文件、包含 .noindex 文件的任何目录,以及 frontmatter 中设置 index: false 的任何笔记。
  • 链接解析方式与 Obsidian 一致。 [[Areas/note]] 按路径解析;如果知识库中恰好只有一篇笔记具有该基本名称,则 [[note]] 可解析;如果有两篇,则保持未解析状态(会记录,目标为 NULL)。删除两篇重名笔记中的一篇后,另一篇会在下次编入索引时重新解析。
  • 模型是架构事实的一部分。 首次运行时,嵌入模型及其维度会记录在数据库中;若使用不同模型,则在执行 --reindex 之前不会编入索引。
评估搜索质量(brain-eval)

使用 npm run build 构建,然后使用与索引相同的数据库、集合和嵌入配置运行:

node dist/eval.js --golden /private/golden.json --grid --out /private/runs/grid.json
# Or evaluate one configuration alongside the baseline:
node dist/eval.js --golden /private/golden.json --config '{"wText":1.5,"perNoteCap":2}' --out /private/runs/candidate.json
# npm run eval -- <the same arguments> also works.

输出目录必须已存在。CLI 以只读模式打开数据库:不会应用架构变更、重新索引或写入索引。嵌入模型和维度必须与存储的元数据匹配,并且所有预期笔记都必须已存在于集合中。每个查询只嵌入一次,其向量会在各项配置间复用。固定网格包含 40 项配置,基线为 v1.8.0 的 rrf-k60-v1-t1-cap0。CLI 会忽略环境中已有的 SEARCH_* 排名设置;--config 仅将提供的字段合并到基线上。无效的排名环境设置会导致服务启动失败。

黄金文件是私有评估数据,且必须恰好包含以下键:

{
  "version": 1,
  "created": "2026-01-01",
  "notes": "Synthetic example only",
  "queries": [
    {
      "id": "example-1",
      "category": "exact-id",
      "query": "synthetic search phrase",
      "expected": ["Example.md"]
    }
  ]
}

查询 ID 必须唯一,查询字符串不得为空,预期列表不得为空且其中的 .md 路径必须唯一。类别依次为 exact-id、paraphrase、decision-why、multi-hop 和 recent,并按此顺序报告。未知键会被拒绝。请将黄金数据集和评估报告保存在公共代码仓库之外。

指标按结果顺序统计不同的笔记路径,且最多请求八个片段:

  • mrr:第一个预期笔记排名的倒数均值;未命中时为零。
  • recall5:前 5 项命中率,表示前五个笔记中是否存在任意一个预期笔记。
  • ndcg8:前八个笔记的二元相关性归一化折损累计增益。
  • distinctNotes:返回的不同笔记数量的均值。指标也会按类别细分,JSON 报告会将其四舍五入到小数点后四位。

候选项必须将 MRR 至少提高 0.0300,保持每个类别的命中率不变,并保留基线命中数在前五位以内的每个查询。比较时会将指标四舍五入为万分之一的整数。通过门槛的候选项按 MRR、命中率、NDCG 从高到低排序;平局时优先选择变更的排名字段较少者,其次选择 ID 按字典序较小者。若没有候选项通过,则采用基线,且 changed: false。JSON 包含黄金文件的 SHA-256、每个查询的笔记列表、门槛原因以及获胜配置的环境变量;标准输出会打印排名表、类别对比和最终的 WINNER 行。

退出代码:0 表示报告已完成(包括排名未变);2 表示输入问题(参数、黄金文件验证、模型不匹配或缺少预期路径);1 表示其他运行时故障(数据库、嵌入服务或输出写入)。

搜索要求使用 pgvector 0.8.0 或更高版本:每个事务都会使用严格顺序的迭代式 HNSW 扫描,经过筛选的搜索会将 hnsw.ef_search 提高到 100。默认 RRF 分数与 v1.8.0 相同;完全相同的分数按片段位置、再按 ID 排序。DBSF 分数范围从零到两路权重之和。

索引可识别的 Frontmatter
---
title: ubuntubox — NFS mount gate     # else first H1, else file name
type: area                            # filterable: semantic-search { type }
status: active                        # filterable: semantic-search { status }
tags: [infra, nas]                    # filterable: semantic-search { tags }
summary: One line that answers "what is this note about".
index: true                           # false = never indexed
---

无效的 Frontmatter 会被报告,而不会被隐藏。 若笔记的 --- 区块不是有效的 YAML(常见原因是未加引号的值中含有 : ,例如 summary: Finished it: all done;应加引号:summary: "Finished it: all done"),该笔记仍会根据正文建立索引,但不会包含其元数据。索引器在索引此类笔记时以及每次启动时都会记录 WARN invalid frontmatter in <path>: <YAML error>;每次处理的日志行都会包含 invalid_frontmatter=<count>,而 index-status 会返回 invalidFrontmatter: { count, notes: [{ path, error }] }(最多 20 条)。reindex-note 会返回一个 warning。修复笔记后,该标记会在下一次处理时清除。

设置
  1. 数据库:任何支持 pgvector 的 Postgres 16+。首次启动时会根据 sql/001_schema.sql 创建架构;无需手动执行任何操作。构建 HNSW 索引需要共享内存:为 Postgres 容器设置 shm_size: 1g。
  2. 嵌入:运行 ollama pull nomic-embed-text(768 维,8k 上下文)或 bge-m3(1024 维)。
  3. 服务:在服务的环境中添加 DATABASE_URL、OLLAMA_URL、EMBED_MODEL(以及可选的 INDEX_COLLECTION)。/health 端点会报告 semanticSearch: enabled。
  4. 索引器:使用相同镜像再次运行,并设置 command: ["node", "dist/indexer.js"]、相同的环境变量,以及以只读方式挂载的库。node dist/indexer.js --once --verbose 会执行单次遍历后退出;如果有任何文件处理失败,则以非零状态码退出。
services:
  obsidian-mcp:
    image: ghcr.io/smith-and-web/obsidian-mcp-server:latest
    environment:
      VAULT_PATH: /vault
      API_KEY: ${API_KEY}
      DATABASE_URL: postgres://brain:${DB_PASSWORD}@brain-db:5432/brain
      OLLAMA_URL: http://ollama:11434
      EMBED_MODEL: nomic-embed-text
      INDEX_COLLECTION: secondbrain
    volumes:
      - /path/to/vault:/vault:rw
    ports: ["127.0.0.1:3001:3000"]

  obsidian-indexer:
    image: ghcr.io/smith-and-web/obsidian-mcp-server:latest
    command: ["node", "dist/indexer.js"]
    environment:
      VAULT_PATH: /vault
      DATABASE_URL: postgres://brain:${DB_PASSWORD}@brain-db:5432/brain
      OLLAMA_URL: http://ollama:11434
      EMBED_MODEL: nomic-embed-text
      INDEX_COLLECTION: secondbrain
      INDEX_INTERVAL_SECONDS: "60"
    volumes:
      - /path/to/vault:/vault:ro

  brain-db:
    image: pgvector/pgvector:0.8.2-pg16
    shm_size: 1g
    environment:
      POSTGRES_DB: brain
      POSTGRES_USER: brain
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - ./brain-db:/var/lib/postgresql/data

  ollama:
    image: ollama/ollama:latest
    volumes:
      - ./ollama:/root/.ollama
索引器 CLI
命令作用
node dist/indexer.js持续运行,每隔 INDEX_INTERVAL_SECONDS 执行一次遍历;收到 SIGTERM 时正常停止
node dist/indexer.js --once执行一次遍历;如果有任何文件出错,则以状态码 1 退出
node dist/indexer.js --reindex删除此集合并重新构建(更改 EMBED_MODEL 后必须执行)
npx -p @smith-and-web/obsidian-mcp-server obsidian-mcp-indexer使用 npm 包运行相同的索引器(也接受 --once、--reindex、--verbose)
--verbose / INDEX_VERBOSE=true记录每个已索引或已移除的文件
安全说明
  • 索引器只需要对库的读取权限;请以 :ro 方式挂载。
  • 分块文本以明文形式存储在 Postgres 中。请像对待库一样保护数据库:使用相同的网络边界和备份策略,并且不要索引那些不应与库中其他内容共用访问密钥的材料(使用 index: false 或 .noindex 目录)。
  • 嵌入数据不会离开 Ollama 主机。此功能不涉及任何外部 API。

API 端点

端点方法描述
/healthGET健康检查
/sseGETMCP 的 SSE 端点
/ssePOST直接调用 MCP 协议
/messagePOSTSSE 传输消息

身份验证

服务支持可选的 API 密钥身份验证。设置 API_KEY 后,所有 /sse 和 /message 端点都需要身份验证。/health 端点仍可公开访问。

启用身份验证

设置 API_KEY 环境变量:

# Docker
docker run -d \
  --name obsidian-mcp \
  -v /path/to/vault:/vault:rw \
  -p 3001:3000 \
  -e VAULT_PATH=/vault \
  -e API_KEY=your-secret-key \
  ghcr.io/smith-and-web/obsidian-mcp-server:latest

# npx
API_KEY=your-secret-key VAULT_PATH=/path/to/vault npx @smith-and-web/obsidian-mcp-server
身份验证方式

客户端在 Authorization 标头中发送密钥:

Authorization: Bearer your-secret-key

?api_key= 查询参数已在 1.6.0 中移除(它会出现在访问日志和客户端历史记录中)。使用该参数的客户端必须改用标头,例如在 mcp-remote 中使用 --header "Authorization: Bearer your-secret-key"。

Tailscale 登录(可选的第二重验证)

在 loopback 上通过 tailscale serve 提供服务时,设置 [email protected]。之后,请求还需要包含 Tailscale-User-Login 标头;serve 会为 tailnet 用户添加此标头。其他请求都会收到 403。如果端口还能通过其他方式访问,请勿依赖此功能,因为直接连接的客户端可以伪造该标头。

使用 API 密钥配置客户端

Claude Desktop / Cursor(通过 mcp-remote):

{
  "mcpServers": {
    "obsidian": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "https://your-domain.com/sse",
        "--header", "Authorization: Bearer your-secret-key"
      ]
    }
  }
}

Claude Code:

claude mcp add --transport sse obsidian https://your-domain.com/sse --header "Authorization: Bearer your-secret-key"
安全注意事项
  • 生成强密钥:使用至少 32 个字符的随机字符串
  • 必须使用 HTTPS:远程公开服务时,始终使用 HTTPS,防止密钥被拦截
  • 文件访问:服务对挂载的保险库具有完整的读写权限,但所有路径都限制在保险库内(拒绝逃出保险库的路径,例如 ../../etc/passwd;已在 1.4.1 中修复)
  • 绑定地址:服务会监听所有网络接口。在 Docker 中,除非需要远程访问,否则请将端口发布到回环地址(127.0.0.1:3001:3000)
  • CORS:目前允许所有来源。如有需要,请在生产环境中进行限制
  • 日志中的密钥:仅通过 Authorization 请求头发送密钥;旧的 ?api_key= 查询参数已移除,因为 URL 最终会出现在访问日志中
  • 网络安全:对于敏感保险库,请考虑添加 VPN 或防火墙规则等额外防护层

使用 NGINX Proxy Manager 部署

如需通过 SSL 远程访问:

  1. 添加代理主机:

    • 域名:obsidian.yourdomain.com
    • 转发主机名:obsidian-mcp(容器名称)
    • 转发端口:3000
    • 无需启用 WebSocket(SSE 使用纯 HTTP);下方的 Advanced 配置才是关键
  2. SSL 选项卡:申请 Let's Encrypt 证书

  3. Advanced 选项卡(用于 SSE):

    proxy_buffering off;
    proxy_cache off;
    proxy_set_header Connection '';
    proxy_http_version 1.1;
    chunked_transfer_encoding off;
    

使用 Tailscale 进行私有访问

如果客户端位于 Tailscale tailnet 中,可以完全跳过公共反向代理。让容器继续绑定到回环地址,并使用 tailscale serve 通过仅限 tailnet 使用的 HTTPS 证书公开服务:

docker run -d --name obsidian-mcp -v /path/to/vault:/vault:rw -p 127.0.0.1:3001:3000 \
  -e API_KEY=your-secret-key -e [email protected] \
  ghcr.io/smith-and-web/obsidian-mcp-server:latest
sudo tailscale serve --bg --https=443 http://127.0.0.1:3001

然后,客户端使用 https://<machine>.<tailnet>.ts.net/sse,并在 Authorization: Bearer 请求头中提供密钥。切勿为此服务启用 Tailscale Funnel。有关 REQUIRE_TAILSCALE_LOGIN 的作用及其无法防护的内容,请参阅 Tailscale 登录。

故障排除

容器问题
# View logs
docker-compose logs -f obsidian-mcp

# Restart
docker-compose restart

# Rebuild
docker-compose up -d --build
保险库访问
# Check host mount
ls -la /path/to/your/vault

# Check container access
docker exec obsidian-mcp ls -la /vault
连接和身份验证错误
  • 401 Unauthorized:缺少或错误的 Authorization: Bearer <key> 请求头(不再接受 ?api_key= 查询参数)。
  • 403 Forbidden:已设置 REQUIRE_TAILSCALE_LOGIN,但请求并非以该用户身份通过 tailscale serve 到达。
  • Path escapes vault:请求的路径解析到 VAULT_PATH 之外;请使用相对于保险库的路径。
  • 搜索结果缺少笔记的 summary、标签或类型筛选结果:检查 index-status 中的 invalidFrontmatter(或索引器日志中的 WARN invalid frontmatter);笔记的 YAML 无效,因此索引时未包含其元数据。
  • SSE 连接在反向代理后中断:关闭代理缓冲(见上方的 NGINX 配置块),检查证书,并确认防火墙允许该端口。
  • Claude Desktop 已启动,但未显示任何工具:服务必须已在运行,且配置必须使用 mcp-remote(服务没有 stdio 模式)。

开发

快速开始
# Clone and install
git clone https://github.com/smith-and-web/obsidian-mcp-server.git
cd obsidian-mcp-server
make install

# Run with example vault
make dev

# Test connection
make test-connection
可用命令

运行 make help 查看所有可用命令:

Development:
  make install         Install dependencies
  make dev             Run server with hot-reload
  make start           Run server in production mode
  make test-connection Test server connectivity

Docker:
  make docker-build    Build Docker image
  make docker-up       Start Docker container
  make docker-down     Stop Docker container
  make docker-logs     View container logs
  make docker-restart  Restart container
  make docker-shell    Open shell in container
使用 Bruno 测试 API

仓库中包含用于测试核心工具的 Bruno 集合(四个语义搜索工具需要 DATABASE_URL 和正在运行的索引)。

  1. 安装 Bruno(免费、开源的 API 客户端)
  2. 从 ./bruno/obsidian-mcp 打开集合
  3. 选择 local 或 remote 环境
  4. 运行请求,测试各个工具

该集合按类别组织:

  • health/ - 服务健康状态和工具列表
  • notes/ - 笔记 CRUD 操作
  • directories/ - 目录操作
  • frontmatter/ - Frontmatter 操作
  • tags/ - 标签管理
  • search/ - 搜索和查找替换
  • links/ - 反向链接和失效链接
  • sections/ - 基于章节的操作
示例保险库

开发和测试用的示例保险库位于 ./examples/test-vault/。其中包含带有标签、链接和章节的示例笔记,可用于测试所有功能。

贡献

请参阅 CONTRIBUTING.md 了解相关指南。

许可证

MIT License——详见 LICENSE。

相关项目

维护工作进程

在与服务相同的镜像中运行 node dist/maintain.js(或 npm run maintain),并配置 DATABASE_URL、INDEX_COLLECTION、VAULT_PATH 和 MAINTAIN_REPORT_DIR。使用主机的调度程序每周运行一次。--dry 会输出候选项数量和维护指标,不会记录运行信息或写入报告。索引必须已存在。

七项确定性检查用于查找缺失链接、未链接的提及、可唯一修复的未解析链接、缺失的 index 或 aliases frontmatter、过时的摘要、近似重复项,以及过时的项目或领域枢纽。类型为 journal 或 inbox 的笔记不会作为目标。Journal/ 下的笔记不会收到任何方向的链接建议。未链接的提及仅统计笔记正文中的内容(不包括 frontmatter、第一个 H1、代码、wikilinks 或 markdown 链接),并且仅在其作为完整单词出现时才计入,不区分大小写,连字符视为单词的一部分;工作进程会从 VAULT_PATH 读取源笔记进行检查。近似重复项配对会跳过已互相链接的笔记,以及类型为 plan 的笔记配对。索引器会在内容变化时记录摘要/正文余弦历史,维护流程会为较早的笔记补建基线。搜索排名保持不变,维护流程绝不会读取学习表。

每个 ISO 周都会在配置的输出目录中生成 Brain maintenance YYYY-Www.md。报告是草稿笔记,包含 index: false、稳定的发现 ID、接受/拒绝复选框、趋势和接受计数。它们不会出现在搜索结果或链接图中。重新运行时会先解析勾选项,然后以原子方式仅替换该周的报告;移动后的报告仍会通过其 maintenance_report frontmatter 被发现。

对每条发现勾选一个复选框,或者明确要求助手调用 maintenance-decision,并提供 finding: "f17"、decision: "accept" 或 "reject",以及可选原因。若勾选项相互冲突,则不会记录决定。复选框不会覆盖先前的决定;显式工具调用可以更改决定。已拒绝的发现不会再次被提出。每类新增发现的数量设有上限,每份报告最多列出 50 条未处理的发现。

此阶段仅生成报告:接受一条发现只会记录决定,不会更改任何笔记。请自行应用已接受的发现。近似重复项合并和枢纽审查永久保持为仅生成报告。工作进程绝不会编辑现有笔记;它唯一写入知识库的内容是自己的报告。

recommend-notes 接受 1–10 条 positive 路径,最多 10 条 negative 路径,以及可选的整数 k(1–50)、type 和 directory。它会排除示例。best_score 会比较最近的正向项和负向项;average_vector 会使用正向项的均值,并在存在负向项时远离负向项的均值。两种工具都不要求记录学习数据;敏感的决定原因会依据当前启用的脱敏模式或内置规则存储为 null。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。