docsonar について
docsonarは、フォルダー内の文書をローカル検索するMCPサーバーです。ファイルを端末外へ送らずに検索したい人向けで、キーワード検索とセマンティック検索を組み合わせ、登録フォルダー内で読み取り専用アクセスを行います。
主な機能
- 01キーワード検索とセマンティック検索
- 02TXT、Markdown、PDF、DOCX、HTMLのインデックス作成
- 03該当箇所のファイル読み取り
- 04意味の近い文書の検索
- 05差分インデックスと状態確認
活用シーン
- 01話題や識別子でメモを検索
- 02PDF内の該当箇所をページ番号付きで特定
- 03ファイル変更後のインデックス更新
MCP 対応
フォルダー登録、インデックス作成、検索、ファイル読み取り、状態確認を行う8つのツールをMCPクライアントに公開します。stdioとHTTPに対応しています。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
docsonar
フォルダーとチャットできます。 ローカル文書検索用の MCP サーバーです。ファイルがマシンの外に出ることはありません。
docsonar は文書フォルダーを単一の SQLite データベースにインデックス化し、あらゆる MCP クライアント(Claude Desktop、Claude Code など)でキーワード検索とセマンティック検索を組み合わせて利用できるようにします。完全オフラインで、設定不要、設計上読み取り専用です。
クイックスタート
Claude Code
プロジェクトの .mcp.json(すべてのプロジェクトに適用する場合は ~/.claude.json)に追加します。
{
"mcpServers": {
"docsonar": {
"command": "uvx",
"args": ["docsonar"]
}
}
}
Claude Desktop
claude_desktop_config.json に追加します(設定 → 開発者 → 設定を編集)。
{
"mcpServers": {
"docsonar": {
"command": "uvx",
"args": ["docsonar"]
}
}
}
ソースコードをチェックアウトした場所から実行する場合は、代わりに "command": "uv", "args": ["run", "--directory", "/path/to/docsonar", "docsonar"] を指定します。
あとは、話しかけるだけです。 「~/Documents/notes フォルダーを追加して、四半期計画に関するものをすべて探して。」 最初のインデックス作成時に埋め込みモデルをダウンロードします(約 130 MB、初回のみ)。その間もキーワード検索はすぐに利用できます。
stdio の代わりに HTTP を使う場合:uvx docsonar --transport http --port 8365。
ツール
| ツール | 目的 |
|---|---|
add_folder(path, include_globs?, exclude_globs?) | フォルダーを登録します。インデックス作成はバックグラウンドで開始されます |
remove_folder(path) | 登録を解除し、インデックスデータを消去します |
list_folders() | 登録済みフォルダーと件数、最終インデックス作成時刻を表示します |
search(query, top_k?, folder?, file_type?, mode?) | キーワード検索とセマンティック検索を組み合わせた検索(RRF で統合)。ファイルパス、見出し/ページ位置、抜粋を含む、順位付けされた文章 |
read_file(path, start_line?, end_line?) | ファイルのテキスト(pdf/docx/html は抽出テキスト)を読み取ります。登録済みフォルダー外のパスは拒否します |
find_similar(path, top_k?) | 指定したファイルと意味的に最も類似した文書を検索します |
reindex(folder?, force?) | 差分更新します。新規/変更ファイルを再インデックス化し、削除済みファイルを消去します |
index_status() | インデックスの合計、埋め込みモデルの状態、バックグラウンドジョブの進行状況、失敗したファイルを表示します |
対応形式:txt、md、pdf(ページ対応、p. 12 のように引用)、docx、html。
アーキテクチャ
flowchart LR
Client["MCP client<br/>(Claude Desktop / Code)"] <-->|stdio or HTTP| Server["FastMCP server<br/>8 tools"]
Server --> Sec["path security<br/>(registered folders only)"]
Server --> Search["hybrid search<br/>BM25 + cosine KNN + RRF"]
Server --> Worker["background indexer<br/>(worker thread + queue)"]
Worker --> Parsers["parsers<br/>txt · md · pdf · docx · html"]
Parsers --> Chunker["heading/page-aware chunker<br/>~400 tokens, 60 overlap"]
Chunker --> DB[("SQLite<br/>FTS5 + sqlite-vec")]
Search --> DB
Embed["sentence-transformers<br/>bge-small-en-v1.5 (local)"] --> Worker
Embed --> Search
各チャンクには位置情報(Setup > Windows のような見出しパス、または PDF のページ範囲)が保存されるため、検索結果を report.pdf, p. 12 のように引用できます。
設計上の決定事項
- 設計上、読み取り専用です。 書き込み、移動、削除を行うツールはなく、今後も追加されることはありません。サーバーは、明示的に登録したフォルダー内のファイルのみを読み取ります。シンボリックリンクによる逸脱を防ぎ、パスを厳密に解決するため、問題のあるクライアントによる影響範囲はゼロです。
- 単一のストアとして SQLite を使用します。 FTS5 は標準ライブラリで本番環境品質の BM25 キーワード検索を実現し、sqlite-vec はベクトルを同じファイルに格納します。データベースファイルは 1 つだけで、実行するサービスはなく、バックアップや削除も簡単です。
- ハイブリッド検索をデフォルトで使用します。 BM25 とコサイン KNN のランキングを、逆順位融合(k=60)で統合します。正確な識別子や珍しい用語はキーワード検索側で優位になり、言い換えられた質問はセマンティック検索側で優位になります。RRF では両者のスコアを調整する必要はありません。呼び出し側は
modeでどちらかを指定できます。 - ローカルの埋め込みを使用します。 BAAI/bge-small-en-v1.5(384 次元)は、定番の all-MiniLM-L6-v2 と同じサイズ帯でありながら、検索ベンチマークではより高い性能を発揮します。初回のインデックス作成時にダウンロードされ、CPU で動作します。遅延読み込みにより、サーバーはすぐに起動します。モデルを読み込めない場合は、すべてがキーワード検索に円滑にフォールバックし、ツールの応答でその旨が通知されます。
- LLM の呼び出し側を想定して構築されたツール群です。
searchは、追加のラウンドトリップなしで次に読む内容を判断できるよう、各ヒットについて十分な情報(パス、位置、スコア、スニペット)を返します。結果には安定したchunk_idが付与されます。機能低下が発生した場合も、エラーにするのではなく、note/embedding_noteフィールドでその都度通知します。意図的に「質問に答える」ツールは用意していません。推論は呼び出し元のモデルが行い、docsonar は検索を担います。 - 更新日時だけでなく、内容に基づいて差分を処理します。 再インデックス時にはまず更新日時とサイズを確認し、その後 SHA-256 のコンテンツハッシュで判定します。変更日時だけが変わった同一内容のファイルはスキップされ、削除されたファイルは FTS インデックスとベクトルインデックスの両方から削除されます。
- スキャンされた PDF は明確に失敗として扱います。 抽出可能なテキストがない PDF は、空のファイルとして黙ってインデックスに追加するのではなく、明確な理由とともに失敗として報告されます。OCR は対象外です。
ベンチマーク
Markdown ファイル 200 個(600 チャンク)の合成コーパスを使用。Intel Core Ultra 5 125U(ノート PC、CPU のみ)、Windows 11、Python 3.12。uv run python scripts/benchmark.py で再現できます。
| 操作 | 結果 |
|---|---|
| インデックス作成、キーワードのみ | 0.7 s(約280ファイル/秒) |
| インデックス作成、埋め込みあり | 59 s(約3.4ファイル/秒 — 埋め込み処理がボトルネック) |
| 差分インデックス作成、変更なし | 0.03 s |
| キーワード検索 | 中央値 8.9 ms |
| セマンティック検索 | 中央値 35 ms |
| ハイブリッド検索 | 中央値 54 ms |
| 埋め込みモデルの読み込み(プロセスごとに1回) | 約21 s |
| データベースのサイズ | 2.6 MB(キーワードのみの場合は1.1 MB) |
設定
設定は不要です。カスタマイズするには、プラットフォームの設定ディレクトリに config.toml を作成してください(Windows:%LOCALAPPDATA%\docsonar\、macOS:~/Library/Application Support/docsonar/、Linux:~/.config/docsonar/)。
embedding_model = "BAAI/bge-small-en-v1.5" # any sentence-transformers model
chunk_target_tokens = 400
chunk_max_tokens = 512
chunk_min_tokens = 100
chunk_overlap_tokens = 60
max_file_size_mb = 50
extra_ignore_dirs = ["Archive"]
CLI フラグ:--transport stdio|http、--host、--port、--db-path、--config。
インデックスデータベースは、プラットフォームのデータディレクトリに保存されます(Windows:%LOCALAPPDATA%\docsonar\、macOS:~/Library/Application Support/docsonar/、Linux:~/.local/share/docsonar/)。
ソースから実行
uv が必要です(適切な Python を自動的にインストールします)。
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
git clone https://github.com/ribhav-jain/docsonar.git
cd docsonar
uv sync --dev # creates .venv and installs everything, incl. dev tools
テストを実行する
uv run pytest # full suite (~2 s, no model download needed)
uv run pytest -v # verbose, one line per test
uv run pytest tests/test_search.py # one file
uv run pytest -k incremental # tests matching a keyword
uv run ruff check . # lint
uv run mypy src tests # strict typecheck
uv run python scripts/benchmark.py # perf numbers (downloads the real model)
サーバーを実行する
uv run docsonar # stdio — for MCP clients (Claude Desktop/Code)
uv run docsonar --transport http --port 8365 # HTTP — for manual testing (Postman, curl)
VS Code:F5 キーを押してください。HTTP サーバーとテストスイートの起動設定は .vscode/launch.json にあります。
MCP クライアントなしでツールを試す
HTTP サーバーが実行中の場合、エンドポイントは http://127.0.0.1:8365/mcp です。最近の Postman バージョンでは直接接続でき(新規 → MCP リクエスト、トランスポートは HTTP)、8 個すべてのツールがフォームとして表示されます。生の HTTP を使う場合、MCP は POST 経由の JSON-RPC です。まず 2 つのセットアップ呼び出しを行い、その後にツールを呼び出します。すべてのリクエストにヘッダー Content-Type: application/json と Accept: application/json, text/event-stream を指定してください。
// 1. initialize — copy the `mcp-session-id` RESPONSE header and send it
// back as a request header on every call below
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"postman","version":"1.0"}}}
// 2. initialized notification (expect 202, empty body)
{"jsonrpc":"2.0","method":"notifications/initialized"}
// 3. list the tools
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
その後、ツールを呼び出します。試用用に、リポジトリには examples/sample-docs にサンプルコーパスが用意されています(エスケープを避けるため、JSON ではスラッシュを使用してください。Windows でも動作します)。
// Register the sample folder (first ever call downloads the embedding model, ~30 s)
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"add_folder",
"arguments":{"path":"C:/path/to/docsonar/examples/sample-docs"}}}
// Watch indexing progress until indexing.active is false
{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"index_status","arguments":{}}}
// Hybrid search — finds the expense-policy PDF, cites its page
{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"search",
"arguments":{"query":"meal reimbursement limit","top_k":3,"mode":"hybrid"}}}
// Semantic search — no keyword overlap needed
{"jsonrpc":"2.0","id":6,"method":"tools/call","params":{"name":"search",
"arguments":{"query":"how hot should water be for green tea","mode":"semantic"}}}
// Read a hit (works on PDFs too — returns extracted text)
{"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"read_file",
"arguments":{"path":"C:/path/to/docsonar/examples/sample-docs/expense-policy.pdf"}}}
// "More like this"
{"jsonrpc":"2.0","id":8,"method":"tools/call","params":{"name":"find_similar",
"arguments":{"path":"C:/path/to/docsonar/examples/sample-docs/espresso-guide.md","top_k":3}}}
// Refresh after files change on disk (force:true rebuilds everything)
{"jsonrpc":"2.0","id":9,"method":"tools/call","params":{"name":"reindex","arguments":{}}}
// Clean up — unregisters the folder and purges its index data
{"jsonrpc":"2.0","id":10,"method":"tools/call","params":{"name":"remove_folder",
"arguments":{"path":"C:/path/to/docsonar/examples/sample-docs"}}}
試しておくとよいセキュリティチェック:登録済みフォルダー外の任意のパス(例:C:/Windows/System32/drivers/etc/hosts)を指定して read_file を実行すると、ファイルの内容ではなく拒否が返されます。
CI では Linux、macOS、Windows 上で lint、型チェック、テストスイートを実行します。
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。