Skip to main content
Glama
librechat-search-mcp

librechat-search-mcp

by krahnikblis

librechat-search-mcp

このプロジェクトは、LibreChatのSearch messages機能をMCPツールへ拡張し、能動的またはオンデマンドな利用を可能にすることで、「全メッセージ・メモリ」を実現します。

Related MCP server: knowledge-base

概要

制限付きのLibreChat専用MCPサーバーで、LibreChatがインデックス化したメッセージ履歴を検索するために、汎用の meilisearch-mcp をベースにしています。ネイティブのmemory機能/能力を補完しつつ、任意のLibreChat memory.agentも無効にする場合には、コストとコンテキストの損失を抑えることを目的としています。Streamable HTTPを使用し、LibreChatのDocker Composeネットワーク内の専用コンテナでホストされます(つまり、非Dockerのホスティング/デプロイ構成では実装されていません)。LibreChatがリクエストごとに送信するUser-Idヘッダーから実効ユーザーを取得し、ユーザーフィルターをサーバーサイドで適用します。エージェントに返す前に結果を制約するため、追加の検索後フィルターも使用します。このサーバーは、すでに権限を持つユーザーと管理者のスコープにのみ機能を制限するよう意図的に設計されており、プライバシーが懸念される潜在的なリスクを意識的に指摘しつつ、主に「プライバシーは期待できない」ことが利用者へ明示されているシナリオ向けに設計されています。

動機

LibreChat組み込みのメモリ機能は、メモ帳的なコンテキストメモリとしては悪くないものの、いくつかのコストと副作用があります:

  • 小型モデル(例:Gemma-4-12B)は、新しいチャットでそのメモリを重要なプロンプトコンテキストとして解釈し、他の会話からの奇妙な持ち越しを引き起こす

  • デフォルトのLibreChat自動メモリエージェントは、メモリを追加・結合ではなく完全に上書きするため、意図的に作成したメモリが失われる

  • 自動メモリエージェントはすべてのユーザーメッセージのたびに実行され、入力トークンコストが2倍になる(そう、あなたはメモリエージェントにもっと安いモデルを使っているでしょう...)

  • キャッシュ書き込みコスト - これが私がこのプロジェクトをついに作るきっかけです:メモリエージェントがメモリを調整するたびに、会話キャッシュ全体が書き換えられます(OpenAIのキャッシュシステムを使用している場合)。メモリはスレッド履歴の先頭に挿入されるためです。

  • 私の場合、GPT-5.6-Terraの会話では1回あたり最大3ドルのコストがかかりましたが、利用状況を調べたところ、不要に繰り返されるキャッシュ書き込みが最大の要因でした。

一方で、私はエージェントにも、ChatGPTのように会話の履歴全体をより把握してほしいと思っていました。LibreChatのSearch messagesボックスにテキストを直接入力できるのだから、「なぜエージェントにこの機能を与えられないの?」と考えました。安価なエージェントが要約したメモリよりも、完全なメッセージからははるかに豊かな情報が得られます。さらに再帰的検索を使えば、多くの会話から多くの情報を結びつけることができるでしょう。私の個人実装はすでにこれを実証しています。職場のグループ内でのデプロイ結果はまだ見えていません...

MCPツール

このサーバーは、元となっている meilisearch-mcp プロジェクトの読み取り専用ツールを、LibreChat専用のバージョンで提供します(書き込みツールは含みません)。

  • search_messages:呼び出し元のインデックス化済みのメッセージを能動的に検索します。既知の会話ID、送信者、結果制限で任意に絞り込めます。メッセージID、会話ID、送信者、テキストを返します。

  • search_conversations:呼び出し者のインデックス化済みの会話をタイトルで能動的に検索します。フォローアップのメッセージ検索のために、会話ID、タイトル、タグを返します。

  • admin_search_messages:明示的に要求され承認された、特定ユーザーのメッセージ検索。対象ユーザーと、上述のメッセージフィールドを返します。

  • admin_search_conversations:明示的に要求され承認された、特定ユーザーの会話をタイトルで検索。対象ユーザーと、会話ID、タイトル、タグを返します。

  • health-check:設定済みのMeilisearchの可用性ステータスを読み取ります。

  • get-version:Meilisearchのバージョン情報を読み取ります。

  • get-stats:データベース全体のMeilisearch統計を読み取ります。

  • get-health-status:構造化されたヘルスステータスとインデックスステータスを読み取ります。

  • get-system-info:Meilisearchのシステム情報を読み取ります。

  • get-index-metrics:特定の既知のインデックスのメトリクスを読み取ります(indexUidが必要)。

    • 未実装 - デフォルトのLibreChat構成ではエラーを返します。戻り値のfieldDistributionは、将来のネットワーク化されたメッセージ検索のトピックグラフ構築で役立つ可能性がありますが、LibreChatの最新バージョンのMeilisearchではこの機能は実験的であり、有効化および作成が必要です。

