esmole について
esmoleは、Elasticsearch 7.xと8.xのクラスターを管理するAIエージェント向けstdio MCPサーバーです。実行中の接続変更、プロジェクト単位またはグローバルの保存、読み取り制限付きSSHトンネルに対応します。
主な機能
- 01名前付きクラスターの実行時管理
- 02Elasticsearch 7.xと8.xへの対応
- 03プロジェクト別・グローバル接続保存
- 04ホスト鍵検証付きSSHトンネル
- 05読み取り専用の許可リストと応答制限
活用シーン
- 01エージェントのセッション中にプロジェクト接続を追加・変更
- 02SSH踏み台経由でElasticsearchを検索
- 03エージェント接続を許可済み読み取りエンドポイントに限定
MCP 対応
MCPクライアントにElasticsearchの接続管理ツールとクエリツールを提供します。各ツール呼び出し時に接続設定を再読み込みするため、サーバーの再起動なしで変更が反映されます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
10掲載時のツール一覧 · 3 日前に更新
このツールにパラメーターはありません。
詳細
esmole-mcp
自身で接続を管理する AI エージェント向けの Elasticsearch 7.x および 8.x:MCP ツールを通じて、実行時にプロジェクトごとにクラスターを追加、編集、削除でき、SSH 経由でホットリロードされます。
esmole-mcp は Elasticsearch 用の stdio MCP サーバーです。エージェントに「bastion.example.com 経由でログクラスターに読み取り専用で接続して」と伝えると、エージェントは
add_connection を呼び出します。接続はプロジェクトごとの .esmole.json またはグローバルストアに保存され、どちらもツールを呼び出すたびに再読み込みされるため、エージェント、エディターでのユーザー操作、別のセッションによる変更が次の呼び出しに反映されます。クライアント設定の編集も再起動も不要です。
- Elasticsearch 7.x および 8.x に対応し、名前付きクラスターをいくつでも登録できます。API キーまたは基本認証を使用できます。
- パスワード、鍵、またはエージェント認証による SSH トンネルに対応します。ホストキーは
known_hostsまたはピン留めしたフィンガープリントと照合して検証されます。 readonly接続では、読み取りエンドポイントの許可リスト、絶対リクエストタイムアウト、10 MB のレスポンス上限を適用し、結果を 40 KB に制限することで、大きな集計結果がコンテキストを埋め尽くすのを防ぎます。
PostgreSQL または MySQL が必要ですか?dbmole-mcp は、SQL データベース向けの同じ設計を採用しています。
デモ

