qs-rag
README.md
# qs-rag
**ローカルの知識ベースを自然文でセマンティック検索する MCP サーバー。**
Markdown ノートや過去の作業ログを「見出し単位」で索引し、`grep` / 全文探索の代わりに意味で当てにいく。
> Model Context Protocol (MCP) server for semantic search over a local knowledge base. Fully local, zero API cost.
実際のインサイドセールス業務で日次運用しているツール。AI エージェント(Claude Code)が過去の方針・フォーマット・経緯を思い出すための「外部記憶」として使っている。
## なぜ作ったか
エージェントに数百件の Markdown メモや過去セッションログを参照させたいが、`grep` はキーワード一致しか拾えず「あれ何だっけ」系の曖昧な問いに弱い。かといってクラウドのベクトル DB を挟むとコストと秘匿性の問題が出る。
→ **埋め込み・ストア・検索を全部ローカルに閉じた RAG** を MCP として実装した。
## 設計のポイント
- **完全ローカル / API コストゼロ** — 埋め込みは Ollama (`snowflake-arctic-embed2`・1024次元・多言語)。外部送信なし
- **ネイティブビルド不要のストア** — `node:sqlite` にベクトルを置き、メモリ上のブルートフォース cos 類似で検索。件数規模的にこれで十分速く、依存を増やさない
- **2段階の差分インデックス** — `mtime` で粗くふるい、変化したものだけ `sha256` で確定判定。検索のたびに 30 秒スロットルで自動更新するので索引が陳腐化しない
- **Progressive Disclosure** — まず `search_knowledge` で当たりを付け、`get_detail` で本文+同一ファイル内の隣接チャンクを開く。エージェントが文脈を横に広げられる
- **埋め込み層を 1 ファイルに隔離** — 別モデル / 別エンジンへの差し替えは `src/embed.js` だけ変えれば済む
## MCP ツール
| ツール | 役割 |
|---|---|
| `search_knowledge(query, limit?, exclude?, domain?)` | 自然文クエリで意味検索。まずこれで当たりを付ける |
| `get_detail(id)` | チャンク本文+同一ファイル内の隣接チャンク一覧 |
| `reindex_now()` | 即時フル差分 reindex |
`domain` でソース種別(個人ノート / 同期ドキュメント / 過去セッションログ)を絞り込める。
`cc-log` は Claude Code の `~/.claude/projects/-Users-kazuki/*.jsonl` に加え、
Codex の `~/.codex/sessions/YYYY/MM/DD/*.jsonl` も同じ索引へ統合する。
Codex側は `response_item.payload` の user / assistant 本文だけを抽出し、
システム指示・推論・ツール出力・起動時のAGENTS wrapperは除外する。
検索時の差分reindexにより、Codexの新規・更新セッションも自動反映される。
## スタック
Node.js (ESM) / `@modelcontextprotocol/sdk` / Ollama / `node:sqlite`
## セットアップ
```bash
npm install
# Ollama を起動し、埋め込みモデルを pull
ollama pull snowflake-arctic-embed2
node bin/reindex.js # 初回フルインデックス
node bin/search.js "クエリ" # ターミナルから直接検索
```
MCP ホスト(Claude Code 等)には stdio サーバーとして登録する。
### 索引対象の指定
既定では `~/notes`(Markdown)と `~/.claude/projects`・`~/.codex/sessions`(エージェントのセッションログ)を索引する。差し替えは環境変数で行う。
| 環境変数 | 既定値 | 用途 |
|---|---|---|
| `RAG_SOURCES` | (なし) | 索引対象を JSON 配列で直接指定 |
| `RAG_SOURCES_FILE` | (なし) | 同じ JSON を書いたファイルのパス |
| `RAG_DB_PATH` | `~/.qs-rag/index.db` | インデックス DB の置き場所 |
| `QS_RAG_OLLAMA_URL` | `http://127.0.0.1:11434` | Ollama のエンドポイント |
| `QS_RAG_MODEL` | `snowflake-arctic-embed2` | 埋め込みモデル |
```jsonc
// RAG_SOURCES の例。root は ~ 展開に対応する
[
{ "root": "~/notes", "kind": "md", "domain": "knowledge", "excludeDirs": ["_archive"] },
{ "root": "~/work/docs", "kind": "md", "domain": "context" },
{ "root": "~/.claude/projects", "kind": "jsonl", "domain": "cc-log", "recursive": true }
]
```
`kind` は `md`(Markdown を見出し単位でチャンク化)か `jsonl`(セッションログを turn 単位で取り込み)。`domain` は検索時の絞り込み・除外の単位になる。
---
<sub>個人で開発した MCP サーバー群の 1 つ。設計の出発点として yuya-mcp の RAG パートを参考にした。</sub>
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues