Skip to main content
Glama
mmorrisj
by mmorrisj

corpus-mcp

MCPサーバーは、エージェントにドキュメントディレクトリに対するキーワード検索を提供します。フォルダを指定するだけで動作します。モデルのダウンロード、APIキー、GPU、並行して動かすベクターデータベースは不要です。依存関係はMCP SDKのみです。

pip install -e .
corpus-mcp --root ./docs serve

興味深いのは検索そのものではありません。ツール設計です。エージェントが検索ツールで実際に何ができるのか、そして何がツールを使いやすくするのか。使いにくいツールはコンテキストウィンドウを焼き尽くすだけです。


10秒で試す

$ make demo
1. reference/glossary.md  (score 1.973, f700ededcfdd:0)
   # Glossary

   **Extraction** — the process of dissolving soluble compounds out of ground
   coffee. Under-extraction tastes sour and thin; over-extraction tastes bitter …

2. guides/brewing.md  (score 1.774, 71c6f092dbcb:0)
   # Pour-over brewing
   …

そのクエリは "why does my coffee taste sour" でした。ドキュメントには tastes とあり、クエリは taste でした。そして実際に答えとなる用語集エントリが最初にランクインします。どちらも意図的なものです。詳細は後述します。

Related MCP server: Saga

ツール

ツール

目的

search(query, limit, snippet_chars)

マッチ中心の短いスニペットとしてランク付けされたパッセージ。それぞれに chunk_id が付きます

fetch(chunk_id, context_chunks)

1つのパッセージの全文とその近傍のパッセージ

list_sources(limit)

インデックスされた内容と文書ごとのサイズ

ドキュメントはMCP リソースとして corpus://<relative-path> でも公開されます。

議論に値する設計判断

検索とフェッチは別々のツールです。 完全なチャンクを返す1つの search は実装は簡単ですが、使い勝手はずっと悪くなります。結果が10件、それぞれ1,200文字だと、エージェントがどれを欲しいか決める前にコンテキストウィンドウの大半を消費してしまいます。そこで search はトリアージに十分なスニペットを返し、fetch が選択した結果をオンデマンドで広げます。エージェントは詳細が必要だと判断した場所でのみ詳細にコストを払います。

スニペットはチャンクの先頭ではなく、マッチを中心にしています。 最初のN文字を返す方式は頻繁に失敗します。マッチする文はたいてい中間にあるからです。エージェントは無関係な前置きを見て、良いヒットを捨てるか、確かめるために全部をフェッチするかのどちらかになります。スニペットウィンドウは、クエリ語の出現をできるだけ多くカバーするように選択されます。

すべての上限はサーバー側で強制されます。 ツールの出力は直接コンテキストウィンドウに入るため、無制限のツールは呼び出し元に対するサービス拒否攻撃になります。10,000件の結果を求める呼び出しは、まさに上限が存在する理由です。そのため、制限は信頼されるのではなく強制されます。出力が切り詰められた場合はレスポンスに明記され、エージェントはすべてを見たと思い込むのではなく、クエリを絞り込むことができます。

空の結果はそれ自体が説明になります。 裸の空リストは行き止まりです。レスポンスはチャンク数とドキュメント数を報告し、「クエリがヒットしなかった」と「何もインデックスされていない」を区別します。この2つは次のアクションが異なります。

古い識別子は想定内の結果であり、エラーではありません。 チャンクIDはドキュメントが編集されると変わるため、長いセッションの初期に取得したIDが無効になることがあります。fetch はその旨を正確に伝え、エージェントに再検索するよう指示します。

チャンクを結合する際に重複は除去されます。 チャンクはパッセージが境界で分割されないように重複していますが、その重複をそのまま返すと、エージェントは同じ文を2回読み、繰り返しを強調と受け取る可能性があります。チャンクは絶対オフセットを持つため、重複は文字列マッチングではなく位置によって除去されます。

埋め込みではなくBM25。 エージェントがある程度知っているコーパスをナビゲートするときに発行するキーワード的なクエリに対しては、語彙ベースの検索が強力です。そしてエージェントループで最も重要な特性を持っています。高速で、暗黙のうちにコストがかかることがありません。セマンティック検索は価値のある追加機能であり、有用であるための前提条件ではありません。