ユーザースコープ

通常の検索は、サービス側でリクエストスコープと発信者スコープに制限され、対象ユーザーや生のフィルターを受け付けません。管理者検索はサービスの認可を必要とし、通常は対象ユーザーも指定します。認証に失敗した場合は、再試行やプローブをしないでください。現在の実装は、一般的な検索エラーを報告します。すべてのツールは読み取り専用であり、上述のドキュメントに記載されたフィールドのみを返します。

リクエストスコープのツール動作

最初は、リクエストスコープ(MCPヘッダーでメッセージIDや会話IDを使うなど)がUXをどう変えるのかわかりませんでした。MCPサーバ自体は全体として選択可能に見えますが、そこにあるツールは個々に選択できません。つまり、ユーザー向けエージェントから管理者ツールを除外することできません(ただし、このサーバーがユーザースコープに基づいてツールを提示する方法には、ある程度の動きがあります)。理想的には、サーバー接続のヘッダーとツール使用のヘッダーを分けて設定したいところです。私はカスタマイズ性を改善できるような変更点を探すため、LibreChatのさまざまなMCPのバグやPRを追っています。

既知の問題

現在のプロジェクト内:

  • ログがトラブルシューティングするには未拠なすぎる(リクエストパラメータとレスポンスメトリクスを追加し、任意でエラーをJSONへ出力する)

  • ツールの失敗エラーが具体的でない(当初はプライバシー保護のために意図的なもの。エージェントが自己修正するにはより多くのコンテキストが必要)

  • conversationIdでフィルタリングされたsearch_messagesの使用が断続的に失敗する可能性?(接続・スレッド・非同期が原因かも。TODO:会話をフィルタ可能フィールドとして追加)

  • get-index-metricsは実験機能の有効化が必要(TODO:テストと調査をする)

  • ドキュメントとコードに、レガシー/開発中のアーティファクトがあり不整合となる

  • 管理者検索の対象となるユーザーIDの取得が面倒(TODO:PeoplePicker APIを調べ、ハンドルや名前+イニシャルへマッピングする)

統合/有効化の影響:

  • ツール選択が利用できない(リクエストスコープのヘッダーが原因)

  • サブエージェント内での連続的なツール利用が失敗レスポンスを生成する(スレッドと非同期関数を詳しく調査する必要がある)

  • 過去のトピックを検索・検討すると、将来の検索でのテーマが薄くなる

  • 会話単位のグループ化がかさばり、トークンコストが高い可能性がある(TODO:メッセージ検索から会話単位の統計を返す機能を追加する)

  • 複雑な検索シナリオのコストが高い(TODO:サーバーサイドのグループ化、キーワード/トピックグラフ、マルチ検索の合体・積集合・差集合・除外演算、重複排除、並び替え)

セキュリティモデル

このツールは、LibreChatデプロイが単一テナント・単一ポリシーであり、セキュリティ専用のモデルやプロバイダを実装しないという前提で構成されています!

ツールには基本的なユーザーアクセス制御があり、潜在的に広大な管理者スコープがあります:

  • 通常ツール:search_messagesとsearch_conversationsは常に呼び出し者のユーザーのみを検索します。モデルがuserや生のMeilisearchフィルタを提供することはありません。

  • 管理者ツール:admin_search_messagesとadmin_search_conversationsは、呼び出し者のUser-IdがMEILI_MCP_ADMINSのエントリと完全一致することを条件とします。MEILI_MCP_ADMIN_SCOPE_ALL_USERS=trueでない限り、対象のuserが必要です。

  • MCPサービスには、MEILI_MCP_KEYとして制限付きの読み取り専用Meilisearchキーが提供されます。Meilisearchマスターキーを絶対に使用または渡さないでください。

  • 結果はスキーマ制限されます。通常の結果にはmessageId、conversationId、sender、textのみ、会話の結果にはconversationId、title、tagsのみが含まれます。管理者の結果にはさらに選択したuserが含まれます。

  • 不足、空、または不正な形式の認証情報がある場合にはフェイルクローズします。認証エラーは意図的に一般的なものとし、秘密情報は一切返しません。

取得されるテキストは、LibreChatがインデックス化した正確な内容です。インデクサーやデプロイの構成によっては、アシスタントの出力や推論にようなテキスト、またはツールのトレースが含まれ可能性があります。このMCPサーバーは、LibreChatがインデックスしていないコンテンツを復元できません。検索結果は潜在的に機微な監査データとして扱ってください。

注意点と注意警告の詳細は、SECURITY.md を参照してください!!!

管理責任

私は、自分の法人利用者に対して、ITセキュリティ運用担当者と私がすべてのデータ/履歴を閲覧できる機能があることをすでに通知しています(「プライバシーの期待はできません」)。私の想定では、あなたのデプロイにこれが該当する場合は同じ措置を取っている、またはポリシーに違反する可能性のあるシナリオではこの実装を導入しないでしょう。このツールは、私が(MongoDBツールやMeili CLIなどを通じて)すでにできることをより簡単にしているだけで、同時に、あるプロバイダー/モデル/エージェントから別のプロバイダー/モデル/エージェントへ履歴を公開することになります(私のデプロイでは、この安全なコンテンツ用のプライベートモデルをまだ実装していないため、これはまだ問題ありません - 今のところは)。

LibreChatのセットアップ

次の example ファイルを LibreChat Composer プロジェクトへコピーまたはマージし、ご自分のキー/ID/設定を入力してください:

  • librechat-search-mcp/librechat.yaml.example:mcpSettingsとmcpServersを既存のlibrechat.yamlにマージします。 {{LIBRECHAT_USER_ID}}などのMCPヘッダーパラメータマッピングは、指定されたとおりに正確に設定する必要があります。LibreChatはこれらをリクエストごとに置き換えます。これらはセキュリティモデルとフィルタリング機能の一部です。

    • 推奨:上記の動機にあなたのデプロイでも同意する場合は、librechat.yamlでメモリエージェントを無効にしてください。将来のLibreChatバージョンが、その動作がトークンコストとクロス・会話トピック位染に与える影響を変えるまで、無効のままにしてください。

    • 注記:最近のLibreChatの変更により、メモリツールの動作がendpoints.agents.capabilities設定のオプトイン方式に変わりました。エージェントがオンデマンドでメモリを書き込めるようにしたい場合は、そこに "memory" を追加してください。

  • librechat-search-mcp/docker-compose.override.yml.example:librechat-search-mcp サービスを既存のComposeプロジェクトにマージします。内部専用で、expose: 8000を持ち、portsはなくコンポーズのデフォルトネットワークに参加します。

  • librechat-search-mcp/.env.example:このキーをメインのLibreChat .envに追加し、マーク付けされたプレースホルダーのみ一度に変更しています。既存のSearchセクション的直下に追加することをお勧めします。

MCP URL は http://librechat-search-mcp:8000/mcp です。クライアント理解しやすいよう、MCPから見えるサーバー名は chat-search のままです。LibreChatがプライベートMCP接続先をブロックする場合は、librechat.yaml.example の allowedAddresses/allowedDomains エントリを残してください。注意:空でないドメインホワイトリストは他のMCPサーバに影響する可能性があるため、意図的にマージしてください。

MEILI_HOST_PORT=7700 は、周辺のLibreChatデプロイが使用するホスト/Composeブリッジ変数です。MCPコンテナ自体はComposeのサービスURL http://meilisearch:${MEILI_HOST_PORT} を使用します(exampleのoverrideがその値を生成します)。LibreChatの既存の MEILI_HOST=http://0.0.0.0:7700 は別のホスト向け設定であり、軽易に置き換えないでください。

明示的な有効化のための(管理者)ユーザーIDを確認する

