Skip to content

feat(mcp): add vector_ids to search for stored-content retrieval #239

Description

@smileygames

purpose

searchvector_ids パラメータを追加し、索引が既に保持している本文を取り出せるようにする。現在 doc / wiki_doc 以外の型には本文を返す手段が一切なく、search であたりを付けたあと gh や grep で取り直す一往復が必要になっている。普段使いの retrieval コストの問題である。

過去の判断(先に確認済み)

専用 tool を追加する案を検討し、退けた#104 / #105 で 4 tool を search 1 本へ統合した判断があり、専用 tool はその逆行になる。

削除された 3 tool: get_issue_context / get_doc_content / list_recent_activity本文取得の専用 tool は get_doc_content の復活そのものである。

統合時の設計意図(commit 6acdbd3 body より):

search_issues now exposes three modes via its parameter set: hybrid semantic search (existing), time-ordered activity scan (empty query + sort=updated_desc/created_desc + optional since/until), and inline doc content fetch (include_content).

「パラメータ集合でモードを表現する」形は意図された設計であり、事故ではない。したがって本 issue もその作法に乗る。

なお #104 は起票者アカウントの凍結により GitHub 上で参照できない(gh issue view 104 は 404)。上記の意図はローカル clone の commit body から復元した。commit body に意図を書く規約が、issue が読めなくなっても判断を保存していた事例である。

premise

本文は既に読み込まれていて、返す直前に捨てられている

src/mcp.ts の search 経路は reranker に食わせるために D1 FTS 行の content を読み込む(L773-820)。dense 側だけでヒットした候補には search_docs からのバックフィルまで行う(L788-806)。つまり結果組み立て時点で content はメモリ上にある。

しかし出力に載るのは doc / wiki_doc だけ。inlineDocContent(L1222)が対象を絞っており、非 doc 行は素通りする(tool description L429: "Non-doc rows are unaffected")。

対照的に graph 軸の buildGraphItem(L258)は includeContentrow.content を型を問わずそのまま返している。同じ include_content フラグで keyword 軸と graph 軸の挙動が割れている。

索引が保持している content の実体

全 surface が FTS に書いているのは embedding input そのもの。

surface 書き込み箇所 中身
issue / PR embed-issue.ts L190, L285 prepareEmbeddingInput(title, body)
comment / review embed-comment.ts L134, L247, L372 embedding input
release embed-release.ts L125 embedding input
doc / wiki_doc embed-doc.ts L82, L186 embedding input
diff embed-diff.ts L249 embedding input

いずれも MAX_EMBEDDING_INPUT_CHARS = 8000 で truncate されている。索引に尾は存在しない。

実測(Liplus-Project/liplus-language の issue body 10 件): 1,175 / 1,319 / 1,400 / 1,640 / 1,749 / 1,975 / 2,226 / 2,715 / 3,193 / 3,696 文字。8000 超は 0 件。issue 本文では上限がほぼ効かない。一方 diff 行は patch なので日常的に上限に当たる。

doc 経路が GitHub から取り直している理由

embed-doc.ts も content を D1 に持っているのに、include_content は contents API を叩いている。これは冗長ではなく、doc は完全なファイルが必要で 8000 文字の頭では足りないため。INCLUDE_CONTENT_MAX_DOCS = 5 はその API fan-out を抑える上限である。

したがって include_content と本 issue の経路を統合してはならない。取得元と上限の根拠が違う。

設計

既存の導出作法に合わせる。モードは列挙パラメータで選ばせず、パラメータ集合から導出する。

query が空          -> scan       (既存、L481 の isScanMode)
include_content     -> doc 本文 inline(既存、contents API 経由)
vector_ids が存在   -> 本文取得   (本 issue)

vector_ids が渡されたら、その行の保存済み content を返す。呼び出し側が対象を名指しするため、サーバ側が合計バイト数上限を発明する必要がない。フラグ方式で必要になる「どこまで返せば安全かの推測」がここでは発生しない。

vector_idsearch の結果各行に追加する。内部では既に主キー(L663 の vector_id -> payload lookup)。

ただし永続識別子として約束しない。 この repo には legacy vector id の移行履歴(src/pipeline/legacy-vector-id.ts、pre-migration generation)がある。「検索結果からその場で引くための一時的な取っ手」として description に明記し、採番変更で縛られない形にする。

応答の mode フィールドが現在 "search" / "scan" の 2 値であるため、本経路をどう報告するかは実装判断。

constraints

target files

  • src/mcp.tsvector_ids パラメータ、search 結果への vector_id 追加、tool description
  • docs/0-requirements.md / docs/0-requirements.ja.md — MCP Tool Surface 節
  • テスト — 型ごとに content が返ること、未知 vector_id の部分成功、truncate 表示、search 結果に vector_id が載ること

acceptance

  • search の結果各行に vector_id が載る
  • vector_ids を渡すと issue / pull_request / issue_comment / pr_review / pr_review_comment / release / diff の本文が返る
  • GitHub API 呼び出し数が増えていない
  • 索引由来・truncate 済みであることが結果から判別できる
  • 未知の vector_id が混ざっても残りは返る
  • include_content の既存挙動が変わっていない
  • MCP tool 数が 1 のまま

補足(この issue のスコープ外)

保存済み content が embedding input と同一値であるため、8000 文字上限は embedding のための判断が保存の判断を兼ねている状態にある。FTS 側に truncate しない本文を持たせるのが根本の形だが、既存行の再 index が必要で、範囲が別。ここでは「既に持っているものを返す」に限定する。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancement新機能・改善要望ready本文が実装開始できる形まで収束している状態。ただし更新は継続可能review-pending実装フェーズ完了。orchestration (brake eval / review / merge / close) 待ち

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions