Elasticsearchで大規模なナレッジベースを扱う場合、情報を見つけるだけでは片手落ちです。エンジニアは複数の文書から結果を統合し、要約を作成し、回答を情報源にたどる必要があることが多いです。モデルコンテキストプロトコル(MCP)は、Elasticsearchと大規模言語モデル(LLM)アプリケーションを接続するための標準化された方法を提供します。ElasticはElastic Agent Builder(MCPエンドポイントを機能の一つに含む)のような公式ソリューションを提供していますが、カスタムMCPサーバーを構築することで、検索ロジック、結果のフォーマット、取得したコンテンツをLLMに渡して合成、要約、引用を行う方法などを完全に制御できます。
この記事では、カスタムElasticsearch MCPサーバーを構築するメリットを探り、ElasticsearchをLLM対応アプリケーションに接続するサーバーをTypeScriptで作成する方法を紹介します。
カスタムのElasticsearch MCPサーバーを構築する理由
ElasticはMCPサーバーのいくつかの代替手段を提供しています。
MCPサーバーとElasticsearchの連携方法をより細かく制御したい場合は、独自のカスタムサーバーを構築することで、ニーズに合わせて柔軟にカスタマイズできます。例えば、Agent BuilderのMCPエンドポイントはElasticsearchクエリ言語(ES|QL)クエリに限定されていますが、カスタムサーバーでは完全なクエリDSLを使用できます。また、LLMに渡される前に結果をどのようにフォーマットするかを制御でき、このチュートリアルで実装するOpenAIを利用した要約など、追加の処理ステップを統合することもできます。
この記事を読み終える頃には、Elasticsearchインデックスに保存されている情報を検索し、要約し、引用を提供するTypeScriptで記述されたMCPサーバーが完成しているでしょう。Elasticsearchを使用して情報を検索し、OpenAIのgpt-4o-miniモデルを用いて要約と引用を生成し、Claude DesktopをMCPクライアントおよびUIとして活用してユーザーのクエリを受け取り、応答を提供します。最終的には、エンジニアが組織内の技術文書全体からベストプラクティスを発見し、統合するのに役立つ内部ナレッジアシスタントが完成します。

要件:
- Node.js 20 +
- Elasticsearch
- OpenAI APIキー
- Claude Desktop
MCPとは何ですか?
MCPはAnthropicによって作成されたオープンスタンダードで、LLMとElasticsearchのような外部システムとの間で安全かつ双方向の接続を提供します。MCP の現状についてはこの記事で詳しく読むことができます。
MCPの環境は日々進化しており、多様なユースケースに対応したサーバーが利用可能です。さらに、この記事でご紹介するように、独自のカスタムMCPサーバーを簡単に構築することもできます。
MCPクライアント
利用可能なMCPクライアントは多数あり、それぞれに特徴や制限があります。簡便性と普及度を考慮し、今回はMCPクライアントとしてClaude Desktopを使用します。これは、ユーザーが自然言語で質問できるチャットインターフェースとして機能し、MCPサーバーが公開しているツールを自動的に呼び出して、文書を検索し、要約を生成します。