MEILI_MCP_ADMINSのユーザーIDは、以下の任意の方法で取得できます(通常は実行の簡単さの順):

  • ブラウザのUI:

  1. インスペクタ/開発者ツールを開き(Ctrl+Shift+I)、「Network」タブを選択します;

  2. Chat History の会話一覧から、過去の会話を選択します(ブラウザキャッシュにない可能性のある古めの会話を選ぶ必要があるかもしれません);

  3. Networking タブに記録された最初の API 呼び出しにより、その Response サブタブに会話ヘッダーのデータが読み込まれます。これには以下が含まれます:

    • user - **この値は、あなたのIDです**(このフィールドはサーバー内の検索の絞り込みや、admin_ ツールの target-user パラメータとして使用されます) - これをコピーして(選択した他の管理者/権限付与者にも同じ値を渡してもらう).env ファイル内の MEILI_MCP_ADMINS に入力します([リストはカンマのみで区切ること]);

    • conversationId - これは search_ MCP ツールのパラメータで使われるIDと同じもので、この値は会話のURL(http://localhost:3080/c/{conversationId})にも含まれていることに留意してください;

  4. this project の機能について興味深い点 - 3番目の API 呼び出しには、この会話のメッセージ一覧が含まれており、Meilisearch がそれらをインデックスする構造に似ています。このプロジェクトでは以下のキーを使用します:

    • conversationId - このプロジェクトでは、現在のチャットからの検索結果をデフォルトで除外したり、メッセージを対象に絞り込んだりするために使用

    • sender - 「User」またはエージェントの表示名

    • text - メッセージの内容

    • 将来の機能要望を考慮した調査事項:

      • endpoint(またはより対象を絞るなら model)は、MEILI_MCP_CONSTRAIN_ENDPOINT=true の設定と組み合わせることで、(プライベートモデル/エージェントとパブリックプロバイダーとを分離している場合)エンドポイントをまたいだメッセージ検索アクセスを防ぐフィルターとして使用できる

      • parentMessageId は、MCPトランスポートのヘッダー内の LibreChat の {{LIBRECHAT_BODY_PARENTMESSAGEID}} 動的変数を介して、ツール使用中に結果を絞り込むフィルタとしてすでに統合されています。私はこの検索インデックスを再調査して、検索ヒットメッセージからの前後バッファを対象にする方法、結果を決定的に順序付ける方法、メッセージチェーンをグラフ化する方法を研究する予定です

      • content - ツールコールの思考/推論を含みます(これがインデックス化された内容に含まれているのを見た記憶はありません。これには十分な理由があると思います。ユーザーのメッセージ履歴を検索するときに、ファイルやエージェント内部ではなく、タイトルやメッセージテキストに一致するヒットを期待するのは合理的です)

      • attachments - ツールコールの結果(場合によっては RAG やアップロードされたファイルの内容)を含みます。content と同様に、これがインデックス化されるとは期待していません

      • createdAt - 決定的な時間順序付け、あるいはフィルタリングキーとして利用できる可能性があります(Meili は既にヒットを見かけ上の時間順で返しますが、これも関連性スコアリングに影響される可能性があります)。また、Meili のインデックスドキュメントのメタデータ(インデックスが作成・更新されたタイムスタンプ)からも(わずかに異なる値ですが)アクセスできるかもしれません。ただし、ページインデックス操作を行うたびにその価値がすべて失われる可能性があります。

  • LibreChat コンテナログ(docker compose logs api)は、あなた(管理者ユーザー)が LibreChat UI で操作を行った直後のもの(注意:同時に多数のユーザーがいてログ結果を混同させてしまう場合には推奨できません。というのも、このログにはユーザー名が表示されないためです)

  • users テーブルを Mongo Express で調べる(個別にセットアップしている場合、Web UI の方が少し簡単です)

  • MongoDB の users テーブルを調べる(以下は bash でも PowerShell でも同じです。LibreChat ディレクトリ、または docker-compose.yml がある場所から実行してください):

# open a shell terminal within the MongoDB container - this assumes the default LibreChat service name `mongodb`:
docker compose exec mongodb sh

# open a database shell terminal within the container's shell:
mongosh

# switch to the database used by LibreChat (see all with `show databases`):
use LibreChat

# display target user by `role` attribute == "ADMIN" (LibreChat also stores `email` and `username` which may be present/null depending on registration method):
db.users.find({role: "ADMIN"}).forEach(printjson)
# Alternatively, display the entire users collection (be careful with this if you have many users):
db.users.find().forEach(printjson)
# the hash string in the first key of returned JSONs is the `user` ID - assuming you've found yourself/chosen admins, grab just this hash value from the `ObjectId` construct:
# {
#   _id: ObjectId('derp7bfe19e9268da678derp'), #### <- in this dummy example, derp7bfe19e9268da678derp is my user ID to add to MEILI_MCP_ADMINS ####
#   name: 'krahnik blis',
#   username: 'krahnik',
#   email: 'krahnik@emailmenot.derp',
#   ...

# quit the mongosh terminal
quit

# exit the mongodb container shell terminal
exit

MCPサーバー用に読み取り専用の権限付きキーを生成する

LibreChat の MEILI_MASTER_KEY を MEILI_MCP_KEY として使用しないでください!

このリポジトリには、APIキーを1つのコマンドで生成および検証するクロスプラットフォームのヘルパーが含まれています。 このヘルパーは meilisearch コンテナにアクセスする(つまり、コンテナが実行中である必要があります)ことで、権限付きキーを生成し、 デフォルトではキーを表示します。必要に応じてローカルファイルに出力することもでき、LibreChat のメインの .env を編集することはありません。 出力ファイル方式は任意であり、--force/-Force が指定されない限り、すでに存在する場合は拒否されます。生成された *.local.env ファイルは git によって無視され、プラットフォームが対応している場合には制限付きのアクセス権が設定されます。

LibreChat ディレクトリから、このリポジトリを git clone した後に実行してください:

bash:

# ensure the script is executable:
chmod +x librechat-search-mcp/scripts/generate-restricted-key.sh

# run the script in terminal mode:
./librechat-search-mcp/scripts/generate-restricted-key.sh
# OR, run it in file-output mode:
./librechat-search-mcp/scripts/generate-restricted-key.sh --output .librechat-search-mcp.local.env

PowerShell:

# run the script in terminal mode:
powershell.exe -ExecutionPolicy Bypass -File .\librechat-search-mcp\scripts\generate-restricted-key.ps1
# OR, run it in file-output mode:
powershell.exe -ExecutionPolicy Bypass -File .\librechat-search-mcp\scripts\generate-restricted-key.ps1 -Output .librechat-search-mcp.local.env

スクリプトの出力には、エンドポイント権限の検証テストと、読み取り専用権限を保証するためのダミー削除プローブが含まれます。読み取り専用の権限付きキーが最後に出力されるか、任意で指定したファイルに書き込まれます。

スクリプトには、私がデバッグで使用したチェックとメッセージが含まれています。これらは、将来のために残してありますので、そのまま利用できます:

[info] Working directory: /path/to/LibreChat
[info] Environment file: .env
[info] Meilisearch container: meilisearch
[info] Messages index: messages
[info] Conversations index: convos
[warning] MEILI_HOST used 0.0.0.0; using loopback for in-container requests.
[info] MEILI_HOST from .env: http://0.0.0.0:7700
[info] API URL used inside chat-meilisearch: http://127.0.0.1:7700
[info] MEILI_MASTER_KEY length: 32
[info] MEILI_MASTER_KEY SHA-256: d3907119a65e489d0202derp0ac65216a44derpb43bd8be71b7dderpb158ac67
[info] Testing Meilisearch connectivity from inside the container.
PASS  /health -> HTTP 200
[info] Testing the MEILI_MASTER_KEY read from .env.
PASS  .env master key accepted by /version
[info] Key contract payload: {"description":"LibreChat MCP search and read-only diagnostics","actions":["search","stats.get","metrics.get","indexes.get","settings.get","version"],"indexes":["messages","convos"],"expiresAt":null}
[info] Creating restricted key in chat-meilisearch.
[info] Restricted key created successfully.
[info] Generated key length: 64
[info] Validating read-only key contract.
PASS  /health -> HTTP 200
PASS  /version -> HTTP 200
PASS  /stats -> HTTP 200
FAIL  /metrics -> HTTP 400
		{"message":"Getting metrics requires enabling the `metrics` experimental feature. See https://github.com/meilisearch/product/discussions/625","code":"feature_not_enabled","type":"invalid_request","link":"https://docs.meilisearch.com/errors#feature_not_enabled"}
PASS  /indexes -> HTTP 200
PASS  /indexes/messages/settings -> HTTP 200
PASS  /indexes/convos/settings -> HTTP 200
[info] Testing that document deletion is rejected.
PASS  DELETE /indexes/messages/documents/__mcp_read_only_probe__ -> HTTP 403

Restricted key was created, but one or more validation checks failed:
- /metrics returned HTTP 400

The key will still be returned below. Do not deploy it until the failures are understood.
394ederp18e6299f7fddderpbb485b77be7bb1d0906b29ade8derpebaf65de43

^ このダミー例では、394ederp18e6299f7fddderpbb485b77be7bb1d0906b29ade8derpebaf65de43 が、LibreChat の .env で MEILI_MCP_KEY として使用するキーです。

想定される FAIL メッセージ

現在、/metrics エンドポイントは、LibreChat で使用されている Meilisearch のバージョンでは実験的機能であるため、失敗することを想定しています。将来、有効にするための有益な内容が見つかった場合は、手順やスクリプトをリポジトリに更新する可能性があります。つまり get_index_metrics ツールは、ご自身でこの機能を有効にしない限り、上記のスクリプト出力例に表示されているエラーを返します。

以下は、generate-restricted-key スクリプトが行う内容を手動で実行する方法です。 実装をカスタマイズしていたり、エラーが発生した場合に使ってください(または、詳細な理屈を知りたい場合はスクリプトを参照してください):

このサービス専用の読み取り専用キーを1つ作成します。その正確なアクション契約は:

  • search

  • stats.get

  • metrics.get

  • indexes.get

  • settings.get

  • version

キーを、設定済みの2つのインデックス(messages と convos、または設定した名前)に範囲指定します。グローバルヘルスエンドポイントは別途確認され、書き込み可能なロールを必要としません。expiresAt に null を設定するのは、意図的に期限切れしない運用キーをそのときだけに限定してください。返されたキーは MEILI_MCP_KEY にのみ保存します。

キーは chat-meilisearch(docker exec)/meilisearch(docker compose exec)コンテナのターミナルから作成します。MCP実行用コンテナからは作成しないでください。以下のマスターキーはコマンド履歴中のプレースホルダーであり、プロンプト、ログ、このリポジトリへ貼り付けてはなりません:

curl -fsS -X POST "http://127.0.0.1:7700/keys" \
-H "Authorization: Bearer $MEILI_MASTER_KEY" \
-H "Content-Type: application/json" \
--data '{"description":"LibreChat MCP search and read-only diagnostics","actions":["search","stats.get","metrics.get","indexes.get","settings.get","version"],"indexes":["messages","convos"],"expiresAt":null}'

documents.*、indexes.create、indexes.delete、settings.* 書き込みアクション、keys.*、tasks.cancel、* を追加してはなりません。MEILI_MCP_KEY を MEILI_MASTER_KEY と等しくしないでください。

キーをデプロイする前に、次の読み取り専用プローブで契約を確認します。どれも HTTP 200 を返す必要があります(JSON は意図的に無視されます):

auth=(-H "Authorization: Bearer $MEILI_MCP_KEY" -H "Accept: application/json")
for path in /health /version /stats /metrics /indexes /indexes/messages/settings /indexes/convos/settings; do
code=$(curl -sS -o /dev/null -w '%{http_code}' "${auth[@]}" "http://127.0.0.1:7700/$path")
test "$code" = 200 || { printf 'unexpected %s: HTTP %s\n' "$path" "$code" >&2; exit 1; }
done

次に、無害な削除プローブが拒否されることを確認します。存在しないセンチネルドキュメント ID を使用してください。これを実際のドキュメント ID に置き換えないでください:

code=$(curl -sS -o /dev/null -w '%{http_code}' -X DELETE \
"${auth[@]}" "http://127.0.0.1:7700/indexes/messages/documents/__mcp_read_only_probe__")
case "$code" in 401|403) ;; *) printf 'write permission was not rejected: HTTP %s\n' "$code" >&2; exit 1;; esac

