Obsidian Mcp Server について
Obsidian MCP Serverは、MCP接続を通じてAIアシスタントからノートやナレッジベースの構成を操作できるサーバーです。ノート編集、メタデータ、リンク機能に加え、Postgres、pgvector、Ollamaによるローカル意味検索を任意で利用できます。
主な機能
- 01ノートの作成、編集、移動、読み取り
- 02タグとYAML frontmatterの管理
- 03ノート検索とリンク確認
- 04セクションとディレクトリの編集
- 05任意で利用できるローカル意味検索
活用シーン
- 01AIアシスタントを通じたノート作成と整理
- 02テキスト、タグ、バックリンクによるノート検索
- 03タグと未解決のwikiリンクの監査
- 04ローカル埋め込みによる関連ノート検索
MCP 対応
HTTPとSSE経由でObsidianのナレッジベース操作をMCPツールとして提供し、stdioには直接対応しません。DATABASE_URLを設定すると、任意の意味検索ツールを利用できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
Obsidian MCP サーバー
Model Context Protocol (MCP) サーバーです。Claude などの AI アシスタントが Obsidian の保管庫とやり取りできるようにします。自然な会話を通じて、ノートへのアクセス、コンテンツの作成、タグの管理、ナレッジベースの検索ができます。
機能
ノート管理
- CRUD 操作:ノートの作成、読み取り、更新、削除(安全確認付き)
- 書き込みモード:コンテンツの上書き、追記、先頭への追加
- 一括読み取り:1 回のリクエストで複数のノートを読み取り
- ファイル情報:コンテンツを読み取らずにメタデータを取得(大規模な保管庫で効率的)
- 移動/複製:保管庫の構成を再編成
- セクション操作:見出しを指定して、特定のセクションを読み取り、追記、置換
フロントマターとタグ
- フロントマターの解析:YAML フロントマターを構造化 JSON として取得/設定(gray-matter を使用)
- タグ管理:タグを追加/削除(フロントマターまたはインライン)
- タグ監査:必須タグがないノートを検出
- タグ検索:使用回数とともにすべてのタグを一覧表示
検索とリンク
- 全文検索:コンテキストとともにコンテンツやファイル名を検索
- バックリンク:特定のノートにリンクしているノートをすべて検索
- リンク切れ:解決できない Wiki リンクを検出
- 検索と置換:正規表現に対応した一括テキスト置換
セマンティック検索(任意)
- 意味による検索:Postgres と pgvector、および Ollama のローカル埋め込みを利用した、見出しを考慮したチャンクに対するベクトル検索と全文検索のハイブリッド検索
- 類似ノート:ノート全体の埋め込みに基づき、指定したノートに近いノートを検索
- 増分インデクサー:同じイメージから起動する 2 つ目のプロセスが保管庫をポーリングし、変更されたものだけを再埋め込みします。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 を使用する場合:
-
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 -
サーバーを起動します
docker compose up -d -
実行中であることを確認します
curl http://localhost:3001/health
ローカル開発
-
依存関係をインストールします
npm install -
環境変数を設定します
export VAULT_PATH=/path/to/your/vault export PORT=3000 -
サーバーを起動します
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 エンドポイントをブリッジします。このサーバーは stdio を使用しないため、Claude Desktop から直接起動することはできません。
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 サーバーをネイティブにサポートしている場合は、http://localhost:3001/sse の 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 | ディレクトリを名前変更/移動します |
フロントマターとタグ
| ツール | 説明 |
|---|---|
get-frontmatter | YAML フロントマターを JSON として取得します |
update-frontmatter | フロントマターのフィールドをその場で更新します(変更されていないフィールドのテキストは完全に保持されます。無効な YAML は拒否されます) |
add-tags | フロントマターまたは本文内にタグを追加します |
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、フロントマターの type と status で絞り込みます。`mode: hybrid |
similar-notes | 重心埋め込みに基づき、あるノートに最も近いノートを検索します |
index-status | モデル、件数、インデクサーの最終実行時刻、遅延を表示します |
reindex-note | 1つのノートをすぐに再インデックスします |
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
環境変数
| 変数 | デフォルト | 説明 |
|---|---|---|
PORT | 3000 | サーバーのポート |
VAULT_PATH | /vault | Obsidian ボルトへのパス |
COMPACT_RESPONSES | false | 応答キーを短縮して、応答サイズを40~60%削減します |
API_KEY | (none) | 認証用の API キーです。設定すると、Bearer トークンが必要になります(定数時間で比較されます) |
REQUIRE_TAILSCALE_LOGIN | (none) | オプションです。Tailscale-User-Login ヘッダー(tailscale serve によって設定されます)がこのログイン名と一致することを要求します。サーバーに tailscale serve 経由でループバック上からのみアクセスできる場合に限り、信頼できます |
SSE_KEEPALIVE_SECONDS | 30 | GET /sse ストリームで : ping SSE コメントを送信する間隔(秒)です。0 にすると無効になります。約5分間バイトを受信しなかったストリームを切断し、initialize を再送せずに再接続するクライアントがあります。その場合、セッションのクライアント名が失われます |
MCP_INSTRUCTIONS_FILE | (none) | オプションです。MCP の initialize 結果に含める instructions として、ボルトの内容と使用するタイミングをクライアントに送るテキスト/Markdown ファイルのパスです。ほとんどのクライアントはモデルのコンテキストに追加します。ファイルが存在しない場合、起動エラーになります。短くしてください(クライアントによっては約2 KBで切り詰められます) |
MCP_INSTRUCTIONS | (none) | 同じ内容をインラインで指定します。MCP_INSTRUCTIONS_FILE が設定されている場合は無視されます |
DATABASE_URL | (none) | Postgres + pgvector の接続文字列です。セマンティック検索を有効にします。未設定の場合、この機能は無効です |
OLLAMA_URL | http://localhost:11434 | 埋め込み生成に使用する Ollama サーバー |
EMBED_MODEL | nomic-embed-text | Ollama の埋め込みモデルです。次元数はモデルから検出されます |
LEARN_LOG | false | オプションの学習ログを有効にします。設定が無効な場合、ログ記録は無効になります |
LEARN_REDACT_PATTERNS_FILE | unset | ログ記録が有効な場合に必要な、読み取り可能な正規表現ファイル |
LEARN_RETENTION_DAYS | 30 | クエリテキスト、埋め込み、フィードバックメモを消去するまでの日数です。整数1~3650 |
INDEX_COLLECTION | default | 共有データベース内の、このボルトのコレクション名 |
MAINTAIN_REPORT_DIR | dry 実行でない場合は必須 | メンテナンスレポート用の、既存の書き込み可能なディレクトリ |
MAINTAIN_REPORT_VAULT_DIR | empty | ボルトからの相対パスで指定するレポートディレクトリです。記録されるレポートパスに使用されます |
MAINTAIN_TZ | UTC | レポートのタイムスタンプと ISO 週に使用する IANA タイムゾーン |
MAINTAIN_LINK_COSINE | 0.85 | リンク欠落のコサイン類似度しきい値です。0より大きく1未満 |
MAINTAIN_DUP_COSINE | 0.92 | 近似重複のコサイン類似度しきい値です。0より大きく1未満 |
MAINTAIN_DUP_TITLE_SIM | 0.6 | 近似重複タイトルの類似度です。0より大きく1未満 |
MAINTAIN_HUB_DAYS | 14 | 古いハブを判定する、リンク先ノートの更新間隔です。整数1~365 |
MAINTAIN_SUMMARY_DROP | 0.05 | 要約と本文のコサイン類似度の低下しきい値です。0より大きく1未満 |
MAINTAIN_MAX_PER_CLASS | 10 | 実行ごとにクラスごとに新たに検出する項目の最大数です。整数1~100 |
SEARCH_FUSION | rrf | 融合方式です。rrf(重み付き逆順位)または dbsf(分布ベースのスコア融合) |
SEARCH_RRF_K | 60 | RRF の順位定数です。整数1~1000。DBSF では検証されますが使用されません |
SEARCH_W_VECTOR | 1 | ベクトル検索の重みです。有効な数値で、0~10 |
SEARCH_W_TEXT | 1 | 全文検索の重みです。有効な数値で、0~10。両方の重みを0にはできません |
SEARCH_PER_NOTE_CAP | 0 | ノートあたりのチャンク数の上限です。整数0~8。0は上限なしを意味します |
INDEX_INTERVAL_SECONDS | 60 | インデクサーのみ:ボルトをスキャンする間隔(秒) |
INDEX_VERBOSE | false | インデクサーのみ:インデックス作成または削除されたすべてのファイルをログに記録します |
EMBED_BATCH_SIZE | 16 | Ollama リクエストあたりのテキスト数 |
EMBED_PROVIDER | ollama | ollama、または fake(テストやスモーク実行用の決定論的なハッシュ埋め込み。実際の検索には使用しません) |
EMBED_DIM | (auto) | fake プロバイダーの埋め込み次元数(デフォルトは64)。Ollama ではモデルから検出されるため無視されます |
学習ログ
オプションの計測レイヤーにはセマンティック検索が必要で、デフォルトでは無効です。3 つの検索ツール(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 と、読み取り可能な UTF-8 ファイルを指定した LEARN_REDACT_PATTERNS_FILE を設定します。空行とコメントは無視され、その他の各行は空白を削除したうえで、大文字と小文字を区別しない JavaScript の正規表現ソースとしてコンパイルされます。ファイルの例を以下に示します。
# comment
\bexample-term\b
組み込みの 8 つのパターンでも、秘密鍵ヘッダー、アクセスキー形式、JWT、ホスト型 Git トークン、シークレットの代入、ベアラー認証情報、URL のトークンパラメーター、64 文字の 16 進文字列を検出します。機密性の高いクエリ(類似ノートのパスを含む)とその埋め込み表現は、保存前に消去されます。機密性の高い文字列パラメーターは [redacted] に置き換えられます。機密性の高いフィードバックのメモは消去され、機密性の高いフィードバックのパスは破棄され、機密性の高い読み取りパスは記録されません。サイト固有のパターンは外部ファイルに記述します。設定が無効な場合、検索ではなくログ記録が無効になり、起動時にその旨が報告されます。
記録された検索は、追加で requestId を返します。この値を読み取りの省略可能な requestId 引数に渡し、その後 requestId、rating(positive、negative、neutral)、usedPaths を指定して search-feedback を呼び出します。expectedPaths と短い note は省略可能です。source のデフォルト値は agent です。user は、人間による明示的なフィードバックの場合にのみ使用します。不明な ID を指定すると、{ recorded: false, reason: 'unknown requestId' } が返されます。不明な ID を指定した読み取りは、関連付けなしで記録されます。
検索、読み取り、セッションの書き込みはすべてファイア・アンド・フォーゲットで実行されます。ツールの応答が遅れることはなく、失敗は learn-log: とともにログに記録されます。フィードバックは完了を待ちます。インデクサーのループは --once を除き、1 日に最大 1 回、データ保持処理を適用します。LEARN_RETENTION_DAYS(デフォルトは 30 日)の経過後、クエリテキスト、クエリの埋め込み表現、フィードバックのメモが消去されます。パス、順位、タイムスタンプ、確認済みパラメーター、クライアント名、フィードバックのパスは保持されます。ログ記録が無効な場合でも、sql/002_learning.sql は 4 つの学習テーブルを作成します。次元をリセットすると、埋め込み列が再作成されます。クエリの保持期間を適用する必要がある場合は、学習テーブルのデータをデータベースダンプに含めず、生のデータベースファイルをバックアップから除外してください。
既存のデータベースに対して、読み取り専用レポートを実行します。
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はその1日あたりの件数です。再検索率とフォールバック率は、セッションに関連付けられたセマンティック検索の後、120秒以内に別のセマンティック検索またはテキスト検索が行われた割合です。フィードバックカバレッジは、フィードバックがあるセマンティック検索の割合です。ソース別件数と否定率には、すべてのフィードバックが含まれます。分母がゼロの場合の割合と、値がない場合の中央値はnullです。数値は小数点以下4桁に丸められます。ボリュームゲートは、リンクされたセマンティック検索が1日あたり30件(丸め後)に達すると通過します。エージェントからのフィードバックは準拠状況を測定し、ユーザーによる修正は独立したラベルを提供します。
セマンティック検索
デフォルトでは無効です。DATABASE_URLを設定すると、サーバー(ツールが4つ追加されます)とインデクサー(インデックスを最新の状態に保つ別プロセス)の両方で有効になります。すべてローカルで動作します。Postgres(pgvector拡張機能を使用)と、埋め込み生成用のOllamaを使用します。
仕組み
- Vaultが常に信頼できる唯一の情報源です。 インデックスは派生データであり、削除して再構築できます(
--reindex)。 - チャンク分割では見出しを考慮します。 ノートはH1~H3で分割されます。約800トークンを超えるセクションは、オーバーラップを設けてさらに分割されます。各チャンクには階層を示すパンくずリスト(
Title › H2 › H3)が付きます。チャンク0はタイトルとフロントマターのsummaryで構成されるため、どのノートが質問に答えるかを判断するうえで、1行の要約が最も強い手がかりになります。 - 検索にはハイブリッド方式を使用します。 HNSWインデックスによるコサイン類似度とPostgresの全文検索を並行して実行し、設定可能な加重逆順位融合(デフォルト)または分布ベースのスコア融合(DBSF)で統合します。そのため、言い換え表現と正確な識別子(ホスト名、チケット番号)のどちらにも対応できます。
- 変更検出は監視ではなくポーリング方式です。 inotifyはNFSやSMBを介して伝播しないためです。インデクサーは各間隔で全ファイルの情報を取得し、mtimeまたはサイズが変わったファイルだけをハッシュ化し、内容が変わったファイルだけを再度埋め込みます。
- 除外は、読み取り前にパスによって適用されます。
.obsidian/、.trash/、.git/、Synologyの#recycle/、@eaDir/、@tmp/、AppleDoubleの._*、ドットファイル、.md以外のファイル、.noindexファイルを含むディレクトリ、およびフロントマターにindex: falseが指定されたノートが対象です。 - リンクはObsidianと同じ方法で解決されます。
[[Areas/note]]はパスで解決されます。[[note]]は、Vault内に同じベース名のノートが1つだけある場合に解決されます。2つある場合は未解決のまま記録され、ターゲットはNULLになります。重複する2つのうち1つを削除すると、次回のインデックス作成時にもう1つが再解決されます。 - モデルはスキーマ上の事実として記録されます。 初回実行時に埋め込みモデルと次元数がデータベースに記録されます。異なるモデルでは、
--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 の順に報告されます。不明なキーは拒否されます。ゴールデンセットと評価レポートは、公開コードリポジトリの外に保管してください。
メトリクスでは、8個のチャンクをリクエストした後、結果の順序に沿って一意のノートパスを使用します。
mrr:最初の期待ノートの逆順位の平均値。該当しない場合は0です。recall5:5位以内のヒット率で、上位5件のノートのいずれかに期待ノートが含まれているかを示します。ndcg8:8件のノートに対する二値関連性の正規化割引累積利得です。distinctNotes:返された一意のノート数の平均値です。メトリクスはカテゴリ別にも集計され、JSON レポートでは小数点以下4桁に丸められます。
候補は MRR を少なくとも0.0300改善し、すべてのカテゴリのヒット率を維持し、ベースラインでヒットが5位以内だったすべてのクエリのヒットを維持する必要があります。比較ではメトリクスを1万分の1の整数に丸めます。合格した候補は、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 スコアの範囲は0から、2つの検索経路の重みの合計までです。
インデックスが認識するフロントマター
---
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
---
無効なフロントマターは隠されず、報告されます。 --- ブロックが有効な 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 を返します。ノートを修正すると、次のパスでフラグが解除されます。
セットアップ
- データベース:pgvector を備えた任意の Postgres 16 以降を使用します。スキーマは初回起動時に
sql/001_schema.sqlから作成されるため、手動で実行する必要はありません。HNSW インデックスの構築には共有メモリが必要です。Postgres コンテナーにshm_size: 1gを指定してください。 - 埋め込み:
ollama pull nomic-embed-text(768 次元、8k コンテキスト)またはbge-m3(1024 次元)を実行します。 - サーバー:サーバーの環境変数に
DATABASE_URL、OLLAMA_URL、EMBED_MODEL(任意でINDEX_COLLECTIONも)を追加します。/healthエンドポイントでsemanticSearch: enabledが報告されます。 - インデクサー:同じイメージを
command: ["node", "dist/indexer.js"]で再度実行し、同じ環境変数を設定して、ボルトを読み取り専用でマウントします。node dist/indexer.js --once --verboseを実行すると、1 回だけ処理して終了します。ファイルの処理に失敗した場合は、0 以外の終了コードを返します。
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 ごとに 1 回処理します。SIGTERM で正常に停止します |
node dist/indexer.js --once | 1 回だけ処理します。ファイルの処理でエラーがあった場合は終了コード 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 エンドポイント
| エンドポイント | メソッド | 説明 |
|---|---|---|
/health | GET | ヘルスチェック |
/sse | GET | MCP 用 SSE エンドポイント |
/sse | POST | MCP プロトコルの直接呼び出し |
/message | POST | SSE トランスポートメッセージ |
認証
サーバーでは、オプションの 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 ログイン(オプションの第 2 要素)
ループバックで tailscale serve の背後に配置する場合は、[email protected] を設定します。その場合、リクエストには、tailnet ユーザー用に serve が追加する Tailscale-User-Login ヘッダーも必要です。それ以外はすべて 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ヘッダーでのみ送信してください。URL はアクセスログに記録されるため、以前の?api_key=クエリパラメーターは削除されました - ネットワークセキュリティ:機密性の高い保管庫では、VPN やファイアウォールルールなどの追加の保護層を検討してください
NGINX Proxy Manager を使ったデプロイ
SSL を使用してリモートアクセスする場合:
-
Proxy Host を追加します:
- ドメイン:
obsidian.yourdomain.com - 転送先ホスト名:
obsidian-mcp(コンテナ名) - 転送先ポート:
3000 - WebSocket は不要です(SSE は通常の HTTP です)。重要なのは、以下の Advanced ブロックです
- ドメイン:
-
SSL タブ:Let's Encrypt 証明書をリクエストします
-
Advanced タブ(SSE 用):
proxy_buffering off; proxy_cache off; proxy_set_header Connection ''; proxy_http_version 1.1; chunked_transfer_encoding off;
Tailscale によるプライベートアクセス
クライアントが Tailscale のテイルネット上にある場合、パブリックリバースプロキシを完全に省略できます。コンテナはループバック上で動作させ、tailscale serve を使ってテイルネット専用の 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
クライアントは Authorization: Bearer ヘッダーを付けて https://<machine>.<tailnet>.ts.net/sse を使用します。このサーバーでは、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 コレクションが含まれています(4 つのセマンティック検索ツールには DATABASE_URL と、実行中のインデックスが必要です)。
- Bruno(無料のオープンソース API クライアント)をインストールします
./bruno/obsidian-mcpからコレクションを開きますlocalまたはremote環境を選択します- リクエストを実行して各ツールをテストします
コレクションはカテゴリ別に整理されています:
health/- サーバーの状態とツール一覧notes/- ノートの CRUD 操作directories/- ディレクトリ操作frontmatter/- フロントマター操作tags/- タグ管理search/- 検索と検索・置換links/- バックリンクとリンク切れsections/- セクション単位の操作
サンプル保管庫
開発とテスト用に、./examples/test-vault/ にサンプル保管庫が含まれています。すべての機能をテストできるよう、タグ、リンク、セクションを含むサンプルノートが用意されています。
コントリビューション
ガイドラインについては、CONTRIBUTING.md を参照してください。
ライセンス
MIT ライセンスです。詳細はLICENSEを参照してください。
関連プロジェクト
- Model Context Protocol - プロトコル仕様
- Obsidian - ナレッジベースアプリケーション
- Claude - Anthropic の AI アシスタント
メンテナンスワーカー
サーバーと同じイメージから node dist/maintain.js(または npm run maintain)を実行し、DATABASE_URL、INDEX_COLLECTION、VAULT_PATH、MAINTAIN_REPORT_DIR を設定してください。ホストのスケジューラーを使って週次で実行してください。--dry は、実行を記録したりレポートを書き込んだりせずに、候補数と健全性指標を出力します。インデックスはすでに存在している必要があります。
7 つの決定論的なチェックで、リンク切れ、リンクされていない言及、一意に修正可能な未解決リンク、欠落している index または aliases の frontmatter、古くなった要約、類似度の高い重複、古くなったプロジェクトまたはエリアのハブを検出します。type が journal または inbox のノートは、リンク先の候補から除外されます。Journal/ 配下のノートには、どちらの方向にもリンク候補を提案しません。リンクされていない言及として数えるのは、ノートの本文(frontmatter、最初の H1、コード、wikilink、Markdown リンクを除く)に含まれ、ハイフンを単語の一部として扱ったうえで、大文字と小文字を区別しない完全一致の単語だけです。確認のため、ワーカーは VAULT_PATH から元のノートを読み込みます。類似度の高い重複ペアのうち、すでに相互にリンクしているペアと、両方が plan ノートであるペアは除外されます。インデクサーは、コンテンツの変更時に要約と本文のコサイン類似度の履歴を記録し、メンテナンス処理では古いノートのベースラインを補完します。検索ランキングは変更されず、メンテナンス処理が学習テーブルを読み取ることもありません。
ISO 週ごとに、設定した出力ディレクトリに Brain maintenance YYYY-Www.md が作成されます。レポートは index: false、安定した検出項目 ID、承認/却下のチェックボックス、傾向、承認数を含むドラフトノートです。検索やリンクグラフには含まれません。再実行時は最初にチェックボックスを解析し、その週のレポートのみをアトミックに置き換えます。移動されたレポートも、maintenance_report frontmatter によって引き続き検出されます。
各検出項目のチェックボックスを 1 つ選択するか、finding: "f17"、decision: "accept" または "reject"、任意の理由を指定して maintenance-decision を呼び出すよう、アシスタントに明示的に依頼してください。チェックボックスの選択が矛盾している場合、決定は記録されません。チェックボックスによって以前の決定が上書きされることはありませんが、明示的なツール呼び出しでは変更できます。却下された検出項目が再提案されることはありません。修正済みの検出項目は、承認数に加算されずに解決済みとなります。クラスごとに新しい検出項目の数が制限され、レポートに記載される未解決の検出項目は最大 50 件です。
この段階ではレポートのみが生成されます。承認を記録しても決定が保存されるだけで、ノートは変更されません。承認された検出項目は自分で適用してください。類似度の高い重複の統合とハブのレビューは、今後もレポートのみを生成します。ワーカーが既存のノートを編集することはありません。Vault への書き込みは、ワーカー自身のレポートのみです。
recommend-notes は、1~10 個の positive パス、最大 10 個の negative パス、任意の整数 k(1~50)、type、directory を受け取ります。例として指定したノートは除外されます。best_score は最も近い positive と negative を比較し、average_vector は positive の平均を使用します。negative が存在する場合は、negative の平均から離れる方向に調整されます。どちらのツールにも学習ログは必要ありません。機密性の高い決定理由は、有効なリダクションパターンまたは組み込みのパターンに基づき、null として保存されます。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。