本格的なステマーではなく軽量なステミング。 複数形と一般的な動詞語尾を折りたたむことで tastes が taste にマッチします。完全なPorter実装は100行とメンテナンス対象を増やし、そのロングテール(operational → oper)は短いクエリでは助けになるよりも害になる可能性が高いです。インデックス作成とクエリは同じトークナイザーを共有します。なぜなら、両者に食い違いがあると暗黙のうちに再現率を損なうからです。

セキュリティ

サーバーはルートディレクトリを指定され、その外を読むことはありません。これは一見した以上に重要です。ツールの引数はモデル出力から来るため、ドキュメント識別子は信頼できない入力であり、../../.ssh/id_rsa は混乱した、あるいは敵対的なエージェントがいつか必ず要求するものです。

境界を越えるすべてのパスは、比較前にシンボリックリンクを解決する単一の封じ込めチェックを通過します。ルート内のシンボリックリンクが外部を指している場合、未解決パスで行われるプレフィックスチェックは無効になります。絶対パスのように見える引数は、実際の絶対パスとしてではなく、ルートからの相対パスとして解釈されます。リソースURIもツール引数と同様に扱われます。

UTF-8以外のファイル、過度に大きなファイル、ベンダーディレクトリ(.git、node_modules、…)はノイズとしてインデックスされるのではなくスキップされます。

クライアントへの接続

Claude Desktop、または任意のMCPホストがサーバーをサブプロセスとして起動します:

{
  "mcpServers": {
    "my-docs": {
      "command": "corpus-mcp",
      "args": ["--root", "/absolute/path/to/docs", "serve"]
    }
  }
}

コーパスはディスク上で変更されると再読み込みされるため、セッション中に編集されたファイルは再起動なしで検索可能になります。再インデックスは毎回全体を再構築するのではなく、変更時刻に基づいて増分で行われます。

開発

make install   # server plus dev tools
make demo      # one query against the example corpus
make test      # 89 tests, no network required
make smoke     # launch the installed server as a subprocess and exercise it
make lint

テストは2層あります。異なる障害を捕捉するためです:

  • tests/test_server.py は実際のMCPクライアントを実際のサーバーに対してインプロセスで駆動します。 テストされるのは、ワイヤー動作(ツールスキーマ、構造化結果、エラーの形状)であり、その下にあるPython関数ではありません。関数が正しくてもツールの表面が間違っているサーバーは依然として壊れており、このレベルのテストだけがそれを捕捉します。

  • scripts/stdio_smoke.py はインストールされたコンソールスクリプトをサブプロセスとして起動し、ホストと同じようにstdio経由でJSON-RPCを送ります。これにより、パッケージング、エントリポイント、トランスポートがカバーされます。何かがstdoutに書き込んでプロトコルストリームを壊すという古典的な障害も含みます。

制限事項

  • 語彙的検索のみ。 ドキュメントと共通の語彙がないクエリはヒットしません。同じツール表面の背後に埋め込みバックエンドを追加するのが明らかな次のステップです。

  • テキスト形式のみ — .md、.txt、.rst、.csv、.json、.yaml など。PDFやDOCXの抽出はありません。

  • インデックス全体がメモリ上に存在し、コーパスが変更されると全量再構築されます。想定している数千ドキュメントのケースでは問題ありません。数百万規模のコーパスには、ファイル単位で更新される本格的なインデックスが必要です。

  • 英語のみ。 ストップワードリストと語尾折りたたみはどちらも英語を前提としています。

  • ルートを超えたアクセス制御はありません。 ルート配下のすべてのファイルは、サーバーが接続されているすべてのものから見えます。

ライセンス

MIT。 Aion Innovations によって構築されました。

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    An MCP server that allows users to efficiently search and reference user-configured documents through document listing, grep searching, semantic searching with OpenAI Embeddings, and full document retrieval.
    4
    3
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    A local-first MCP server for document ingestion and semantic search, providing tools to add, search, and retrieve documents, chunks, and code blocks.
    13 npm
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    A local-first MCP server providing secure workspace file operations, offline full-text search, and web search/fetch capabilities without requiring API keys.
    10
    -
  • A
    license
    A
    quality
    A
    maintenance
    A self-hosted MCP server providing web search and URL fetching tools, running locally without external API keys or accounts.
    2
    152 npm
    MIT