同じキーは MCP 検索パスと診断パスの両方で使用されます。読み取り専用プローブが 401/403 を返す場合は、キーのアクション契約またはインデックス範囲を修正してください。書き込みが拒否されるまで、マスターキーに置き換えたり、権限を広げたりしないでください。

キーが増え過ぎてしまった場合の削除

注意:上記のスクリプト/コマンドを複数回実行すると、Meilisearch 内に複数の孤立キーが作成されます。やらないことをお勧めします。ただし、もし実行してしまった場合には、

  • コンテナ内にマスターキーの環境変数を設定するか、以下の $MEILI_MASTER_KEY の部分を実際のキーに置き換えてください

  • メインの Meilisearch コンテナ内のターミナルから、まずすべてのキーを一覧表示します:curl -sS -H "Authorization: Bearer $MEILI_MASTER_KEY" "http://127.0.0.1:7700/keys"

  • このプロジェクトの作成スクリプトがラベル付けしたキーを探してください。それらには description として「LibreChat MCP search and read-only diagnostics」とあります

  • 保持するキー以外のものを選択し、その uid を取得します

  • 削除するキーごとに実行します(KEY_UID を実際の値に置き換えてください):curl -sS -X DELETE -H "Authorization: Bearer $MEILI_MASTER_KEY" "http://127.0.0.1:7700/keys/KEY_UID"

セットアップ全体のコマンドシーケンス

以下のコマンドを1つずつ対話形式で実行してください(言うまでもなく、Windows ユーザーは cat/nano まどは気にせず、notepad や IDE を使えばいいです):

cd LibreChat

# this creates the folder librechat-search-mcp WITHIN the LibreChat Compose scope:
git clone https://github.com/krahnikblis/librechat-search-mcp.git

# assuming the baseline LibreChat Compose services are already running, this creates & tests the restricted API key to set manually into the LibreChat .env MEILI_MCP_KEY:
# see above/README page for details and/or PowerShell equivalent commands
# either write to a local file:
./librechat-search-mcp/scripts/generate-restricted-key.sh --output .librechat-search-mcp.local.env
# OR print to the terminal:
./librechat-search-mcp/scripts/generate-restricted-key.sh

# print the example to copy as template:
cat librechat-search-mcp/.env.example
# copy or merge the example MEILI_MCP_ variables, including the key generated in the prior step into .env:
nano .env

# print the example to copy as template:
cat librechat-search-mcp/docker-compose.override.yml.example
# copy or merge the example configurations from the example into docker-compose.override.yml
nano docker-compose.override.yml

# print the example to copy as template:
cat librechat-search-mcp/librechat.yaml.example
# copy or merge the MCP [and optional agent capabilities and memory agent changes] configurations into librechat.yaml:
nano librechat.yaml

# validate config:
docker compose config

# stop existing services to recreate the LibreChat container with the MCP settings:
docker compose down

# build the image:
docker compose build librechat-search-mcp

# start all Compose services together:
docker compose up -d