インストール
Node.js 22 以降が必要です。サーバーは起動時に設定不要です。接続は後から追加します。
Claude Code
claude mcp add esmole -- npx -y esmole-mcp
すべてのプロジェクトで有効にするには、--scope user を追加します。または、プラグインとしてインストールすることもできます(Claude Code 2.1.275 以降)。
/plugin install esmole --marketplace ed-smartass/esmole-mcp
Codex
codex mcp add esmole -- npx -y esmole-mcp
または、~/.codex/config.toml に追加します。
[mcp_servers.esmole]
command = "npx"
args = ["-y", "esmole-mcp"]
Cursor
VS Code
Claude Desktop
最新リリースから esmole-mcp-<version>.mcpb をダウンロードして開くか、以下の JSON を claude_desktop_config.json に追加します。Claude Desktop はプロジェクト内でサーバーを起動しないため、接続はグローバルストア(デフォルトのスコープ)に保存してください。
その他の MCP クライアント
{
"mcpServers": {
"esmole": { "command": "npx", "args": ["-y", "esmole-mcp"] }
}
}
Docker
イメージはソースからビルドします。
git clone https://github.com/ed-smartass/esmole-mcp.git && cd esmole-mcp
docker build -t esmole-mcp .
{
"mcpServers": {
"esmole": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "esmole-store:/home/node/.config/esmole",
"-v", "/abs/path/to/project:/work",
"-v", "/home/me/.ssh/known_hosts:/home/node/.ssh/known_hosts:ro",
"esmole-mcp"
]
}
}
}
コンテナーは node ユーザーとして、作業ディレクトリ /work で実行されます。プロジェクトの .esmole.json を使うには、プロジェクトをそこにマウントしてください。名前付きボリュームにはグローバルストアが保持されます。SSH 接続用に known_hosts(または ssh.hostKey をピン留め)をマウントし、privateKeyPath で参照する秘密鍵も、接続で指定したパスにマウントしてください。ssh.agent: true の場合は、エージェントソケットを転送します(-v "$SSH_AUTH_SOCK:/ssh-agent" -e SSH_AUTH_SOCK=/ssh-agent)。マシンからしかアクセスできないホストに接続するには、--add-host=host.docker.internal:host-gateway(Linux)を追加し、host.docker.internal を使用します。イメージには git が含まれていないため、「git によって無視されていない」かどうかのチェックでは常に警告が表示されます。
0.1 の設定で ESMOLE_CONNECTIONS、ESMOLE_CONFIG、または --config が指定されていても起動できます。サーバーは stderr に、それらが無視されたことを示す 1 行を出力します。変更履歴を参照してください。
クイックスタート
たとえば、エージェントに次のように依頼します。
このプロジェクトに
logsという読み取り専用の Elasticsearch 接続を追加してください。10.0.0.20 の https を使用し、API キーは VnVhQ2ZH…です。ssh agent を使って [email protected] 経由で接続してください。その後、最も大きいインデックスを 5 つ表示してください。
エージェントは add_connection を次の内容で呼び出します。
{
"name": "logs",
"host": "10.0.0.20",
"apiKey": "VnVhQ2ZH…",
"readonly": true,
"ssh": { "host": "bastion.example.com", "user": "deploy", "agent": true },
"scope": "project"
}
続いて test_connection と es_list_indices を呼び出します。チャットに入力した認証情報はモデルのコンテキストを経由します。本番環境のシークレットについては、自分でファイルにエントリーを書き込んでください。
接続
2 つのレイヤー
| レイヤー | ファイル | 形式 |
|---|---|---|
project | サーバーの作業ディレクトリから検索される .esmole.json | { "connections": [ ... ] } |
global | ~/.config/esmole/connections.json、または ESMOLE_STORE で指定したパス | [ ... ] |
- 両方に同じ名前がある場合、プロジェクトのエントリーが優先されます。
list_connectionsは各接続のsource(projectまたはglobal)を報告し、もう一方のレイヤーに同じ名前のエントリーがあり、それを隠している場合はshadowsも報告します。 - ホットリロード。 どちらのファイルも、ツールを呼び出すたびに再読み込みされます。セッション中にファイルを編集すると、次の呼び出しから新しい設定が使われます。接続が変更されると、新しいクライアントが作成され、古いクライアントは閉じられます。
- プロジェクトファイルの検出。 サーバーの作業ディレクトリ(Claude Code と Codex はプロジェクトディレクトリでサーバーを起動します)からファイルシステムのルートまで上にたどり、最初に見つかった
.esmole.jsonを使用します。独自のファイルがないリンクされた git worktree では、メインのチェックアウトにある.esmole.jsonにフォールバックするため、リポジトリ内のすべての worktree で 1 つのファイルが共有されます。 - どちらのファイルも、モード
0600のプレーンな JSON で、アトミックに書き込まれます。書き込み時には、解析できないエントリーはそのまま保持し、無効な JSON のファイルへの上書きは拒否します。
ツールで接続を管理する
add_connectionは、接続フィールドとscopeを受け取ります。scopeは"global"(デフォルト)または"project"です。projectを指定していて、まだファイルがない場合は、メインのチェックアウトルート (または Git ルート、Git 管理外の場合は作業ディレクトリ)にファイルが作成されます。Git がこのファイルを無視しない場合は、 応答で警告されます。認証情報がコミットされないよう、.esmole.jsonを.gitignoreに追加してください。add_connectionは、対象レイヤーに同じ名前がすでに存在する場合は失敗します。もう一方のレイヤーに同じ名前がある場合は 登録でき、応答でどのエントリがどのエントリをシャドーイングするかが示されます。update_connectionは、接続が存在するレイヤー(優先されるレイヤー)で接続を更新します。nullを指定すると、任意フィールドが削除されます。sshオブジェクトは保存済みのものにフィールドごとにマージされるため、{ "ssh": { "hostKey": "SHA256:..." } }を指定しても、保存済みの SSH シークレットは保持されます。remove_connectionはそのレイヤーから接続を削除し、もう一方のレイヤーに同じ名前のエントリがあれば、それが表示されるようになることを通知します。- 認証情報がそのまま返されることはありません。
list_connectionsには、スキーム、ホスト、ポート、認証の種類、verifyTls、readonly、source、SSH が使用されているかどうかが表示されます。
破損したエントリと無効なエントリ
- 検証に失敗したエントリが黙って無視されることはありません。同じ名前のエントリがグローバルストアにあっても、
その名前を解決するとエラー(
connection 'x' in <file> is invalid: ...)になり、list_connectionsには無効として表示されます。 1 つのファイル内で同じ名前が重複して定義されている場合もエラーになります。remove_connectionで無効なエントリを削除できます。 - ファイルが存在するものの、読み取れない、JSON 形式ではない、または形状が正しくない場合は、
list_connectionsのbrokenLayersに報告されます。破損したプロジェクトファイルはすべての接続をブロックします。破損したグローバルストアは、 プロジェクトファイルで定義されていない名前のみをブロックします。ファイルが存在しない場合は空として扱われます。
接続フィールド
不明なフィールドは拒否されます。認証情報は必須です。apiKey、または user と
password の両方を指定してください。
| フィールド | 型 | 備考 |
|---|---|---|
name | string | [a-zA-Z0-9_-]+ |
type | elasticsearch | デフォルトは elasticsearch |
host | string | ssh が設定されている場合は、SSH 踏み台から見たホスト |
port | number | デフォルトは 9200 |
scheme | http | https | デフォルトは https |
verifyTls | boolean | デフォルトは true。false の場合は証明書の検証を省略します |
apiKey | string | API キー(base64 の id:key 形式) |
user、password | string | Basic 認証 |
readonly | boolean | デフォルトは false。読み取り専用を参照してください |
queryTimeoutMs | integer | ミリ秒単位。デフォルトは 60000、最大値は 2147483647。制限とタイムアウトを参照してください |
ssh | object | SSH トンネルを参照してください |
.esmole.json の例:
{
"connections": [
{ "name": "local", "host": "localhost", "scheme": "http", "user": "elastic", "password": "changeme" },
{
"name": "logs",
"host": "10.0.0.20",
"apiKey": "VnVhQ2ZHY0JDZGJrUW0t...",
"readonly": true,
"ssh": { "host": "bastion.example.com", "user": "deploy", "agent": true }
}
]
}
SSH トンネル
ssh フィールド | 備考 |
|---|---|
host、port | 踏み台サーバー。ポートのデフォルトは 22 です |
user | SSH ユーザー |
password | パスワード認証 |
privateKey / privateKeyPath | キーの内容、またはパス(~ は展開されます) |
passphrase | 暗号化されたキー用 |
agent | true にすると、SSH_AUTH_SOCK のエージェントを使用します |
hostKey | 固定するホストキーのフィンガープリント。SHA256:...(OpenSSH 形式) |
{ "host": "bastion.example.com", "user": "deploy", "privateKeyPath": "~/.ssh/id_ed25519" }
{ "host": "bastion.example.com", "user": "deploy", "password": "…" }
{ "host": "bastion.example.com", "port": 2222, "user": "deploy", "agent": true }
{ "host": "bastion.example.com", "user": "deploy", "agent": true, "hostKey": "SHA256:EXAMPLEexampleEXAMPLEexampleEXAMPLEexample1" }
ホストキーは検証されます。 hostKey が設定されている場合、踏み台サーバーのキーはその値と一致する必要があります(末尾の = パディングは許容されます)。また、known_hosts は参照されません。設定されていない場合、キーは ~/.ssh/known_hosts 内の該当ホストのエントリと一致する必要があります(ポートが 22 の場合は host、それ以外の場合は [host]:port)。
- プレーン形式とハッシュ化されたホスト名が一致します。ワイルドカードパターンは一致せず、否定ワイルドカード(
!*.example.com)を含む行は無視されます。 @revokedの下に記載されたキーは、行のホストパターンにかかわらず、すべてのホストで拒否されます。@cert-authorityの行と不明なマーカーはスキップされます。
初回接続時の信頼(TOFU)は行いません。不明なキーの場合、提示されたフィンガープリントを示すエラーとともに接続が失敗します。信頼できる情報源と照合してから、ホストを known_hosts に追加するか、次のように固定してください。
ssh-keyscan -p 22 bastion.example.com 2>/dev/null | ssh-keygen -lf -
# 256 SHA256:EXAMPLEexampleEXAMPLEexampleEXAMPLEexample1 bastion.example.com (ED25519)
その後、ssh.hostKey にその SHA256:... の値を設定して、エージェントに update_connection を依頼してください。
トンネルは 15 秒ごとにキープアライブを送信し、応答が 3 回途絶えると再構築されます。サポート対象外:ProxyJump と ~/.ssh/config、SSH 証明書。トンネル経由で scheme: "https" を使用する場合、証明書はトンネルのローカルアドレスではなく host に対して検証されます。
読み取り専用
readonly: true は、誤操作による書き込みを防ぎます。es_request を含むすべてのツールは、リクエストを送信する前に、メソッドとパスが許可リストに含まれているかを確認します。
GETとHEAD:許可されます。POST:_search、_msearch、_count、_field_caps、_pitのみ(必要に応じて 1 つのインデックスまたはパターンを指定できます。例:/logs-*/_search)、および/_search/scroll。DELETE:/_search/scrollと/_pit(読み取りセッションの終了)のみ。- その他はすべて拒否されます。また、メソッドにかかわらず、
..、%2e、%2f、%5c、\、#を含むパスも拒否されます。そのため、読み取り専用の接続では、es_requestで<logs-{now/d}>のように/を使って丸める日付計算インデックス名を使用できません。書き込み可能な接続には影響しません。 - ヘルパーツールのインデックス引数とパターン引数も検証されます(
/、\、?、#、%、空白、..は使用できません)。カンマ区切りのリスト、ワイルドカード、-による除外、cluster:indexは使用できます。日付計算名には%エンコードが必要なため、es_request経由でのみ使用できます。 - すべての
GETが許可されるため、GET /_flushのような読み取り専用のメンテナンスエンドポイントも許可されます。ドキュメントは変更されませんが、読み取り操作ではありません。
これはセキュリティ境界ではありません。設計上、エージェントは update_connection でこの設定を無効にできます。確実に保証するには、読み取り権限のみを持つ Elasticsearch ロールまたは API キーを使用してください。
ツール
| ツール | 機能 |
|---|---|
list_connections | source、シャドーされた名前、無効なエントリー、破損したファイルを含む接続一覧 |
add_connection | project ファイルまたは global ストアに接続を追加 |
update_connection | 接続が保存されている場所で接続を更新。null を指定するとフィールドを削除 |
remove_connection | 接続を削除し、同名のエントリーが見つかった場合は報告 |
test_connection | トンネルを含めてエンドツーエンドで接続し、クラスターのバージョンとレイテンシを報告 |
es_request | 任意のメソッド、パス、本文、クエリパラメーターに対応。読み取り専用ガード付き。NDJSON(_bulk、_msearch)には文字列の本文を使用 |
es_search | インデックスまたはパターンに対する query、aggs、size、source(_source として送信)、sort、from、search_after、track_total_hits、highlight、script_fields に対応。本文全体が query の中にネストされている場合は取り出し、note で通知 |
es_list_indices | パターン(デフォルトは *)に一致するインデックスと、ヘルス、ドキュメント数、ストアサイズを一覧表示 |
es_get_mapping | マッピングを field: type 形式にフラット化。元の形式を取得するには raw: true を指定 |
es_cluster_health | クラスターのヘルス |
es_search の size のデフォルト値は 10 で、ネストされた本文から取得した場合も含め、上限は 1000 です。aggs があり query がない場合は 0 になります。ツールの引数は厳密にチェックされます。誤ったキーは、たとえば unknown key '_source' — did you mean 'source'? のようなヒントとともに拒否されます。
クラスターからの 4xx または 5xx は、es_request も含め、ツールエラーとして返されます。最初の行には HTTP <status> <root_cause[0].type>: <reason> が続き、その後に整形されたレスポンス本文が表示されます。test_connection は、セキュリティ保護されたクラスターからの 401 など、2xx 以外の応答があると失敗します。
10 個のツール定義が消費するコンテキストは約 2.1k トークンです(tools/list は約 8,200 文字。npm run smoke を使用し、1 トークンあたり約 4 文字として測定)。
制限とタイムアウト
- 各結果は JSON で最大 40 KB です。2 KB を超える文字列は切り詰められ、
…[+N bytes]と表示されます。それでも本文が収まらない場合は、最も長い配列(hits、buckets)を収まるまで半分にします。切り詰めが発生したことはtruncatedに示され、結果は有効な JSON のままです。es_searchのsizeとsource、またはes_requestのfilter_pathを使って、取得量を減らしてください。 - 10 MB を超えるレスポンスはエラー(「size/_source で絞り込んでください」)とともに中止され、一部だけが返されることはありません。
queryTimeoutMs(デフォルト 60 秒)は、接続から本文の最後のバイトを読み取るまでの、リクエストごとの絶対期限です。
比較
| esmole-mcp | elastic/mcp-server-elasticsearch | cr7258/elasticsearch-mcp-server | |
|---|---|---|---|
| 状態 | メンテナンス中 | 非推奨。Elastic は Agent Builder MCP エンドポイント(Elasticsearch 9.2 以降)を案内 | メンテナンス中 |
| Elasticsearch 7.x | ✓ | — | ✓ |
| Elasticsearch 8.x | ✓ | ✓ | ✓ |
| OpenSearch | — | ✗ | ✓ |
| SSH トンネルを内蔵 | ✓ | ✗ | ✗ |
| エージェントが MCP ツールを通じて接続を追加・編集 | ✓ | ✗ | ✗ |
✓ 文書化済み、✗ 非対応、— 記載なし、または未テスト。2026 年 10 月時点で確認。修正提案を歓迎します。
セキュリティ
接続ファイルには、平文の認証情報が保存されています(モード 0600)。.esmole.json を Git に含めないでください。
クラスターのエラーは、そのままクライアントに渡されます。
update_connection を通じて、または接続ファイルを編集して接続を変更できる人は、認証情報の送信先を変更できます。host を変更すると保存済みのパスワードまたは API キーが引き継がれ、ssh.host を変更すると保存済みの SSH パスワードまたはキーが引き継がれるため、次の呼び出しではそれらが新しいホストに送信されます。接続ツールやファイルへの書き込み権限は、認証情報へのアクセス権と同様に扱ってください。
プロジェクトの .esmole.json は、そのまま信頼されます。クローンしたリポジトリや信頼できないリポジトリでは、接続が追加されたり、同じ名前のグローバル接続が上書きされたりして、クエリが別のホストに送信される可能性があります。検出処理は / まで親ディレクトリをたどるため、親ディレクトリ(~ など)にあるファイルは、その下のすべてのプロジェクトに適用されます。見慣れないリポジトリで作業する前に、list_connections を確認してください。
開いている SSH トンネルは、それぞれランダムなポートで 127.0.0.1 をリッスンし、認証を行いません。開いている間は、共有ホスト上の他のユーザーを含む、すべてのローカルプロセスがこのトンネル経由でターゲットホストに接続できます。クラスターは引き続き独自の認証情報を要求します。
脅威モデルと脆弱性の報告方法については、SECURITY.md を参照してください。
開発
npm ci
npm run lint # Biome
npm run typecheck # tsc
npm run test:unit # unit tests, mocked IO
npm run test:int # integration tests against Elasticsearch 7.17 and 8.x (needs Docker)
npm run smoke # build, npm pack, install the tarball in a temp dir, boot, tools/list
共有接続コアは @dbmole/core です。dbmole-mcp リポジトリで開発され、ビルド時にこのパッケージにバンドルされます。CONTRIBUTING.md を参照してください。
ライセンス
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。