Elasticsearch MCPサーバーの作成
TypeScript SDKを使えば、ユーザーのクエリ入力に基づいてElasticsearchデータのクエリ方法を理解するサーバーを簡単に作成できます。
この記事では、Elasticsearch MCPサーバーとClaude Desktopクライアントを統合するための手順を説明します。
Elasticsearch MCPサーバーを設定してください
まず、Nodeアプリケーションを初期化します。
これで package.jsonファイルが作成され、このアプリケーションに必要な依存関係のインストールを開始できます。
- @elastic/elasticsearch はElasticsearchのNode.jsライブラリにアクセスするためのものです。
- @modelcontextprotocol/sdkは、MCPサーバーの作成と管理、ツールの登録、MCPクライアントとの通信処理を行うためのコアツールを提供します。
- openaiは、OpenAIのモデルと対話し、要約や自然言語による対応を生成することができます。
- zodは、各ツールの入出力データの構造化スキーマの定義と検証に役立ちます。
ts-node、@types/node、 typescriptは開発中にコードの入力やスクリプトのコンパイルに使用されます。
データセットを設定
Claude DesktopがMCPサーバーを使用してクエリできるデータを提供するために、内部の模擬ナレッジベースデータセットを使用します。このデータセットから作成される文書は以下のような形式になります。
データを取り込むために、Elasticsearchにインデックスを作成し、そこにデータセットをロードするスクリプトを用意しました。こちらでご覧いただけます。
MCPサーバー
index.tsというファイルを作成し、依存関係をインポートして環境変数を処理するための以下のコードを追加します。
また、ElasticsearchとOpenAIの呼び出しを処理するようにクライアントを初期化します。
実装をより堅牢にし、構造化された入出力を保証するために、 zodを使用してスキーマを定義します。これにより、ランタイムでデータを検証し、エラーを早期に捕捉し、ツールの対応をプログラムで処理しやすくすることができます。
構造化出力の詳細については、こちらをご覧ください。
それでは、MCPサーバーを初期化しましょう。
MCPツールの定義
すべての設定が完了したので、MCPサーバーによって公開されるツールの作成を開始できます。このサーバーは2つのツールを公開します。
search_docs:Elasticsearchで文書を全文検索で検索します。summarize_and_cite:以前に取得した文書から情報を要約・統合し、ユーザーの質問に答えます。このツールは、出典となる文書を参照する引用も追加します。
これらのツールを組み合わせることで、シンプルな「検索してから要約」ワークフローが構築されます。一方のツールが関連文書を取得し、もう一方のツールがその文書を使用して要約と引用を含む回答を生成します。
ツールの応答形式
各ツールは任意の入力パラメータを受け入れることができますが、以下の構造で応答する必要があります。
- Content: これは非構造化形式でのツールの応答です。このフィールドは通常、テキスト、画像、音声、リンク、または埋め込みを返すために使用されます。この用途では、ツールによって生成された情報を含む整形済みテキストを返すために使用されます。
- structuredContent:これは、各ツールの結果を構造化された形式で提供するために使用されるオプションの戻り値です。これはプログラム上の目的に役立ちます。このMCPサーバーでは使用されていませんが、他のツールを開発したり、結果をプログラムで処理したりする場合に便利です。
その構造を念頭に置いて、各ツールについて詳しく見ていきましょう。
Search_docsツール
このツールは、Elasticsearchインデックスで全文検索を実行し、ユーザークエリに基づいて最も関連性の高いドキュメントを取得します。主要な一致をハイライトし、関連性スコアを素早くまとめてくれます。
fuzziness: “AUTO” は 分析対象のトークンの長さに応じて誤字許容度を調整するように設定しています。また 、 タイトルフィールドで一致が発生したドキュメントのスコアを上げるtitle^2も設定しました。。
summarize_and_citeツール
このツールは、前回の検索で取得したドキュメントに基づいて要約を生成します。OpenAIの gpt-4o-miniモデルを使用して、ユーザーの質問に答えるために最も関連性の高い情報を統合し、検索結果に直接基づく回答を提供します。要約に加えて、使用したソースドキュメントの引用情報(メタデータ)も返します。
最後に、stdioを使用してサーバーを起動する必要があります。つまり、MCPクライアントは、標準の入出力ストリームを読み書きすることでサーバーと通信します。stdioは最もシンプルな転送オプションで、クライアントによってサブプロセスとして立ち上げられるローカルMCPサーバーに適しています。ファイルの最後に以下のコードを追加します。
次に、以下のコマンドを使用してプロジェクトをコンパイルします。
これによりdistフォルダが作成され、その中にindex.jsファイルが作成されます。
MCPサーバーをClaude Desktopにロード
Claude DesktopでMCPサーバーを設定するには、このガイドに従ってください。Claudeの設定ファイルでは、以下の値を設定する必要があります:
args値は、 distフォルダ内のコンパイル済みファイルを指す必要があります。また、設定ファイル内の環境変数も、コード内で定義されているものと全く同じ名前で設定する必要があります。
試してみる
各ツールを実行する前に、「検索とツール」をクリックして、ツールが有効になっていることを確認します。ここでは、それぞれを有効または無効にすることもできます。

最後に、Claude DesktopのチャットからMCPサーバーをテストして、質問を始めましょう。

「認証方法とRBACに関する文書を検索する」という質問に対して、search_docs ツールが実行され、以下の結果が返されます。
回答は「素晴らしい!認証方法とロールベースのアクセス制御に関する関連文書を5件見つけました。見つかった内容は以下のとおりです。」
ツール呼び出しは、対応ペイロードの一部としてソース文書を返します。これらの文書は、後に引用を生成するために使用されます。

また、複数のツールを一度のインタラクションで連結することも可能です。この場合、Claude Desktopはユーザーの質問を分析し、まずsearch_docsを呼び出して関連文書を取得し、次にその結果をsummarize_and_citeに渡して最終的な回答を生成する必要があると判断します。これらすべては、ユーザーからの個別のプロンプトを必要とせずに実行されます。

この場合、「システム全体の認証とアクセス制御を改善するための主な推奨事項は何ですか?参考文献を含めてください。」というクエリに対して、以下の結果が得られました。
前のステップと同様に、この質問に対する各ツールの回答を確認できます。

注:各ツールの使用を承認するかを確認するサブメニューが表示された場合は、「常に許可」または「一度だけ許可」を選択します。

まとめ
MCPサーバーは、ローカルとリモートの両方のアプリケーションのLLMツールの標準化に向けた重要な一歩です。完全な互換性の実現にはまだ取り組んでいますが、その方向へ急速に進んでいます。
この記事では、ElasticsearchをLLM搭載アプリケーションに接続するカスタムMCPサーバーをTypeScriptで構築する方法を学びました。当サーバーは2つのツールを提供しています。1つはQuery DSLを使用して関連文書を取得するためのツールsearch_docs、もう1つはOpenAIモデルとクライアントUIとしてのClaude Desktopを使用して引用付きの要約を生成するためのツールsummarize_and_citeです。
異なるクライアントとサーバープロバイダー間の互換性の将来は有望に見えます。次のステップは、エージェントにより多くの機能と柔軟性を加えることです。実用的な記事で、検索テンプレートを使用してクエリをパラメーター化し、精度と柔軟性を得る方法を学ぶことができます。