# check logs for the new service:
docker compose logs --tail=100 librechat-search-mcp

うまくいけば、この MCP が LibreChat UI で利用できるようになります!

環境とインデックスの契約

必要なもの:

MEILI_MCP_KEY=<restricted-search-key>
MEILI_MCP_ADMINS=<admin,list>

.env の中の重要な値:

MEILI_HOST_PORT=7700
MEILI_MCP_PORT=8000
MEILI_MCP_MESSAGES_INDEX=messages
MEILI_MCP_CONVOS_INDEX=convos
MEILI_MCP_DEFAULT_LIMIT=5
MEILI_MCP_MAX_LIMIT=25
MEILI_MCP_ADMIN_SCOPE_ALL_USERS=false
MEILI_MCP_LOG_HOST_DIR=<local/log/path>

両方のインデックスには、フィルタ可能な user 属性が必要です(LibreChat の設計で既に存在します)。 LibreChat が作成するメッセージのインデックスには、フィルタ可能な conversationId はありません。 この属性と、MCP 検索ツールのその他のパラメータは、呼び出し元に返す前にサーバー側で処理されます。

ログのマウントと永続性

コンテナは、構造化された JSON 行のログを /var/log/librechat-search-mcp に書き込みます。 Compose の例では、そのディレクトリを ${MEILI_MCP_LOG_HOST_DIR} にバインドマウントしています。 デフォルトは、親の LibreChat Compose プロジェクト相対の ./librechat-search-mcp/logs です。ログファイル名は librechat-search-mcp-YYYY-MM-DD.log という形なので、 コンテナを再作成しても既存のホスト側ログは削除されません。このホストディレクトリをプライベートに対してて、デプロイメントのポリシーに応じてバックアップまたはローテーションしてください。 代わりに親プロジェクトの慣用的なログディレクトリを使うには、ローカルの .env 内で MEILI_MCP_LOG_HOST_DIR=./logs を設定してください。そのファイル(この設定値が入ったもの)や生成されたログをコミットしないでください。

librechat-search-mcp コンテナ内で読み取り専用の契約チェックを実行します:

bash/PowerShell:

# The image's WORKDIR is /app and Compose injects MEILI_HOST plus the
# restricted MEILI_MCP_KEY into the service.
# the script was copied into the container as part of image build
docker compose exec -T -w /app librechat-search-mcp python scripts/check_index_contract.py

このスクリプトは、/app/scripts/check_index_contract.py としてイメージ内にコピーされています。 このスクリプトは、設定を変更したりキーを出力したりせずに、ヘルス、インデックス名、プライマリキー、フィルタ可能属性、ソート可能属性を確認します。 終了ステータス 0 と JSON の "status": "pass" は契約が合格であることを意味します。ゼロ以外の終了ステータスは、報告されたヘルス、インデックス、設定、または必須フィルタチェックが失敗したことを意味します。 これは診断用であり、MCP の準備性を確認するものではありません。/health は MCP プロセスが生存していることを示すだけです。

ここからの呼び出しプロンプトと期待される動作

構成後、コンテナが動作している状態で新しい LibreChat の会話を開始してください(例:UI の MCP サイドバー、Agent Builder、チャットボックスの MCP Servers ドロップダウン)。 これにより、モデルが現在のツールリストを発見できます。

ツールの説明は、標準の検索ツールをエージェントが積極的に使うように促す書き方にしています。一方 admin_ のものは「ユーザーが最初に呼び出すように使います」という指示を入れています。将来はこの指示を経験に基づいて調整する可能性が高いです。既に、必要ないのに使われすぎ、またはその装定が広すぎるように思える、興味深いプロアクティブな使用事例を確認できています...

注意:小さいローカルモデルでは、プロンプト内でツール名を明示的に指定する必要がある場合があります。

通常検索 - 明示的な指示:

Use search_conversations with query "deployment" and limit 3. Return only conversationId, title, and tags.
Use search_messages with query "deployment" and limit 3. Return only messageId, conversationId, sender, and text.

通常検索のプロアクティブな使用意図:

Hey remember that time we went wild designing a giant robotic grackle? I have some ideas about how to combine it with the ornithopter we discussed last week...

エージェントは、タグ grackle ornithopter に類似するクエリを自ら実行し、複数の会話から一致するメッセージを見ることができるはずです。

意図した検索エージェント設計:

このツールは標準的なセットアップとツールの説明を含んでいますが、本当の面白さは、専用エージェントや、メモリのような動作を形作るための有意義な SKILL.md を構築することにあります。これらのツールが返す結果は完全なメッセージであるため、トークンコストは十分高くなり得ます。そのため、より安価なモデルで構築されたサブエージェントに、相互接続された会話全体でトピックを再帰的に辿り、詳細な要約/統合を返す指示を与えることが、おそらく自分のチームにデフォルトエージェントとしてデプロイする方法になるでしょう。

