elastic-mcp

elastic-mcp

A Model Context Protocol server for Elasticsearch, enabling search, index inspection, and cluster information tools with optional write tools.

Category
Visit Server

README

elastic-mcp

npm version build

⚠️ Disclaimer: this MCP server was vibe coded. It was built iteratively with an AI assistant and is typechecked and unit-tested, but review it yourself before relying on it — especially the write tools — and use it at your own risk.

A Model Context Protocol server for Elasticsearch, written in JavaScript with JSDoc types checked by TypeScript (@ts-check / checkJs). Read-only by default, with optional write tools.

It exposes search, index inspection, and cluster information tools over the stdio transport, and transparently supports:

  • Elasticsearch deployments served behind a reverse proxy under a base path (for example https://host/elasticsearch) — something the official client does not handle out of the box.
  • Both Elasticsearch 8.x and 9.x clusters — the v9 client speaks compatible-with=9 and is rejected by 8.x clusters, so the matching client major is selected at startup (auto-detected or pinned).

Tested in corporate environments where API keys are often issued to restricted users with limited privileges (e.g. index read only, without cluster monitor or view_index_metadata). The server is built to degrade gracefully in these setups rather than fail outright — it falls back to lower-privilege APIs where possible and surfaces clear authorization errors otherwise. See Elasticsearch version compatibility and the privilege fallback table for details.

Usage

Run it straight from npm with npx (no install needed — set the environment variables from Configuration first):

ELASTICSEARCH_URL=http://localhost:9200/elastic npx elastic-mcp

Or install it globally to get the elastic-mcp command on your PATH:

npm install -g elastic-mcp
ELASTICSEARCH_URL=http://localhost:9200/elastic elastic-mcp

Claude Desktop / Claude Code

Add the server to your MCP client configuration:

{
  "mcpServers": {
    "elastic": {
      "command": "npx",
      "args": ["-y", "elastic-mcp"],
      "env": {
        "ELASTICSEARCH_URL": "https://host/elasticsearch",
        "ELASTICSEARCH_API_KEY": "<base64-api-key>"
      }
    }
  }
}

Tools

Read tools

Always registered, and all marked read-only (readOnlyHint).

Tool Description
search Run a Query DSL search (query, aggs, sort, size, from, _source).
count Count documents matching an optional query.
get_document Fetch a single document by index and id.
list_indices List indices with health, status, doc count, and size; falls back to names-only via _resolve/index without cluster monitor.
get_mapping Get field mappings for one or more indices; falls back to read-level _field_caps (field names + types) without view_index_metadata.
get_settings Get settings for one or more indices.
get_aliases List index aliases.
list_shards List shards with role, state, doc count, store size, and node (equivalent to _cat/shards); the doc count and store size come back null without cluster monitor.
get_kibana_object Fetch a Kibana saved object by <type>:<id>; decodes inline JSON-string fields (visState, searchSourceJSON, ...) and resolves references[] to titles. Reads .kibana_analytics / .kibana, so the key needs read on those.
cluster_health Cluster health, optionally scoped to indices.
cluster_stats Cluster-wide statistics.
cluster_info Cluster name, UUID, and version.
list_nodes List nodes with role, heap, CPU, and load.

Write tools

Off by default. Registered only when ELASTICSEARCH_ENABLE_WRITES=true. Each is marked destructiveHint (except create_index) so MCP clients can prompt for confirmation, and of course only works if the API key carries the matching write privileges.

Tool Description
index_document Create or replace a document (auto-generates an id if omitted; createOnly to avoid overwriting).
update_document Partially update a document by id, with optional upsert.
delete_document Delete a single document by id.
create_index Create an index, optionally with mappings, settings, and aliases.
delete_index Permanently delete one or more indices — cannot be undone.

Configuration

Configuration is read from environment variables (see .env.example):

Variable Required Description
ELASTICSEARCH_URL yes Endpoint URL, optionally including a base path.
ELASTICSEARCH_API_KEY no Base64 API key; takes precedence over basic auth.
ELASTICSEARCH_USERNAME no Basic-auth username.
ELASTICSEARCH_PASSWORD no Basic-auth password.
ELASTICSEARCH_CA_FINGERPRINT no SHA-256 fingerprint of the CA certificate.
ELASTICSEARCH_TLS_VERIFY no Defaults to true; set to false to accept self-signed/invalid certs (dev only).
ELASTICSEARCH_API_VERSION no 8, 9, or auto (default). Selects the client major; see below.
ELASTICSEARCH_ENABLE_WRITES no Set to true to register the write tools. Off by default (server is read-only).

Elasticsearch version compatibility

The official client always sends a compatible-with=<major> media type that matches its own major version, and a cluster of a different major rejects it. To work against both 8.x and 9.x clusters, both client majors are bundled and the right one is chosen at startup:

  • auto (default) — probe the cluster's root endpoint (with a plain application/json request that side-steps the compatibility header) and pick the matching client major. Anything up to 8.x uses the v8 client; 9.x and newer use the v9 client.
  • 8 / 9 — pin the client major explicitly and skip the probe.

Note: the root probe requires the cluster:monitor/main privilege. Index-scoped API keys often lack it (it can only be granted by an admin), in which case the probe fails with action [cluster:monitor/main] is unauthorized. When that happens the server logs a warning and falls back to the v8 client, which speaks compatible-with=8 — accepted by both 8.x and 9.x clusters — so search and index inspection keep working. Set ELASTICSEARCH_API_VERSION explicitly to skip the probe (and the warning) entirely.

Base path support

When ELASTICSEARCH_URL contains a path (e.g. https://host/elasticsearch), the URL is split into its origin (https://host) and prefix (/elasticsearch). A custom connection class prepends the prefix to every request path, because the official client routes requests against the origin only and silently drops the path.

Creating an API key

By default the server is read-only, so it only needs cluster monitor rights (for cluster_health, cluster_stats, cluster_info, list_nodes, and the _cat listings) plus read and view_index_metadata on the indices you want to expose. Create a least-privilege key with the Create API key API:

POST /_security/api_key
{
  "name": "elastic-mcp",
  "role_descriptors": {
    "elastic_mcp_read_only": {
      "cluster": ["monitor"],
      "indices": [
        {
          "names": ["*"],
          "privileges": ["read", "view_index_metadata"]
        }
      ]
    }
  }
}

Or with curl:

curl -u elastic -X POST "$ELASTICSEARCH_URL/_security/api_key" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "elastic-mcp",
    "role_descriptors": {
      "elastic_mcp_read_only": {
        "cluster": ["monitor"],
        "indices": [
          { "names": ["*"], "privileges": ["read", "view_index_metadata"] }
        ]
      }
    }
  }'

The response contains an encoded field — that base64 value is exactly what ELASTICSEARCH_API_KEY expects:

{
  "id": "VuaCfGcBCdbkQm-e5aOx",
  "name": "elastic-mcp",
  "api_key": "ui2lp2axTNmsyakw9tvNnw",
  "encoded": "VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6dWkybHAyYXhUTm1zeWFrdzl0dk5udw=="
}
ELASTICSEARCH_API_KEY=VnVhQ2ZHY0JDZGJrUW0tZTVhT3g6dWkybHAyYXhUTm1zeWFrdzl0dk5udw==

Restrict indices[].names to specific index names or patterns to narrow access further.

Kibana saved-object access (only for get_kibana_object)

get_kibana_object reads Kibana's saved objects straight from the .kibana_analytics and .kibana indices. These are restricted system indices, so a plain read on * does not reach them — the role needs a dedicated entry that opts in with allow_restricted_indices. Add it alongside the existing read entry (keep the wildcard entry at false so the key cannot read other system indices such as .security-*):

{
  "name": "elastic-mcp",
  "role_descriptors": {
    "elastic_mcp_read_only": {
      "cluster": ["monitor"],
      "indices": [
        { "names": ["*"], "privileges": ["read", "view_index_metadata"], "allow_restricted_indices": false },
        { "names": [".kibana*"], "privileges": ["read"], "allow_restricted_indices": true }
      ]
    }
  }
}

To widen an existing key without rotating it, the Update API key API (PUT /_security/api_key/<id>) rewrites its role_descriptors in place — the id and encoded value are unchanged, so ELASTICSEARCH_API_KEY does not need updating. Omit this entry entirely if you do not use get_kibana_object; the tool then returns an authorization error and the rest of the server is unaffected.

Write privileges (only if ELASTICSEARCH_ENABLE_WRITES=true)

The read-only key above cannot mutate data — the write tools would return authorization errors. To allow them, add the relevant index privileges: write (covers index_document, update_document, delete_document), create_index, and delete_index:

{
  "name": "elastic-mcp",
  "role_descriptors": {
    "elastic_mcp_read_write": {
      "cluster": ["monitor"],
      "indices": [
        {
          "names": ["*"],
          "privileges": ["read", "view_index_metadata", "write", "create_index", "delete_index"]
        }
      ]
    }
  }
}

Grant only the subset you need — for example drop delete_index if you never delete indices. Cluster monitor remains optional (see the fallback table below).

Graceful privilege degradation

Some tools degrade gracefully when privileges are missing, falling back once to a lower-privilege API and remembering that for the rest of the process so they don't retry the rejected endpoint:

Tool Needs Fallback when missing Granted by
list_indices cluster monitor _resolve/index (names only) view_index_metadata
get_mapping view_index_metadata _field_caps (field names + types) read

So a key with only read + view_index_metadata (or even just read) still gets useful results from search, count, get_document, get_mapping, and list_indices. The tools that have no lower-privilege equivalent — cluster_health, cluster_stats, cluster_info, list_nodes (cluster monitor), get_settings, get_aliases (view_index_metadata), and get_kibana_object (restricted .kibana* read, see above) — return an authorization error without the privilege.

Contributing

See CLAUDE.md for the project layout, architecture notes, and coding conventions.

License

ISC — see LICENSE.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured