Semantic search over a Markdown knowledge base, served over MCP.
GrooveSeek が接続クライアントに公開する MCP の面。
English version: mcp-tools.md
| ツール | 説明 | 主なパラメータ |
|---|---|---|
search |
ベクトル + FTS5 全文検索を Reciprocal Rank Fusion でマージしたハイブリッド検索、任意で cross-encoder 再ランク + MMR 多様性再ランク + parent retriever 展開。{ results, low_confidence, filter_applied } ラッパで関連度ランク付き chunk を返す。parent retriever が発火した行には expanded_from も付く。chunk がソースファイル由来なら (v1.2.0+) start_line / end_line (1 始まり、定義ではなく chunk の範囲) と symbol_kind (grammar が呼ぶ定義の種別) も付く。この 3 つは、それ以外では null ではなくキーごと現れない。詳細: docs/citations.ja.md、docs/filters.ja.md、docs/retrieval-pipeline.ja.md |
query (必須。空白区切りの group の先頭に - を付けると (例: -async)、検索するのではなく両脚から除外する — v1.1.0+、詳細は retrieval-pipeline.ja.md — 同じ 3 文字の trigram 下限が効くので -ab は何も除外しない)、limit、category、topic、rerank (サーバ既定を上書き)、min_quality、include_low_quality、path_globs (! 始まりは exclude)、tags_any / tags_all、date_from / date_to (YYYY-MM-DD)、fields / fields_not (object: key → list of strings、スキーマが宣言した key のみ、v1.9.0+)、min_confidence_ratio、mmr / mmr_lambda / mmr_same_doc_penalty (v0.7.0+)、parent_retriever (v0.7.0+) |
list_topics |
index 済みの全トピック / カテゴリと文書数を列挙。search の category / topic filter が受ける値はここで分かる。(v1.1.0+) 各 entry に children が付く: そのカテゴリ / トピック配下の directory tree で、topic より下の path segment 1 つが 1 node。node は segment / file_count (その prefix 配下の文書数。親は配下すべてを数える) / 自身の children を持つ。root と category のみの entry、および文書が topic 直下にしか無い topic では []。tree は保存された path から作るので、frontmatter の topic: で path 由来の topic を上書きした文書も、2 番目の path segment より後の directory をその group に寄与させる。この segment はその文書自身の path から取ったものなので、<category>/<topic>/ の下に directory として実在するとは限らない — client はこれを繋げて path prefix を組み立ててはいけない。MCP の面の安定性 を参照 |
(なし) |
get_document |
相対パスから文書の全文 + メタデータを取得。パスはその文書のただ 1 つの綴り — KB 相対・/ 区切りで、search が返したとおり — でなければならない。同じファイルに届く別の書き方 (./a.md、a//b.md、a/../a.md、絶対パス、Windows / macOS での大文字小文字違い、Windows でのバックスラッシュと 8.3 短縮名、symlink のディレクトリ経由) は “not found” になる。要求文字列で絞り込む前段ゲートウェイを迂回させないため。索引が持ちうる名前でないパス (絶対パス・空文字列・..・.・空の区間を含むもの (./a.md、a//b.md)、Windows ではドライブ指定・UNC 共有・バックスラッシュ・どこかに含まれる : (note.md:secret のような代替データストリーム)・NUL や COM1 などの予約デバイス名・末尾がドットか空白の区間・< > " \| ? * や制御文字) はディスクを見る前に拒否する: そこに何かがあっても無くても答えは同じで、Windows で共有に接続することもない。索引が持ちうる名前での別の綴り (大文字小文字違い・8.3 短縮名・symlink のディレクトリ経由) は先にディスクを見てから (見るのは KB の中だけ) 同じく “not found” になる |
path (例: "deep-dive/mcp/overview.md") |
get_best_practice |
opt-in: groove.toml の [best_practice].path_templates を設定しているときのみ機能する。対象向けの best practice 文書を取得し、任意で特定 h2 セクションを抽出。未設定時は “not configured” エラーを返す |
target (例: "claude-code")、category (任意) |
rebuild_index |
すべてのソースファイル (Markdown + [parsers].enabled で有効化された拡張子) を走査してインデックス再構築。同時に 1 本だけ (v1.0.0+): 実行中に来た呼び出しは「実行中のものが何秒前に始まったか」を添えたエラーで断る。再構築は embedder と DB を握り続けるので、終わるまで検索が使えないため。制限がかかるのはこのツールで、groove index は別プロセスなので対象外。返り値は CLI の summary と同じ counter で、frontmatter_unparsed (v1.7.0+) を含む。[index].fail_on_frontmatter_error = true のときは、その値が 0 でなければ counter の隣に error key が付く。embedding provider が OpenAI 互換のとき、endpoint が入力を断った (HTTP 400 / 413 / 422) ファイルは skip されて skipped に数えられ、そうした拒否 (そのファイルのどのバッチも受け付けられないままのもの) があって endpoint がどのバッチも受け付けなかった run では counter の隣に error key が付く。force: true の run でそうした拒否が 1 つでもあった場合も同じで、再構築が先に索引を空にしたためそのファイルは索引に無い (ADR-0025)。force: true で embedding provider が OpenAI 互換のときは、索引を空にする前に固定の probe 文字列を 1 件 embedding し、endpoint が断れば、索引から何も消していないと述べるエラーを返す (ADR-0024) |
force (任意、既定 false) |
get_connection_graph |
ドキュメントパスを起点に意味的に関連するチャンクを BFS 展開。search の後、query の語が届かなかった文書に答えがありそうな時に使う (探索は query ではなく、起点文書からの embedding 類似度を辿る)。parent_id / depth / score / snippet 付きのノード配列を返し、呼び出し側でコンテキスト発見を連鎖させられる。上限で探索が切られた場合は truncated / truncation[] が付く。snippet は抜粋なので、ノードの全文は get_document で読む |
start (必須、探索の起点パス — groove graph --start)、depth (既定 2、最大 3)、fan_out (既定 5、最大 20)、min_similarity (既定 0.3)、seed_strategy (all_chunks / centroid。all-chunks も受け付ける)、dedup_by_path、category、topic、exclude_paths、max_nodes (既定 100、最大 2000)、max_seed_chunks (既定 32、最大 1000) |
(v0.22.0+) 4 つの prompt を同梱している。クライアントはこれをユーザが選ぶコマンドとして出す (Claude Code では /mcp__<server>__<name>。<server> は .mcp.json でこのサーバに付けた鍵であって、GrooveSeek が決める名前ではない)。存在理由は「ツールだけでは組み合わせ方が分からない」こと — get_connection_graph は search の後に使えるとは言うが、どこまで広げるか、出てきた語彙で検索し直すか、low_confidence が立ったらそう言うべきかは、どのツールも言わない。
| Prompt | 引数 | 何を指示するか |
|---|---|---|
summarize_topic |
topic (必須) |
list_topics でトピックの存在を確認 → search で集める → 重要な文書は get_document で全文を読む → 要約する。カバーされていないことも書かせる |
deep_dive |
question (必須) |
最初の検索だけで答えない。上位ヒットを get_connection_graph の depth 2 で広げ、全文を読み、そこで得た語彙で再検索する |
whats_new |
since (任意、YYYY-MM-DD。省略時は 30 日前) |
その日付以降の文書を概観する。date_from が絞るのは frontmatter の date = 著者が書いた値であって、ファイルの更新時刻ではないことを prompt 自身に明記させ、近似であると断らせる。加えて date_from は文字列として比較されるので、YYYY-MM-DD 以外を渡すとエラーにならず全文書が落ちることも警告する |
find_gaps |
topic (任意) |
欠落を探す。low_confidence が立つ問い、include_low_quality: true でしか出てこない stub。欠けているものを報告させ、内容の提案はさせない |
4 つとも text のみで、引用規則を共有する: 使った文書の path を必ず引用する / low_confidence を握り潰さず表に出す / ナレッジベースが沈黙している時は一般知識で埋めずにそう言う。
設定ファイルではなくコンパイル時固定にしてある。 prompt 本文はモデルに渡るテキストで、groove.toml は cwd や .git 祖先から発見されるため、設定で定義できるようにすると untrusted config に対して kb_path と同じ制限が必要になる。MCP 仕様も助けにならない — tool annotation と違い、クライアントに「prompt の内容を信用するな」と言う指針が無い。
(v0.22.0+) ナレッジベースを kb:// スキームの MCP resource としても公開する。Claude Code では @ メニューに出る。
| URI | 中身 |
|---|---|
kb://topic/<prefix> |
topic group = パスの先頭 1〜2 セグメント。indexer が category / topic を導出するのと同じ規則。read するとその配下の文書一覧 (URI 付き) が Markdown で返る。kb://topic/ は root group |
kb://doc/<path> |
索引済みの文書 1 件。列挙はせずテンプレートとして公開する |
resources/list が返すのは topic group であって、文書 1 件ごとではない。ナレッジベースの文書は数百でもグループは数十であり、listing は接続のたびにクライアントが取りに来るもの。個々の文書はテンプレートと、search hit に付くようになった uri から辿れる — spec は「listing に出ていない文書へのリンクを tool が返すこと」を明示的に許している。listing もこの uri も同一の述語から来るので、同じ文書について両者が食い違うことはない。索引に残り検索でも見つかるまま、提示だけ外れる要因が 3 つある (Windows ではもう 1 つ、Windows がそのままでは開けない名前。ADR-0023 を参照)。1 つ目は現在の parser registry: [parsers].enabled を狭めて再 index しないと、外した拡張子の行は索引にも検索結果にも残るが、read が拒否する以上提示しない。2 つ目は size (v0.23.0+): 1 MiB を超える Markdown / テキスト文書は resources/read が返す量を超えるので、これも提示しない (search hit は残り、uri だけが付かない)。同じサイズでも PDF や表計算は提示され続ける — read が拒否ではなく抽出テキストを切り詰めるため。50 MiB を超えて索引されたバイナリ文書 ([index].max_binary_file_size で索引の上限を上げた時だけ起こる) は提示しない — read は索引の設定に関係なく 50 MiB を超えるバイナリを拒否するため (ADR-0026)。3 つ目は展開上限: バイナリ文書を提示するのは [index].max_decompressed_size が組み込みの展開 budget (50 MiB) 以下の間だけ — それより上げると、バイナリの hit は uri を持たず、resources/list / resources/read も提示しない。read は組み込みの budget で parse し、記録された raw の大きさからはどの文書を read が受け付けるか分からないため。テキスト文書には影響しない。size は index 時に記録される。以前のバージョンで索引した文書は size 未記録で、次の groove index まで提示されたままになる (その 1 回で再 embed 無しに埋まる)。groove doctor は 3 つの要因それぞれで外れている文書を名指しし (extension-not-registered / larger-than-a-read-returns / binary-uris-withheld)、size 未記録の文書は件数を報告する。根拠は ADR-0005。
区切りは forward slash のまま、それ以外は percent-encode するので、空白や非 ASCII を含むパスでも正しい ASCII URI になる。
read は索引で縛られる。 提供されるのは索引に入っている文書のみで、そのうえで get_document と同一の検査 (symlink / hardlink 拒否、path traversal、拡張子 membership、size cap、handle 束縛の read) を通す。これは get_document (= kb_path 配下で拡張子が registry にあれば返す) より狭い。resource は「サーバが提示したもの」なので、提示していない URI を提供するのは別の操作だから。したがって .grooveignore された文書は resource には出ないが get_document からは従来どおり読める — これは ADR-0003 の契約が不変であることの帰結。判断の正本は ADR-0004。
内容はテキストとして返り、media type は提供物の型にする: Markdown は text/markdown、抽出テキストとして出すものは text/plain。PDF や表計算は groove が抽出したテキストとして返り、元のバイト列ではない。
未実装: resources/subscribe と notifications/resources/list_changed。これらが無くても "resources": {} は準拠した宣言であり、固定の topic group は滅多に変わらない。
docs/citations.ja.md — match_spans とバイトオフセットdocs/filters.ja.md — 検索結果の絞り込みdocs/clients.ja.md — そもそもクライアントを繋ぐ手順