対象を絞った管理者監査(許可されたアカウントからのみ):

To-do list では、LibreChat の PeoplePicker API を調べて、それが Compose ネットワーク内でどのように公開されているか(または公開されているかどうか)を確認する予定です。理想的には、管理者がハンドル名やファーストネームでユーザーを指定できるようになり、PeoplePicker が有効になっていれば、エージェントが内部 ID を検索できるようになるといいでしょう(あるいは、エージェントを経由せずに、サーバー側で検索・絞り込み・エラー処理を行い、例えば「『Sally』が2件見つかりました。もしかして Sally X. か Sally Y. ですか?」のように判定することも可能かもしれません)※ただし、エージェントにはメールアドレスや氏名を公開しません。

Use admin_search_messages for target user "<target-user-id>" with query "deployment" and limit 3.

想定される管理者のスコープ(デバッグ、プロンプト/会話の最適化、集団的な注意)

What are our team members saying overall about our company's brand presense in the FIFA World Cup?
Let's review <target-user-id>'s conversation <conversationId> - what initial prompt and context would have elicited the final answer more directly?

境界チェック:

Try to search another user's messages by supplying a user argument and a raw filter. Do not bypass the tool schema; report whether the request was rejected and do not return cross-user results.
Find messages before and after this hit using createdAt, reconstruct surrounding messages through MongoDB, and sort by timestamp.

後者は 非対応 です。このプロジェクトでは、タイムスタンプの並び順、前/後取得、MongoDB/API 検索、周辺メッセージの再構成、任意のソートは追加しません。送信者フィルタと会話フィルタは結果を絞るだけのポストフィルタであるため、要求された上限件数未満でも有効で、Meilisearch の元のヒット順序は保持されます。

検証

ローカルチェック(LibreChat 内のこのプロジェクトのフォルダ内で実施):

python -m pytest tests/test_monitoring.py tests/test_m2_contract.py tests/test_m2_authorization.py tests/test_m1_search.py tests/test_server.py -q
python -m compileall -q src scripts tests
git diff --check

デプロイ確認には起動中の LibreChat/Meilisearch スタックが引き続き必要です。新しいセッションでのツール検出、User-Id ヘッダー、制限付きキーの権限、インデックスの契約、ホストポートの非公開、2 人のユーザーによる同時リクエストを確認してください。ローカルの単体テストを、実際の呼び出し動作の証明として扱わないでください。

デプロイとトラブルシューティング

  • サポート対象の Docker Compose の境界、安全な設定の投入順序、サービス ID、container_name のトレードオフについては、docs/deployment.md を参照してください。

  • 一般的な Compose、キー生成、ネットワーク接続、MCP ディスカバリ、インデックス、ロギングの障害については、docs/troubleshooting.md を参照してください。

  • サービスを有効化する前に SECURITY.md を参照してください。ここには、インデックス化される内容、AI プロバイダへの露出、識別と管理者の範囲、ログ/保存、制限付きキー、信頼境界、このプロジェクトが保証しないことなどが記載されています。

開発

  • エージェント向けのツール契約は docs/tool-descriptions.md を参照してください。

  • 上流の出所とライセンスは ATTRIBUTION.md を参照してください。

  • 開発、計画、監査、内部の意思決定記録は、意図的にはあくまでも、本番リポジトリの外の workspace/project-context/librechat-search-mcp/development-records/ に保持されています。

つまり、もし誰かが コントリビュート したいのならば、Discussion や Issue でも何でも開いてください。Contributing セクションを追加して、PR の仕組みを学ぶのもありがたく思います…が、実際にはこれは単に自分の趣味のプロジェクトであり、仕事にもとても価値があることも分かっています。ここからあちらへ渡る最も簡単な経路は、GitHub で公開することです。つまり、私はものづくりや問題解決が好きですが、だからといって誰かの Issue に注意を払う約束はありません。おそらく素晴らしい機能を実現できるか、自分の不足を埋めるかを優先するでしょう。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Persistent, searchable memory for AI agents. Enables agents to recover context after compaction by searching indexed conversations, emails, and files via MCP tools.
    1
    MIT
  • F
    license
    Not graded
    quality
    F
    maintenance
    Enables AI coding agents to persistently store and retrieve conversation history with hybrid semantic and keyword search, cross-encoder reranking, session filtering, and archiving through MCP tools.
    -
  • A
    license
    A
    quality
    B
    maintenance
    Enables MCP-capable coding agents to semantically search, store, and inspect a single local, cross-tool index of session histories and project docs. Agents can retrieve what other tools and prior sessions already discovered.
    3
    MIT