Doramagic Project Pack · Human Manual

mcp-server-elasticsearch

The Elasticsearch MCP Server is a Model Context Protocol (MCP) server implementation that connects AI agents to Elasticsearch clusters. It enables natural language interactions with Elasti...

Project Introduction

Related topics: System Architecture, Available MCP Tools, Docker Deployment

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Deprecation Notice

Continue reading this section for the full explanation and source context.

Section High-Level Architecture

Continue reading this section for the full explanation and source context.

Section Server Modes

Continue reading this section for the full explanation and source context.

Related topics: System Architecture, Available MCP Tools, Docker Deployment

Project Introduction

Overview

The Elasticsearch MCP Server is a Model Context Protocol (MCP) server implementation that connects AI agents to Elasticsearch clusters. It enables natural language interactions with Elasticsearch indices, allowing agents to query, analyze, and retrieve data without custom APIs.

Source: README.md

Deprecation Notice

[!CAUTION]
This MCP server is deprecated and will only receive critical security updates going forward. It has been superseded by the Elastic Agent Builder MCP endpoint, which is available in Elastic 9.2.0+ and Elasticsearch Serverless projects.

Source: README.md

Project Metadata

The project is classified as a beta-stage library owned by the DevTools team at Elastic.

AttributeValue
Project Namemcp-server-elasticsearch
TypeLibrary (MCP Server)
LifecycleBeta
Ownergroup:devtools-team
CI/CDBuildkite Pipeline
CopyrightCopyright 2025 Elasticsearch B.V.

Source: catalog-info.yaml

Architecture

High-Level Architecture

graph TD
    A[AI Agent / MCP Client] -->|MCP Protocol| B[MCP Server]
    B --> C[Elasticsearch Cluster]
    
    subgraph "MCP Server Components"
        D[CLI Layer<br/>stdio/http] --> E[Protocol Handler]
        E --> F[Tool Router]
        F --> G[Elasticsearch Client]
    end
    
    subgraph "Tools"
        H[list_indices]
        I[get_mappings]
        J[search]
        K[esql]
        L[get_shards]
        M[Custom Tools]
    end
    
    G --> H
    G --> I
    G --> J
    G --> K
    G --> L
    G --> M

Server Modes

The MCP server supports two primary transport modes:

ModeDescriptionUse Case
StdioStandard input/output communicationLocal MCP clients, Claude Desktop, Cursor
HTTP/SSEHTTP with Server-Sent EventsRemote deployment, web-based clients, n8n integration

Source: src/cli.rs:19-35

Configuration Structure

graph LR
    A[Config File<br/>JSON5] --> B[Interpolator]
    B --> C[Configuration]
    
    subgraph "Elasticsearch Config"
        D[url]
        E[api_key]
        F[username/password]
        G[ssl_skip_verify]
    end
    
    subgraph "MCP Servers Config"
        H[Stdio servers]
        I[Streamable HTTP servers]
        J[SSE servers]
    end

Source: src/lib.rs and src/cli.rs:63-80

Core Components

ElasticsearchMcpConfig

The main configuration struct for the Elasticsearch MCP server.

FieldTypeDefaultDescription
urlStringRequiredCluster URL
api_keyOption<String>NoneAPI key authentication
usernameOption<String>NoneUsername for basic auth
passwordOption<String>NonePassword for basic auth
ssl_skip_verifyboolfalseSkip SSL certificate verification
toolsToolsEmptyCustom tools configuration
promptsVec<String>EmptyPrompts to expose

Source: src/servers/elasticsearch/mod.rs:64-85

EsClientProvider

A wrapper around the Elasticsearch client that provides request-context-aware client instances.

pub struct EsClientProvider(Elasticsearch);

The provider supports authentication via:

  • API Key: Credentials::EncodedApiKey(api_key)
  • Basic Auth: Credentials::Basic(username, password)
  • Per-request Auth: Extracts Authorization header from incoming HTTP requests

Source: src/servers/elasticsearch/mod.rs:88-106

Available Tools

Base Tools

ToolDescriptionRead Only
list_indicesList all available Elasticsearch indicesYes
get_mappingsRetrieve index mappingsYes
searchPerform Elasticsearch query DSL searchYes
esqlExecute ESQL queriesYes
get_shardsGet shard information for indicesYes

Source: src/servers/elasticsearch/base_tools.rs

Custom Tools

The server supports extensible custom tools through the Tools struct:

FieldTypeDescription
incl_exclOption<IncludeExclude>Include/exclude filter for tools
customHashMap<String, CustomTool>Map of custom tool definitions

Supported custom tool types:

TypeDescription
EsqlESQL query tool with configurable result format
SearchTemplateSearch template tool (by ID or inline)

Source: src/servers/elasticsearch/mod.rs:1-65

ES|QL Result Formats

FormatDescription
json (default)Output as JSON array or single object
valueIf single object with single property, output only value

Source: src/servers/elasticsearch/mod.rs:28-34

Data Models

Search Result

pub struct SearchResult {
    pub hits: Hits,
    #[serde(default)]
    pub aggregations: IndexMap<String, Value>,
}

pub struct Hits {
    pub total: Option<TotalHits>,
    pub hits: Vec<Hit>,
}

pub struct TotalHits {
    pub value: u64,
}

pub struct Hit {
    #[serde(rename = "_source")]
    pub source: Value,
}

Source: src/servers/elasticsearch/base_tools.rs:100-122

ES|QL Response

pub struct EsqlQueryResponse {
    pub is_partial: Option<bool>,
    pub columns: Vec<Column>,
    pub values: Vec<Vec<Value>>,
}

pub struct Column {
    pub name: String,
    #[serde(rename = "type")]
    pub type_: String,
}

Source: src/servers/elasticsearch/base_tools.rs:155-169

Transport Protocols

Stdio Transport

Used for local MCP client connections. Compatible with Claude Desktop, Cursor, and VS Code.

{
  "mcpServers": {
    "elasticsearch": {
      "command": "npx",
      "args": ["-y", "@elastic/mcp-server-elasticsearch"]
    }
  }
}

Source: src/cli.rs:42-55

HTTP Transport

HTTP server with optional SSE support for remote deployments.

EndpointMethodDescription
/GETHello endpoint
/pingGETHealth check
/readyGETReadiness probe
/liveGETLiveness probe
/mcp/sseGETSSE endpoint
/mcpPOSTMCP JSON-RPC handler

Source: src/protocol/http.rs

Environment Variable Interpolation

The configuration file supports environment variable interpolation using ${VAR} or ${VAR:default} syntax.

fn interpolate(name: String, lookup: impl Fn(&str) -> Option<String>) 
    -> Result<String, InterpolationError>
SyntaxBehavior
${VAR}Required - fails if not defined
${VAR:default}Optional - uses default if not defined

Source: src/utils/interpolator.rs

CLI Commands

Stdio Command

mcp-server-elasticsearch stdio --config <path>

Source: src/cli.rs:36-41

HTTP Command

mcp-server-elasticsearch http [OPTIONS]
OptionEnvironment VariableDefault
--config <path>-None
--address <ip:port>HTTP_ADDRESS127.0.0.1:8080
--sse-Disabled

Source: src/cli.rs:19-33

Dependency Management

The project uses Renovate for automated dependency updates.

SettingValue
Schemahttps://docs.renovatebot.com/renovate-schema.json
Base Configlocal>elastic/renovate-config
Scheduleafter 1am on monday
StatusRate-limited

Source: renovate.json

Known Issues

Community-Reported Issues

IssueDescription
#185get_mappings tool fails with "error decoding response body" when nested type is omitted in properties
#170Basic auth failed - 401 Unauthorized despite correct credentials
#191Missing Linux ARM64 binary releases
#17Request for streamable HTTP transport support

Source: GitHub Issues

Quick Reference

Minimum Requirements

  • Elasticsearch cluster (version 8.x or 9.x)
  • Authentication credentials (API key or username/password)
  • Docker (for container deployment)
  • MCP-compatible client

Default Configuration

{
  "elasticsearch": {
    "url": "${ES_URL:}",
    "api_key": "${ES_API_KEY:}",
    "username": "${ES_USERNAME:}",
    "password": "${ES_PASSWORD:}",
    "ssl_skip_verify": "${ES_SSL_SKIP_VERIFY:false}"
  }
}

Source: src/lib.rs:36-45

Version History

VersionKey Changes
v0.4.6Deprecation notice added
v0.4.5ENV name fix for username
v0.4.4CA certificates added
v0.4.3Default port set to 8080
v0.4.2Default port changed to 8000
v0.3.1Hashbang fix for npx execution
v0.3.0OpenTelemetry support, aggregation results
v0.2.0get_shards tool added

Source: GitHub Releases

Source: https://github.com/elastic/mcp-server-elasticsearch / Human Manual

Available MCP Tools

Related topics: System Architecture, Troubleshooting Guide

Section Related Pages

Continue reading this section for the full explanation and source context.

Section listindices

Continue reading this section for the full explanation and source context.

Section getmappings

Continue reading this section for the full explanation and source context.

Section search

Continue reading this section for the full explanation and source context.

Related topics: System Architecture, Troubleshooting Guide

Available MCP Tools

The Elasticsearch MCP Server exposes a set of tools that enable AI agents to interact with Elasticsearch clusters through natural language. These tools wrap the Elasticsearch REST API and provide a simplified interface for common operations like searching, exploring indices, and retrieving cluster metadata.

Overview

The MCP server implements the Model Context Protocol tool specification, using the rmcp framework with Rust macros for tool definition and routing. All tools are read-only by default, enabling safe interactions with production Elasticsearch clusters.

graph TD
    A[MCP Client] -->|tool_request| B[EsBaseTools]
    B --> C[Elasticsearch Cluster]
    
    subgraph Tools
        D[list_indices]
        E[get_mappings]
        F[search]
        G[esql]
        H[get_shards]
    end
    
    C -->|response| B
    B -->|tool_result| A

Source: src/servers/elasticsearch/base_tools.rs:30-36

Core Tools

Core tools are built-in MCP tools that provide fundamental Elasticsearch operations. They are implemented in EsBaseTools and registered via the #[tool_router] macro.

Source: src/servers/elasticsearch/base_tools.rs:1-40

list_indices

Lists all available Elasticsearch indices matching a specified pattern.

Parameters:

ParameterTypeRequiredDescription
index_patternStringYesIndex pattern to filter indices (e.g., *, logs-*)

Implementation Details:

The tool uses the Elasticsearch _cat/indices API with JSON response format, requesting the index, status, and docs.count fields.

#[tool(
    description = "List all available Elasticsearch indices",
    annotations(title = "List ES indices", read_only_hint = true)
)]
async fn list_indices(
    &self,
    req_ctx: RequestContext<RoleServer>,
    Parameters(ListIndicesParams { index_pattern }): Parameters<ListIndicesParams>,
) -> Result<CallToolResult, rmcp::Error>

Source: src/servers/elasticsearch/base_tools.rs:70-92

get_mappings

Retrieves field mappings for a specific Elasticsearch index.

Parameters:

ParameterTypeRequiredDescription
indexStringYesName of the Elasticsearch index

Implementation Details:

The tool calls the _mapping endpoint for the specified index and returns the complete mapping definition.

#[tool(
    description = "Get field mappings for a specific Elasticsearch index",
    annotations(title = "Get ES index mappings", read_only_hint = true)
)]
async fn get_mappings(
    &self,
    req_ctx: RequestContext<RoleServer>,
    Parameters(GetMappingsParams { index }): Parameters<GetMappingsParams>,
) -> Result<CallToolResult, rmcp::Error>

Known Issue: When a nested property is defined without explicitly specifying "type": "nested", the server may throw "error decoding response body" even though the mapping is valid according to the Elasticsearch specification. This is tracked in issue #185.

Source: src/servers/elasticsearch/base_tools.rs:95-115

Performs an Elasticsearch search using the Query DSL.

Parameters:

ParameterTypeRequiredDescription
indexStringYesName of the Elasticsearch index to search
fieldsVec<String>NoSpecific fields to return, augments _source
query_bodyMap<String, Value>YesComplete Elasticsearch query DSL object

Implementation Details:

The search tool accepts a full Elasticsearch query DSL object that can include query, size, from, sort, aggs, and other query parameters. If the fields parameter is provided, it augments the _source parameter to limit returned data.

The response includes both search hits and aggregations:

#[derive(Serialize, Deserialize)]
pub struct SearchResult {
    pub hits: Hits,
    #[serde(default)]
    pub aggregations: IndexMap<String, Value>,
}
#[tool(
    description = "Perform an Elasticsearch search with the provided query DSL.",
    annotations(title = "Elasticsearch search DSL query", read_only_hint = true)
)]
async fn search(
    &self,
    req_ctx: RequestContext<RoleServer>,
    Parameters(SearchParams {
        index,
        fields,
        query_body,
    }): Parameters<SearchParams>,
) -> Result<CallToolResult, rmcp::Error>

Source: src/servers/elasticsearch/base_tools.rs:118-165

esql

Executes an ES|QL query against Elasticsearch.

Parameters:

ParameterTypeRequiredDescription
queryStringYesComplete ESQL query

Response Formats:

The tool supports different output formats configured via the format parameter:

FormatDescription
json (default)Output as JSON array of objects or single object
valueIf single object with single property, output only its value

Source: src/servers/elasticsearch/mod.rs:40-55

get_shards

Retrieves shard allocation information for all or specific indices.

Parameters:

ParameterTypeRequiredDescription
indexOption<String>NoOptional index name to filter shards

Implementation Details:

The tool uses the Elasticsearch _cat/shards API with JSON format, requesting index, shard, prirep, state, docs, store, and node fields.

#[tool(
    description = "Get shard information for all or specific indices.",
    annotations(title = "Get ES shard information", read_only_hint = true)
)]
async fn get_shards(
    &self,
    req_ctx: RequestContext<RoleServer>,
    Parameters(GetShardsParams { index }): Parameters<GetShardsParams>,
) -> Result<CallToolResult, rmcp::Error>

Source: src/servers/elasticsearch/base_tools.rs:168-200

Custom Tools

Custom tools extend the core functionality by allowing users to define pre-configured queries and templates. They are defined in the configuration file and registered at startup.

Source: src/servers/elasticsearch/mod.rs:15-30

Tool Definition Structure

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum CustomTool {
    Esql(EsqlTool),
    SearchTemplate(SearchTemplateTool),
}

#[derive(Debug, Serialize, Deserialize)]
pub struct ToolBase {
    pub description: String,
    pub parameters: IndexMap<String, schemars::schema::SchemaObject>,
    pub annotations: Option<ToolAnnotations>,
}

EsqlTool

Pre-configured ES|QL queries that can be exposed as tools. Includes a base definition with description, parameters schema, and the query to execute.

Source: src/servers/elasticsearch/mod.rs:32-55

SearchTemplateTool

Pre-configured search templates that accept parameters at runtime. Supports two template specification modes:

ModeDescription
template_idReference an existing saved search template by ID
templateInline template definition as JSON

Source: src/servers/elasticsearch/mod.rs:57-72

Tool Configuration

Tools are configured in the server configuration file under the tools section:

{
  "elasticsearch": {
    "url": "${ES_URL}",
    "api_key": "${ES_API_KEY}"
  },
  "tools": {
    "incl_excl": {
      "include": ["custom_tool_1"],
      "exclude": ["custom_tool_2"]
    },
    "custom": {
      "my_esql_query": {
        "type": "esql",
        "description": "Count documents by status",
        "parameters": {},
        "query": "FROM my-index | STATS count = COUNT(*)"
      }
    }
  }
}

Source: src/lib.rs:45-65

Server Capabilities

Each tool set reports its capabilities through the get_info() method:

fn get_info(&self) -> ServerInfo {
    ServerInfo {
        protocol_version: ProtocolVersion::V_2025_03_26,
        capabilities: ServerCapabilities::builder().enable_tools().build(),
        server_info: Implementation::from_build_env(),
        instructions: Some("Provides access to Elasticsearch".to_string()),
    }
}

Source: src/servers/elasticsearch/base_tools.rs:27-36

Transport Support

Tools can be accessed through multiple transport protocols:

TransportDescriptionUse Case
stdioDirect process communicationLocal clients, Claude Desktop
streamable-httpHTTP-based with session supportWeb integrations, remote access
sseServer-Sent Events (deprecated)Legacy compatibility

Source: src/cli.rs:20-35

Response Structure

All tools return results wrapped in CallToolResult:

Ok(CallToolResult::success(vec![
    Content::text(format!("Found {} indices:", response.len())),
    Content::json(response)?,
]))

The server returns:

  • Text summary with counts or status
  • JSON content with the full response data

Community Considerations

When using these tools, be aware of the following community-reported issues:

  • Aggregation results in search: Some agents may not receive aggregation results properly. The enhancement request #45 tracks improvements to aggregation handling.
  • get_mappings with nested types: Valid Elasticsearch mappings with implicit nested types may cause decoding errors. See issue #185.
  • HTTP transport limitations: When accessing via HTTP/SSE, certain tool combinations may return errors. This is discussed in issue #173.

Source: https://github.com/elastic/mcp-server-elasticsearch / Human Manual

System Architecture

Related topics: MCP Protocol Configuration, Available MCP Tools

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Stdio Transport

Continue reading this section for the full explanation and source context.

Section HTTP Transport

Continue reading this section for the full explanation and source context.

Section Runtime Entry Points

Continue reading this section for the full explanation and source context.

Related topics: MCP Protocol Configuration, Available MCP Tools

System Architecture

Overview

The Elasticsearch MCP Server is a Model Context Protocol (MCP) server implementation written in Rust that connects AI agents to Elasticsearch clusters. It enables natural language interactions with Elasticsearch indices through a standardized tool interface, supporting both stdio and HTTP transport protocols.

Project Type: Library component (Backstage classification) Owner: devtools-team Lifecycle: Beta (deprecated as of v0.4.6) Source: catalog-info.yaml:1-56

High-Level Architecture

The server follows a layered architecture with distinct separation between transport handling, protocol implementation, and tool execution:

graph TD
    subgraph Transport Layer
        STDIOC[Stdio Transport]
        HTTPC[HTTP Transport]
        SSEC[SSE Transport]
    end
    
    subgraph Protocol Layer
        MCP[Model Context Protocol]
    end
    
    subgraph Server Layer
        ESMC[ElasticsearchMcp]
        BASET[EsBaseTools]
    end
    
    subgraph Tools
        SEARCH[search]
        LISTIDX[list_indices]
        GETMAP[get_mappings]
        GETSHARDS[get_shards]
        ESQL[esql]
    end
    
    subgraph Elasticsearch
        ES[Elasticsearch Cluster]
    end
    
    STDIOC --> MCP
    HTTPC --> MCP
    SSEC --> MCP
    MCP --> ESMC
    ESMC --> BASET
    BASET --> SEARCH
    BASET --> LISTIDX
    BASET --> GETMAP
    BASET --> GETSHARDS
    BASET --> ESQL
    SEARCH --> ES
    LISTIDX --> ES
    GETMAP --> ES
    GETSHARDS --> ES
    ESQL --> ES

Transport Layer

The server supports multiple transport mechanisms, configurable via command-line arguments:

Stdio Transport

The default transport mode for local MCP client integrations. Communicates via standard input/output streams using JSON-RPC messages.

pub enum Command {
    Stdio(StdioCommand),
    Http(HttpCommand),
}

pub struct StdioCommand {
    /// Config file
    #[clap(short, long)]
    pub config: Option<PathBuf>,
}

Source: src/cli.rs:19-29

HTTP Transport

Supports remote deployments with optional Server-Sent Events (SSE) fallback:

pub struct HttpCommand {
    /// Config file
    #[clap(short, long)]
    pub config: Option<PathBuf>,

    /// Address to listen to [default: 127.0.0.1:8080]
    #[clap(long, value_name = "IP_ADDRESS:PORT", env = "HTTP_ADDRESS")]
    pub address: Option<std::net::SocketAddr>,

    /// Also start an SSE server on '/sse'
    #[clap(long)]
    pub sse: bool,
}
ParameterTypeDefaultEnvironment Variable
configPathBufNone-
addressSocketAddr127.0.0.1:8080HTTP_ADDRESS
sseboolfalse-

Source: src/cli.rs:31-47

Runtime Entry Points

The CLI determines which transport to initialize based on the subcommand:

pub async fn run_stdio(cmd: StdioCommand, container_mode: bool) -> anyhow::Result<()> {
    tracing::info!("Starting stdio server");
    let handler = setup_services(&cmd.config, container_mode).await?;
    let service = handler.serve(stdio()).await.inspect_err(|e| {
        tracing::error!("serving error: {:?}", e);
    })?;
    // ...
}

pub async fn run_http(cmd: HttpCommand, container_mode: bool) -> anyhow::Result<()> {
    let handler = setup_services(&cmd.config, container_mode).await?;
    let server_provider = move || handler.clone();
    // ...
}

Source: src/lib.rs:1-100

Configuration System

Configuration Structure

The server uses JSON5 format for configuration files, with support for comments and environment variable interpolation:

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Configuration {
    pub elasticsearch: elasticsearch::ElasticsearchMcpConfig,
    #[serde(default)]
    pub mcp_servers: HashMap<String, McpServer>,
}

Source: src/cli.rs:104-111

Elasticsearch Configuration

pub struct ElasticsearchMcpConfig {
    /// Cluster URL
    pub url: String,

    /// API key
    #[serde(default, deserialize_with = "none_if_empty_string")]
    pub api_key: Option<String>,

    /// Username
    #[serde(default, deserialize_with = "none_if_empty_string")]
    pub username: Option<String>,

    /// Password
    #[serde(default, deserialize_with = "none_if_empty_string")]
    pub password: Option<String>,

    /// Should we skip SSL certificate verification?
    #[serde(default, deserialize_with = "deserialize_bool_from_anything")]
    pub ssl_skip_verify: bool,

    /// Search templates to expose as tools or resources
    #[serde(default)]
    pub tools: Tools,

    /// Prompts
    #[serde(default)]
    pub prompts: Vec<String>,
}
ParameterRequiredDefaultEnvironment Variable
urlYes-ES_URL
api_keyNo-ES_API_KEY
usernameNo-ES_USERNAME
passwordNo-ES_PASSWORD
ssl_skip_verifyNofalseES_SSL_SKIP_VERIFY

Source: src/servers/elasticsearch/mod.rs:1-100

Environment Variable Interpolation

The configuration parser supports ${VAR_NAME} and ${VAR_NAME:default_value} syntax:

fn expand(name: &str) -> Result<String, InterpolationError> {
    let lookup = |s: &str| match s {
        "foo" => Some("foo_value".to_string()),
        "bar" => Some("bar_value".to_string()),
        _ => None,
    };
    interpolate(name.to_string(), lookup)
}

Source: src/utils/interpolator.rs:1-50

Core Server Components

ElasticsearchMcp Server

The main server implementation wraps the Elasticsearch client and provides tool routing:

pub struct ElasticsearchMcp {}

impl ElasticsearchMcp {
    pub fn new_with_config(
        config: ElasticsearchMcpConfig, 
        container_mode: bool
    ) -> anyhow::Result<base_tools::EsBaseTools> {
        let creds = if let Some(api_key) = config.api_key.clone() {
            Some(Credentials::EncodedApiKey(api_key))
        } else if let Some(username) = config.username.clone() {
            let pwd = config.password.clone().ok_or(anyhow::Error::msg("missing password"))?;
            Some(Credentials::Basic(username, pwd))
        } else {
            None
        };

        let url = config.url.as_str();
        if url.is_empty() {
            return Err(anyhow::Error::msg("Elasticsearch URL is empty"));
        }

        let mut url = Url::parse(url)?;
        if container_mode {
            rewrite_localhost(&mut url)?;
        }

        let pool = elasticsearch::http::transport::SingleNodeConnectionPool::new(url.clone());
        let mut transport = elasticsearch::http::transport::TransportBuilder::new(pool);
        if let Some(creds) = creds {
            transport = transport.auth(creds);
        }
        // ...
    }
}

Source: src/servers/elasticsearch/mod.rs:1-100

EsClientProvider

A wrapper around the Elasticsearch client that supports per-request authentication:

#[derive(Clone)]
pub struct EsClientProvider(Elasticsearch);

impl EsClientProvider {
    pub fn new(client: Elasticsearch) -> Self {
        EsClientProvider(client)
    }

    /// If the incoming request is a http request and has an `Authorization` header, use it
    /// to authenticate to the remote ES instance.
    pub fn get(&self, context: RequestContext<RoleServer>) -> Elasticsearch {
        // Authentication context handling
    }
}

Source: src/servers/elasticsearch/mod.rs:100-150

EsBaseTools

The core tool provider implementing the MCP tool protocol:

#[derive(Clone)]
pub struct EsBaseTools {
    es_client: EsClientProvider,
    tool_router: ToolRouter<EsBaseTools>,
}

impl EsBaseTools {
    pub fn new(es_client: Elasticsearch) -> Self {
        Self {
            es_client: EsClientProvider::new(es_client),
            tool_router: Self::tool_router(),
        }
    }
}

#[tool_handler]
impl ServerHandler for EsBaseTools {
    fn get_info(&self) -> ServerInfo {
        ServerInfo {
            protocol_version: ProtocolVersion::V_2025_03_26,
            capabilities: ServerCapabilities::builder().enable_tools().build(),
            server_info: Implementation::from_build_env(),
            instructions: Some("Provides access to Elasticsearch".to_string()),
        }
    }
}

Source: src/servers/elasticsearch/base_tools.rs:1-100

Tool System

Available Tools

ToolDescriptionRead Only
list_indicesList all available Elasticsearch indicesYes
get_mappingsRetrieve index mappingsYes
get_shardsGet shard information for indicesYes
searchPerform Elasticsearch search with Query DSLYes
esqlExecute ES\QL queriesYes

Source: src/servers/elasticsearch/base_tools.rs:100-200

Tool Parameter Definitions

#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
struct ListIndicesParams {
    /// Index pattern of Elasticsearch indices to list
    pub index_pattern: String,
}

#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
struct GetMappingsParams {
    /// Name of the Elasticsearch index to get mappings for
    index: String,
}

#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
struct SearchParams {
    /// Name of the Elasticsearch index to search
    index: String,

    /// Name of the fields that need to be returned (optional)
    fields: Option<Vec<String>>,

    /// Complete Elasticsearch query DSL object that can include query, size, from, sort, etc.
    query_body: Map<String, Value>,
}

#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
struct EsqlQueryParams {
    /// Complete Elasticsearch ES|QL query
    query: String,
}

#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
struct GetShardsParams {
    /// Optional index name to get shard information for
    index: Option<String>,
}

Source: src/servers/elasticsearch/base_tools.rs:100-200

Custom Tools

The server supports extensible custom tools via configuration:

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum CustomTool {
    Esql(EsqlTool),
    SearchTemplate(SearchTemplateTool),
}

pub struct EsqlTool {
    #[serde(flatten)]
    base: ToolBase,
    query: String,
    #[serde(default)]
    format: EsqlResultFormat,
}

#[derive(Debug, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum EsqlResultFormat {
    #[default]
    Json,
    Value,
}

Source: src/servers/elasticsearch/mod.rs:20-50

Data Models

Search Response

#[derive(Serialize, Deserialize)]
pub struct SearchResult {
    pub hits: Hits,
    #[serde(default)]
    pub aggregations: IndexMap<String, Value>,
}

#[derive(Serialize, Deserialize)]
pub struct Hits {
    pub total: Option<TotalHits>,
    pub hits: Vec<Hit>,
}

#[derive(Serialize, Deserialize)]
pub struct TotalHits {
    pub value: u64,
}

Source: src/servers/elasticsearch/base_tools.rs:50-70

Index Mappings Response

pub type MappingResponse = HashMap<String, Mappings>;

#[derive(Serialize, Deserialize)]
pub struct Mappings {
    pub mappings: Mapping,
}

#[derive(Serialize, Deserialize)]
pub struct Mapping {
    #[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
    pub meta: Option<JsonObject>,
    properties: HashMap<String, MappingProperty>,
}

#[derive(Serialize, Deserialize)]
pub struct MappingProperty {
    #[serde(rename = "type")]
    pub type_: String,
    #[serde(flatten)]
    pub settings: HashMap<String, serde_json::Value>,
}

Source: src/servers/elasticsearch/base_tools.rs:100-130

ES|QL Response

#[derive(Serialize, Deserialize)]
pub struct EsqlQueryResponse {
    pub is_partial: Option<bool>,
    pub columns: Vec<Column>,
    pub values: Vec<Vec<Value>>,
}

#[derive(Serialize, Deserialize)]
pub struct Column {
    pub name: String,
    #[serde(rename = "type")]
    pub type_: String,
}

Source: src/servers/elasticsearch/base_tools.rs:130-150

Server Initialization Flow

sequenceDiagram
    participant CLI as Command Line
    participant Config as Config Loader
    participant Interpolator as Env Interpolator
    participant Server as ElasticsearchMcp
    participant Transport as MCP Transport
    
    CLI->>Config: Load config file
    Config->>Interpolator: Expand ${VAR} placeholders
    Interpolator->>Config: Expanded config
    Config->>Server: Parse JSON5
    Server->>Server: Create ES client with auth
    CLI->>Transport: Start transport (stdio/http)
    Transport->>Server: Serve MCP requests

Source: src/lib.rs:1-100

Known Limitations

Community-Reported Issues

  1. Nested Mapping Parsing (Issue #185): The get_mappings tool fails with "error decoding response body" when a nested property is defined without explicitly specifying "type": "nested", even though the mapping is valid according to Elasticsearch spec.
  1. HTTP Transport Complexity (Issue #17): Support for streamable HTTP is a requested enhancement. Currently, the server supports stdio and HTTP/SSE transports only.
  1. Basic Auth Configuration (Issue #170): Users have reported confusion with authentication configuration when deploying via Docker, requiring careful setup of environment variables.

Architecture Summary

The Elasticsearch MCP Server implements a clean separation of concerns:

  1. Transport Layer: Handles protocol-agnostic communication (stdio/HTTP/SSE)
  2. Protocol Layer: Implements MCP specification for tool discovery and invocation
  3. Service Layer: Manages Elasticsearch connections and authentication
  4. Tool Layer: Provides domain-specific tools for Elasticsearch operations

This architecture enables the server to act as a bridge between AI agents and Elasticsearch clusters, translating natural language requests into structured queries while maintaining security through per-request authentication context propagation.

Source: https://github.com/elastic/mcp-server-elasticsearch / Human Manual

MCP Protocol Configuration

Related topics: Docker Deployment, System Architecture

Section Related Pages

Continue reading this section for the full explanation and source context.

Related topics: Docker Deployment, System Architecture

MCP Protocol Configuration

Overview

The Elasticsearch MCP Server supports multiple transport protocols for communicating with MCP clients. The protocol configuration system allows operators to choose between stdio (for direct client connections) and streamable-HTTP (for web-based integrations, stateful sessions, and concurrent clients). Source: README.md

The server implements the Model Context Protocol specification and provides flexible configuration options through both CLI arguments and configuration files. The configuration system is designed to support various deployment scenarios, from local development to production cloud environments.

Source: https://github.com/elastic/mcp-server-elasticsearch / Human Manual

Docker Deployment

Related topics: MCP Protocol Configuration, Authentication and Security, Configuration Reference

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Authentication Variables

Continue reading this section for the full explanation and source context.

Section Network Variables

Continue reading this section for the full explanation and source context.

Section Basic Stdio Command

Continue reading this section for the full explanation and source context.

Related topics: MCP Protocol Configuration, Authentication and Security, Configuration Reference

Docker Deployment

The Elasticsearch MCP Server is distributed as a Docker container image, providing a self-contained deployment mechanism that encapsulates all dependencies and configurations required to run the MCP server. This approach ensures consistent behavior across different environments and simplifies the deployment process for users who need to integrate the MCP server with AI agents and tools.

Architecture Overview

The Docker deployment architecture supports two primary protocol modes: stdio and streamable-HTTP. The stdio mode provides direct communication between the MCP client and server, while the HTTP mode enables remote connections and supports multiple concurrent clients. Both modes share the same underlying Elasticsearch client configuration and authentication mechanisms.

graph TD
    A[MCP Client] --> B{Docker Container}
    B --> C[Elasticsearch MCP Server]
    C --> D{Protocol Mode}
    D -->|Stdio| E[Direct Stdio Communication]
    D -->|HTTP| F[Streamable HTTP Endpoint]
    F --> G[Port 8080 or 8000]
    C --> H[Elasticsearch Cluster]
    
    I[Environment Variables] --> C
    J[Config File] --> C

Container Image

The official Docker image is published to the Elastic registry and uses a multi-stage build process to minimize the final image size. The image includes the compiled Rust binary and all necessary CA certificates for secure communication with Elasticsearch clusters.

PropertyValue
Image Registrydocker.elastic.co/mcp/elasticsearch
Default Port8080
Alternative Port8000
Base ImageDistroless/static (minimal attack surface)
UserNon-root (security hardened)

Environment Variables

The Docker container accepts configuration through environment variables. These variables are interpolated into a JSON5 configuration file at runtime, allowing flexible deployment scenarios without requiring custom configuration files.

Authentication Variables

VariableRequiredDescription
ES_URLYesElasticsearch cluster URL (e.g., https://your-cluster.es.amazonaws.com:9200)
ES_API_KEYConditionalElasticsearch API key for authentication (required if not using username/password)
ES_USERNAMEConditionalUsername for basic authentication
ES_PASSWORDConditionalPassword for basic authentication
ES_SSL_SKIP_VERIFYNoSet to true to skip SSL/TLS certificate verification (not recommended for production)

Source: src/lib.rs:setup_services()

Network Variables

VariableDescription
HTTP_ADDRESSSocket address for HTTP server binding (format: IP:PORT)
CLI_ARGSAdditional command-line arguments passed to the binary

Running in Stdio Mode

The stdio protocol provides the most straightforward deployment pattern for MCP clients that run in the same environment as the container. The server reads from stdin and writes to stdout, enabling direct communication with the MCP client.

Basic Stdio Command

docker run -i --rm \
  -e ES_URL="https://your-cluster.es.us-east-1.es.amazonaws.com:443" \
  -e ES_API_KEY="your-api-key-here" \
  docker.elastic.co/mcp/elasticsearch \
  stdio

Claude Desktop Configuration

To integrate the MCP server with Claude Desktop, add the following configuration to your Claude Desktop settings file:

{
  "mcpServers": {
    "elasticsearch-mcp-server": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "ES_URL",
        "-e", "ES_API_KEY",
        "docker.elastic.co/mcp/elasticsearch",
        "stdio"
      ],
      "env": {
        "ES_URL": "<elasticsearch-cluster-url>",
        "ES_API_KEY": "<elasticsearch-api-key>"
      }
    }
  }
}

Running in HTTP Mode

The streamable-HTTP protocol extends the MCP server's capabilities beyond local connections. This mode is recommended for web integrations, stateful sessions, and deployments that require supporting multiple concurrent clients.

Basic HTTP Command

docker run --rm \
  -e ES_URL="https://your-cluster.es.us-east-1.es.amazonaws.com:443" \
  -e ES_API_KEY="your-api-key-here" \
  -p 8080:8080 \
  docker.elastic.co/mcp/elasticsearch \
  http

HTTP Endpoints

EndpointMethodDescription
/mcpPOST/GETStreamable-HTTP MCP endpoint
/pingGETHealth check endpoint (returns pong)

Source: src/lib.rs:run_http()

HTTP-SSE Mode

For environments that require Server-Sent Events (SSE) for backwards compatibility, the HTTP server can be started with SSE support enabled:

docker run --rm \
  -e ES_URL \
  -e ES_API_KEY \
  -p 8080:8080 \
  docker.elastic.co/mcp/elasticsearch \
  http --sse

Note that SSE is deprecated in favor of streamable-HTTP. The streamable-HTTP protocol provides better streaming support and should be preferred for new deployments.

HTTP Address Configuration

By default, the HTTP server binds to 127.0.0.1:8080, restricting access to local connections only. To allow external access, specify the binding address explicitly:

docker run --rm \
  -e ES_URL \
  -e ES_API_KEY \
  -p 0.0.0.0:8080:8080 \
  docker.elastic.co/mcp/elasticsearch \
  http --address 0.0.0.0:8080

The server also respects the HTTP_ADDRESS environment variable for configuration.

Container Mode Host Resolution

The MCP server includes special handling for Docker container environments. When the Elasticsearch URL points to localhost, the server automatically attempts to resolve alternative hostnames that are commonly used for host access from within containers.

The following host aliases are checked in order:

AliasPlatform
host.docker.internalDocker Desktop (Linux, macOS, Windows)
docker.for.host.internalLegacy Docker for macOS
host.containers.internalPodman and other container runtimes

Source: src/servers/elasticsearch/mod.rs:container_mode()

If localhost is detected and no alias resolves successfully, the server logs a warning but continues operation:

tracing::warn!("Container mode: could not find a replacement for 'localhost'");

Configuration File

For more complex configurations, you can mount a configuration file into the container. The configuration supports JSON5 format, which allows comments and multi-line strings—useful for ES|QL queries.

Example Configuration File

{
  "elasticsearch": {
    "url": "${ES_URL}",
    "api_key": "${ES_API_KEY:}",
    "username": "${ES_USERNAME:}",
    "password": "${ES_PASSWORD:}",
    "ssl_skip_verify": "${ES_SSL_SKIP_VERIFY:false}"
  }
}

Running with Configuration File

docker run --rm \
  -v /path/to/config.json:/config.json:ro \
  -p 8080:8080 \
  docker.elastic.co/mcp/elasticsearch \
  http --config /config.json

The configuration file supports environment variable interpolation using the ${VAR} and ${VAR:default} syntax.

Security Considerations

Credential Handling

The Elasticsearch MCP Server follows security best practices for credential management:

  • API keys and passwords: Stored only in environment variables passed to the container. They are never persisted to disk or included in logs.
  • Environment variables: Set when running the container. Use secret management services like AWS Secrets Manager or AWS Systems Manager Parameter Store in production environments.
  • Non-root user: The container runs as a non-root user for security hardening.

Network Security

Security FeatureImplementation
TLS/SSLEnabled automatically when ES_URL uses https://
Certificate ValidationEnabled by default; disabled with ES_SSL_SKIP_VERIFY=true
Localhost BindingHTTP server binds to 127.0.0.1:8080 by default
Port ExposureOnly required ports should be exposed to the network

Best Practices

  • Rotate API keys regularly (every 30-90 days for production)
  • Use API keys with minimal required permissions
  • Never commit credentials to version control
  • Use secret management services for credential storage
  • Restrict network access to the container using firewall rules

Troubleshooting

Connection Issues

If the container fails to connect to Elasticsearch, verify the following:

  1. Check container logs: View logs using docker logs <container-id> to identify authentication or connection errors.

``bash docker exec <container-id> curl -k -u <username>:<password> <ES_URL> ` Or with an API key: `bash docker exec <container-id> curl -k -H "Authorization: ApiKey <api-key>" <ES_URL> ``

  1. Test Elasticsearch connectivity: From within the container:
  1. Verify network access: Ensure the container can reach the Elasticsearch cluster. For cloud deployments, check security groups and network ACLs.

Authentication Failures

Common authentication issues and solutions:

IssueSolution
401 UnauthorizedVerify ES_USERNAME and ES_PASSWORD are correct; check for typos in environment variable names
API key rejectedEnsure the API key has sufficient permissions for the operations being performed
Certificate errorsIf using a self-signed certificate, set ES_SSL_SKIP_VERIFY=true (development only)

Port Binding Issues

If port 8080 is already in use, either stop the conflicting service or use an alternative port:

docker run --rm \
  -e ES_URL \
  -e ES_API_KEY \
  -p 8081:8080 \
  docker.elastic.co/mcp/elasticsearch \
  http --address 0.0.0.0:8080

Health Check Verification

Verify the server is running correctly by checking the health endpoint:

curl http://localhost:8080/ping

A successful response returns pong, indicating the server is operational.

Building the Docker Image

For development or custom deployments, you can build the Docker image locally using the provided Makefile:

make docker-build

The Makefile targets include:

TargetDescription
docker-buildBuild the default Docker image
docker-build-8000Build the image with port 8000 as default
docker-pushPush the built image to the registry

Limitations and Known Issues

The following limitations are relevant to Docker deployment:

  • Nested mapping decoding: The get_mappings tool may fail with "error decoding response body" when nested properties are defined without explicitly specifying "type": "nested", even though the mapping is valid according to Elasticsearch specification. This is a known issue tracked at #185.
  • Basic auth configuration: Users have reported authentication failures when using basic authentication via Docker environment variables. Ensure environment variable names are correctly specified (ES_USERNAME, ES_PASSWORD) and that the credentials have appropriate permissions.
  • ARM64 support: The project currently publishes Linux AMD64 binaries. ARM64 support is requested by the community (issue #191) but not yet available.

Source: https://github.com/elastic/mcp-server-elasticsearch / Human Manual

Authentication and Security

Related topics: Docker Deployment, Troubleshooting Guide

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Supported Authentication Methods

Continue reading this section for the full explanation and source context.

Section Environment Variable Mapping

Continue reading this section for the full explanation and source context.

Section Authorization Header Handling

Continue reading this section for the full explanation and source context.

Related topics: Docker Deployment, Troubleshooting Guide

Authentication and Security

The Elasticsearch MCP Server implements a multi-layered authentication system that supports both static server-side credentials and dynamic per-request authentication headers. This design enables secure connections to Elasticsearch clusters while maintaining flexibility for different deployment scenarios, including proxy-based authentication flows.

Overview

The MCP server handles authentication at two distinct layers:

LayerPurposeSource
Server ConfigurationEstablishes baseline credentials for connecting to ElasticsearchEnvironment variables or config file
Per-Request AuthAllows MCP clients to inject authentication for specific requestsHTTP Authorization header

This dual-layer approach allows administrators to configure default credentials while still supporting scenarios where clients need to authenticate with different credentials or where a reverse proxy handles authentication delegation.

Configuration Options

The ElasticsearchMcpConfig struct in src/servers/elasticsearch/mod.rs defines the supported authentication parameters:

pub struct ElasticsearchMcpConfig {
    /// Cluster URL
    pub url: String,

    /// API key
    #[serde(default, deserialize_with = "none_if_empty_string")]
    pub api_key: Option<String>,

    /// Username
    #[serde(default, deserialize_with = "none_if_empty_string")]
    pub username: Option<String>,

    /// Password
    #[serde(default, deserialize_with = "none_if_empty_string")]
    pub password: Option<String>,

    /// Should we skip SSL certificate verification?
    #[serde(default, deserialize_with = "deserialize_bool_from_anything")]
    pub ssl_skip_verify: bool,
}

Source: src/servers/elasticsearch/mod.rs:98-120

Supported Authentication Methods

MethodConfigurationPriority
API KeyES_API_KEY environment variableHighest
Basic AuthenticationES_USERNAME + ES_PASSWORD environment variablesFallback
No AuthenticationNeither configuredWhen no credentials needed

The credential resolution logic follows this precedence:

let creds = if let Some(api_key) = config.api_key.clone() {
    Some(Credentials::EncodedApiKey(api_key))
} else if let Some(username) = config.username.clone() {
    let pwd = config.password.clone().ok_or(anyhow::Error::msg("missing password"))?;
    Some(Credentials::Basic(username, pwd))
} else {
    None
};

Source: src/servers/elasticsearch/mod.rs:160-168

Environment Variable Mapping

Environment VariableConfig FieldDescription
ES_URLurlElasticsearch cluster endpoint
ES_API_KEYapi_keyBase64-encoded API key
ES_USERNAMEusernameUsername for basic auth
ES_PASSWORDpasswordPassword for basic auth
ES_SSL_SKIP_VERIFYssl_skip_verifyDisable TLS verification (not recommended)

The configuration template demonstrates environment variable interpolation:

{
    "elasticsearch": {
        "url": "${ES_URL}",
        "api_key": "${ES_API_KEY:}",
        "username": "${ES_USERNAME:}",
        "password": "${ES_PASSWORD:}",
        "ssl_skip_verify": "${ES_SSL_SKIP_VERIFY:false}"
    }
}

Source: src/lib.rs:56-66

Per-Request Authentication

The EsClientProvider wraps the Elasticsearch client and implements dynamic credential injection for individual requests. This is particularly useful in HTTP/SSE deployment modes where clients may need to authenticate differently than the server's baseline configuration.

pub fn get(&self, context: RequestContext<RoleServer>) -> Cow<'_, Elasticsearch> {
    let client = &self.0;

    let Some(mut auth) = context
        .extensions
        .get::<Parts>()
        .and_then(|p| p.headers.get(header::AUTHORIZATION))
        .and_then(|h| h.to_str().ok())
    else {
        // No auth
        return Cow::Borrowed(client);
    };

    // MCP inspector insists on sending a bearer token and prepends "Bearer" to the value provided
    if auth.starts_with("Bearer ApiKey ") || auth.starts_with("Bearer Basic ") {
        auth = auth.trim_start_matches("Bearer ");
    }

    let transport = client
        .transport()
        .clone_with_auth(Some(Credentials::AuthorizationHeader(auth.to_string())));

    Cow::Owned(Elasticsearch::new(transport))
}

Source: src/servers/elasticsearch/mod.rs:126-151

Authorization Header Handling

The server intelligently processes the Authorization header by:

  1. Extracting the header value from the incoming HTTP request
  2. Stripping Bearer prefixes that some MCP clients (like the MCP Inspector) automatically prepend
  3. Creating a new Elasticsearch client transport with the extracted credentials
  4. Returning an owned Cow<Elasticsearch> to ensure the per-request client is used

Supported Per-Request Formats

FormatExample HeaderNotes
ApiKey <key>Authorization: ApiKey VGhpcyBpcyBhbiBhcGkga2V5...Direct API key
Basic <credentials>Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=Base64-encoded username:password
Bearer ApiKey <key>Authorization: Bearer ApiKey VGhpcyBpcyBhbiBhcGkga2V5...MCP Inspector format for API key
Bearer Basic <credentials>Authorization: Bearer Basic dXNlcm5hbWU6cGFzc3dvcmQ=MCP Inspector format for basic auth

Deployment Modes and Authentication

The MCP server supports multiple transport modes that interact differently with authentication:

Stdio Mode

In stdio mode, the server reads credentials exclusively from environment variables or the configuration file. Per-request authentication via HTTP headers is not applicable in this mode.

#[derive(Debug, Subcommand)]
pub enum Command {
    Stdio(StdioCommand),
    Http(HttpCommand),
}

#[derive(Debug, Args)]
pub struct StdioCommand {
    /// Config file
    #[clap(short, long)]
    pub config: Option<PathBuf>,
}

Source: src/cli.rs:42-52

HTTP/SSE Mode

In HTTP/SSE mode, the server can receive per-request authentication headers, enabling proxy-based authentication where the proxy handles credential validation and injects the appropriate Authorization header.

#[derive(Debug, Args)]
pub struct HttpCommand {
    /// Config file
    #[clap(short, long)]
    pub config: Option<PathBuf>,

    /// Address to listen to [default: 127.0.0.1:8080]
    #[clap(long, value_name = "IP_ADDRESS:PORT", env = "HTTP_ADDRESS")]
    pub address: Option<std::net::SocketAddr>,

    /// Also start an SSE server on '/sse'
    #[clap(long)]
    pub sse: bool,
}

Source: src/cli.rs:30-41

Authentication Flow Diagram

sequenceDiagram
    participant Client as MCP Client
    participant MCP as MCP Server
    participant ES as Elasticsearch

    Note over MCP: Configuration Load
    MCP->>MCP: Read ES_URL, ES_API_KEY/ES_USERNAME/ES_PASSWORD
    MCP->>MCP: Create base Elasticsearch client

    Note over Client,MCP: Per-Request Auth (HTTP mode only)
    Client->>MCP: HTTP Request + Authorization header
    MCP->>MCP: Extract Authorization header
    
    alt Authorization header present
        MCP->>MCP: Clone transport with new credentials
        MCP->>ES: Request with per-request auth
    else No Authorization header
        MCP->>ES: Request with base client auth
    end
    
    ES-->>MCP: Response
    MCP-->>Client: MCP Response

SSL/TLS Configuration

Certificate Verification

By default, the server validates SSL/TLS certificates when connecting to Elasticsearch. To disable verification (not recommended for production):

ES_SSL_SKIP_VERIFY=true

This sets ssl_skip_verify: true in the configuration, which is passed to the Elasticsearch HTTP transport.

Container Mode URL Rewriting

When running inside a container, localhost connections may need URL rewriting to reach the host machine:

if container_mode {
    rewrite_localhost(&mut url)?;
}

This ensures that http://localhost:9200 in a container context resolves to the actual host machine's Elasticsearch instance.

Common Issues and Troubleshooting

Issue: Basic Auth Failed - 401 Unauthorized

A frequently reported issue (#170) involves authentication failures even when credentials are correctly configured:

Symptoms:

  • Server logs show 401 Unauthorized
  • Environment variables ES_USERNAME, ES_PASSWORD are confirmed correct inside the container

Potential Causes:

CauseSolution
Conflicting env var namesUse ES_USERNAME and ES_PASSWORD (v0.4.5 updated env name)
Empty password stringEnsure ES_PASSWORD is not empty; use quotes if special characters present
API key takes precedenceIf ES_API_KEY is set, it overrides username/password

Diagnostic Steps:

  1. Verify all environment variables are correctly set
  2. Test connectivity directly to Elasticsearch with the same credentials
  3. For HTTP mode, check if a proxy is stripping or modifying the Authorization header

MCP Inspector Compatibility

The MCP Inspector prepends Bearer to authentication values. The server handles this by stripping the prefix:

if auth.starts_with("Bearer ApiKey ") || auth.starts_with("Bearer Basic ") {
    auth = auth.trim_start_matches("Bearer ");
}

This ensures compatibility with tools that follow the OAuth2 bearer token convention.

Security Best Practices

PracticeRecommendation
Credential StorageUse secrets management systems (AWS Secrets Manager, HashiCorp Vault) rather than plain environment variables
SSL VerificationKeep ES_SSL_SKIP_VERIFY=false in production; only disable for local development
API KeysPrefer API keys over username/password for machine-to-machine authentication
Network ExposureBind HTTP server to localhost (127.0.0.1) when possible; restrict network access
Proxy AuthenticationWhen using a reverse proxy, ensure it properly forwards or handles the Authorization header

Source: https://github.com/elastic/mcp-server-elasticsearch / Human Manual

Configuration Reference

Related topics: Docker Deployment, Authentication and Security

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Syntax

Continue reading this section for the full explanation and source context.

Section Example Usage

Continue reading this section for the full explanation and source context.

Section API Key Authentication

Continue reading this section for the full explanation and source context.

Related topics: Docker Deployment, Authentication and Security

Configuration Reference

The Elasticsearch MCP Server supports flexible configuration through configuration files and environment variables. This reference documents all available configuration options, their purposes, and usage patterns.

Overview

The server configuration defines how the MCP server connects to Elasticsearch and which tools and features to expose. Configuration can be provided through:

  1. Configuration file (JSON or JSON5 format) specified via CLI
  2. Environment variables for containerized deployments
  3. Default values built into the binary

Source: src/lib.rs:66-85

Configuration File Structure

The configuration file uses JSON5 format, which extends JSON with support for comments and trailing commas. This allows for human-readable configuration with documentation.

{
  "elasticsearch": {
    "url": "${ES_URL}",
    "api_key": "${ES_API_KEY:}",
    "username": "${ES_USERNAME:}",
    "password": "${ES_PASSWORD:}",
    "ssl_skip_verify": "${ES_SSL_SKIP_VERIFY:false}",
    "tools": {
      "custom": {
        // Custom tools configuration
      }
    },
    "prompts": []
  }
}

Source: src/lib.rs:66-79

Elasticsearch Configuration Options

The ElasticsearchMcpConfig struct defines all connection and behavior settings:

ParameterTypeDefaultDescription
urlString*(required)*Elasticsearch cluster URL (e.g., https://localhost:9200)
api_keyOption<String>NoneAPI key for authentication
usernameOption<String>NoneUsername for basic authentication
passwordOption<String>NonePassword for basic authentication
ssl_skip_verifyboolfalseSkip SSL certificate verification (not recommended for production)
toolsTools{}Custom tools configuration (ESQL, search templates)
promptsVec<String>[]List of prompt identifiers to expose

Source: src/servers/elasticsearch/mod.rs:101-129

Environment Variable Interpolation

The configuration system supports environment variable interpolation using ${VAR} or ${VAR:default} syntax. This enables containerized deployments and integration with orchestration systems.

Syntax

PatternBehavior
${VAR}Required variable - server fails if not set
${VAR:default}Optional variable with default value

Example Usage

# With all environment variables
ES_URL=https://elasticsearch:9200 \
ES_API_KEY=my-api-key \
./elastic-mcp stdio --config config.json5

# Using defaults (empty strings for optional vars)
ES_URL=https://elasticsearch:9200 \
./elastic-mcp stdio

The interpolator replaces ${VAR} patterns with actual environment variable values before JSON parsing occurs.

Source: src/utils/interpolator.rs:1-50

graph TD
    A[Config File or Built-in Defaults] --> B[Environment Variable Interpolation]
    B --> C[JSON5 Parsing]
    C --> D[serde_json5 Deserialization]
    D --> E[ElasticsearchMcpConfig]
    E --> F[Server Initialization]
    
    G[Environment Variables] -.->|${VAR} replacement| B

Authentication Configuration

The server supports multiple authentication methods. Only one should be configured per deployment.

API Key Authentication

{
  "elasticsearch": {
    "url": "https://elasticsearch:9200",
    "api_key": "${ES_API_KEY}"
  }
}

Username/Password Authentication

{
  "elasticsearch": {
    "url": "https://elasticsearch:9200",
    "username": "${ES_USERNAME}",
    "password": "${ES_PASSWORD}"
  }
}

Authentication Priority

When multiple authentication methods are specified:

  1. api_key takes precedence over username/password
  2. Both username and password must be present for basic auth

Source: src/servers/elasticsearch/mod.rs:70-81

CLI Configuration

Stdio Mode

Run the server in stdio mode for local integration with MCP clients:

elastic-mcp stdio [OPTIONS]
OptionDescription
-c, --config <PATH>Path to configuration file

Source: src/cli.rs:38-45

HTTP Mode

Run the server as an HTTP server for remote access:

elastic-mcp http [OPTIONS]
OptionEnvironment VariableDefaultDescription
-c, --config <PATH>-NonePath to configuration file
--address <ADDR>HTTP_ADDRESS127.0.0.1:8080Listen address
--sse-falseEnable SSE endpoint at /mcp/sse

Source: src/cli.rs:26-37

Address Binding Behavior

The server binds to different addresses based on execution mode:

ModeDefault AddressDescription
StdioN/ANo network binding required
HTTP127.0.0.1:8080Localhost only for security
HTTP (container)0.0.0.0:8080All interfaces for container networking

Source: src/lib.rs:90-99

Container Mode

When running inside a Docker container, the server can automatically rewrite localhost URLs to the host machine's address. This is enabled by passing the --container flag or setting the CONTAINER_MODE environment variable.

Supported Host Aliases

Container mode rewrites localhost to one of these addresses (in order of priority):

PlatformHost Alias
Docker Desktophost.docker.internal
Podmanhost.containers.internal
Kuberneteshost.containers.internal

Source: src/servers/elasticsearch/mod.rs:158-175

graph TD
    A[Container Mode Enabled] --> B{URL host = localhost?}
    B -->|Yes| C[Resolve alias addresses]
    B -->|No| E[Use URL as-is]
    C --> D[Rewrite to resolved address]
    D --> E
    E --> F[Create ES Client]
    
    F --> G[host.docker.internal]
    F --> H[host.containers.internal]

Custom Tools Configuration

The Tools struct allows exposing custom ES|QL queries and search templates as MCP tools:

{
  "elasticsearch": {
    "url": "https://elasticsearch:9200",
    "tools": {
      "custom": {
        "esql_query": {
          "type": "esql",
          "description": "Execute ES|QL query",
          "parameters": { /* JSON Schema */ },
          "query": "FROM my-index | LIMIT 10"
        },
        "search_template": {
          "type": "search_template",
          "description": "Execute search template",
          "template": {
            "id": "my-template"
          }
        }
      }
    }
  }
}

ES|QL Tool Configuration

FieldTypeDescription
typeStringMust be "esql"
descriptionStringHuman-readable tool description
parametersSchemaObjectJSON Schema for parameters
queryStringESQL query to execute
formatStringOutput format: json (default) or value

Source: src/servers/elasticsearch/mod.rs:35-68

Complete Configuration Example

{
  "elasticsearch": {
    // Connection settings
    "url": "${ES_URL}",
    "api_key": "${ES_API_KEY:}",
    "username": "${ES_USERNAME:}",
    "password": "${ES_PASSWORD:}",
    "ssl_skip_verify": "${ES_SSL_SKIP_VERIFY:false}",
    
    // Custom tools
    "tools": {
      "custom": {
        "log_analysis": {
          "type": "esql",
          "description": "Analyze recent error logs",
          "query": "FROM logs-* | WHERE level == 'ERROR' | LIMIT 100"
        }
      }
    },
    
    // Prompts to expose
    "prompts": []
  }
}

Environment Variable Reference

VariableRequiredDescription
ES_URLYesElasticsearch cluster URL
ES_API_KEYNo*API key for authentication
ES_USERNAMENo*Username for basic auth
ES_PASSWORDNo*Password for basic auth
ES_SSL_SKIP_VERIFYNoSet to true to skip SSL verification
CLI_ARGSNoAlternative to CLI arguments
HTTP_ADDRESSNoHTTP server listen address

*Either ES_API_KEY or both ES_USERNAME and ES_PASSWORD should be set.

Source: .env-example

Known Configuration Issues

Basic Auth 401 Unauthorized

If using basic authentication fails with 401 errors, verify that:

  1. Both ES_USERNAME and ES_PASSWORD are set
  2. The Elasticsearch user has sufficient permissions
  3. The credentials are correctly passed to the container

Container Mode URL Resolution

Container mode requires the host alias to be resolvable. If you see warnings about failing to rewrite localhost, ensure:

  • Docker Desktop is running (for host.docker.internal)
  • Podman socket is active (for host.containers.internal)

Source: src/servers/elasticsearch/mod.rs:169-170

Configuration Schema

The complete JSON Schema for validation:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "required": ["elasticsearch"],
  "properties": {
    "elasticsearch": {
      "type": "object",
      "required": ["url"],
      "properties": {
        "url": { "type": "string", "format": "uri" },
        "api_key": { "type": ["string", "null"] },
        "username": { "type": ["string", "null"] },
        "password": { "type": ["string", "null"] },
        "ssl_skip_verify": { "type": "boolean" },
        "tools": { "$ref": "#/definitions/Tools" },
        "prompts": { "type": "array", "items": { "type": "string" } }
      }
    }
  }
}

Source: src/servers/elasticsearch/mod.rs:101-129

Source: https://github.com/elastic/mcp-server-elasticsearch / Human Manual

Troubleshooting Guide

Related topics: Authentication and Security, Monitoring and Health Checks, Available MCP Tools

Section Related Pages

Continue reading this section for the full explanation and source context.

Section 401 Unauthorized with Basic Auth

Continue reading this section for the full explanation and source context.

Section API Key Authentication

Continue reading this section for the full explanation and source context.

Section Empty Elasticsearch URL

Continue reading this section for the full explanation and source context.

Related topics: Authentication and Security, Monitoring and Health Checks, Available MCP Tools

Troubleshooting Guide

This guide covers common issues encountered when deploying and using the Elasticsearch MCP Server, with solutions based on the codebase and reported community issues.

Authentication Failures

401 Unauthorized with Basic Auth

Users deploying via Docker have reported authentication failures even when credentials appear correct.

Common Causes:

IssueCauseSolution
Environment variable nameES_lOGIN is a typo; use ES_USERNAMEUse ES_USERNAME and ES_PASSWORD correctly
Missing passwordUsername provided without passwordAlways provide ES_PASSWORD when ES_USERNAME is set
Container env setupVariables not properly passed to containerVerify -e flags in docker run command

Source: The server validates credentials in src/servers/elasticsearch/mod.rs:47-54:

let creds = if let Some(api_key) = config.api_key.clone() {
    Some(Credentials::EncodedApiKey(api_key))
} else if let Some(username) = config.username.clone() {
    let pwd = config.password.clone().ok_or(anyhow::Error::msg("missing password"))?;
    Some(Credentials::Basic(username, pwd))
} else {
    None
};

Verification Steps:

``bash docker exec -it <container_name> env | grep ES_ ``

  1. Enter the container and confirm environment variables:
  1. Verify the correct variable names are used:
  • ES_URL - Elasticsearch cluster URL
  • ES_USERNAME - Username (NOT ES_lOGIN)
  • ES_PASSWORD - Password
  • ES_API_KEY - API key (alternative to username/password)
  1. Test authentication directly against Elasticsearch using the same credentials.

API Key Authentication

When using API key authentication, ensure the key is properly formatted and has sufficient permissions.

Configuration:

{
  "elasticsearch": {
    "url": "${ES_URL}",
    "api_key": "${ES_API_KEY:}"
  }
}

The server will use api_key if provided, falling back to username/password authentication. Source: src/servers/elasticsearch/mod.rs:47

Configuration Issues

Empty Elasticsearch URL

The server fails to start with an empty ES_URL:

Error: "Elasticsearch URL is empty"

Source: src/servers/elasticsearch/mod.rs:53-55:

let url = config.url.as_str();
if url.is_empty() {
    return Err(anyhow::Error::msg("Elasticsearch URL is empty"));
}

Solution: Ensure ES_URL is set to a valid Elasticsearch endpoint (e.g., https://localhost:9200).

SSL Certificate Verification Failures

For development or testing with self-signed certificates:

Configuration option:

{
  "elasticsearch": {
    "url": "${ES_URL}",
    "ssl_skip_verify": "${ES_SSL_SKIP_VERIFY:false}"
  }
}

Set ES_SSL_SKIP_VERIFY=true to skip SSL verification. Source: src/servers/elasticsearch/mod.rs:33-34

Environment Variable Interpolation

The server supports ${VAR_NAME:default_value} syntax in configuration files.

Source: src/utils/interpolator.rs:17-38:

if line.starts_with("${") {
    if let Some(end) = line.find("$}") {
        let expr = &line[2..end];
        let value = if let Some((name, default)) = expr.split_once(':') {
            lookup(name).unwrap_or(default.to_string())
        } else {
            lookup(expr).ok_or_else(|| err(...))?
        };
        result.push_str(&value);
    }
}

Example:

{
  "elasticsearch": {
    "url": "${ES_URL:http://localhost:9200}",
    "api_key": "${ES_API_KEY:}",
    "username": "${ES_USERNAME:}",
    "password": "${ES_PASSWORD:}",
    "ssl_skip_verify": "${ES_SSL_SKIP_VERIFY:false}"
  }
}

Config File Parsing Errors

Configuration files support JSON5 (JSON with comments and trailing commas).

Error format for parsing failures:

{
  "elasticsearch": {
    "url": "http://localhost:9200"
    // Missing comma above causes parsing error
  }
}

Source: src/lib.rs:58-63:

let config: Configuration = match serde_json5::from_str(&config) {
    Ok(c) => c,
    Err(serde_json5::Error::Message { msg, location }) if location.is_some() => {
        let location = location.unwrap();
        anyhow::bail!("Failed to parse config: {msg}, at line {line} column {column}");
    }
    Err(err) => return Err(err)?,
};

Tool-Specific Issues

get_mappings Decoding Error

Issue: get_mappings tool fails with "error decoding response body" when index mappings contain nested properties defined without explicit "type": "nested".

This is a known limitation when Elasticsearch returns mappings that are technically valid but contain implicit nested type declarations.

Source: The tool uses read_json to parse responses in src/servers/elasticsearch/base_tools.rs:140-150:

async fn get_mappings(
    &self,
    req_ctx: RequestContext<RoleServer>,
    Parameters(GetMappingsParams { index }): Parameters<GetMappingsParams>,
) -> Result<CallToolResult, rmcp::Error> {
    let es_client = self.es_client.get(req_ctx);
    let response = es_client.indices().get_mapping(GetMappingParts::Index(&[&index])).send().await;
    let mapping: GetMappingResponse = read_json(response).await?;
}

Workaround: Ensure your Elasticsearch index mappings explicitly define the type property for nested fields:

{
  "mappings": {
    "properties": {
      "nested_field": {
        "type": "nested"
      }
    }
  }
}

search Tool Aggregation Results

The search tool returns aggregation results alongside hits:

Source: src/servers/elasticsearch/base_tools.rs:153-177:

let response: SearchResult = read_json(response).await?;
let mut results: Vec<Content> = Vec::new();

// Send result stats only if it's not pure aggregation results
if response.aggregations.is_empty() || !response.hits.hits.is_empty() {
    let total = response.hits.total.map(|t| t.value).unwrap_or(0);
    results.push(Content::text(format!("Found {} hits:", total)));
}

// Include aggregations if present
if !response.aggregations.is_empty() {
    results.push(Content::text("Aggregations:"));
    results.push(Content::json(response.aggregations)?);
}

ES|QL Query Response Format

ES|QL queries transform columnar results into object format:

Source: src/servers/elasticsearch/base_tools.rs:186-203:

let response: EsqlQueryResponse = read_json(response).await?;

// Transform response into an array of objects
let mut objects: Vec<Value> = Vec::new();
for row in response.values.into_iter() {
    let mut obj = Map::new();
    for (i, value) in row.into_iter().enumerate() {
        obj.insert(response.columns[i].name.clone(), value);
    }
    objects.push(Value::Object(obj));
}

Deployment Issues

Docker Container Mode

When running in Docker, the server rewrites localhost references to enable container-to-container communication.

Source: src/servers/elasticsearch/mod.rs:57:

if container_mode {
    rewrite_localhost(&mut url)?;
}

Default Ports:

ModeDefault AddressEnvironment Variable
Docker (HTTP)0.0.0.0:8080HTTP_ADDRESS
Local (HTTP)127.0.0.1:8080HTTP_ADDRESS
StdioN/AN/A

Source: src/lib.rs:47-53:

let address: SocketAddr = if let Some(addr) = cmd.address {
    addr
} else if container_mode {
    SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 8080)
} else {
    SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080)
};

HTTP Transport Endpoints

When running in HTTP mode:

EndpointPurpose
/mcpStreamable-HTTP MCP endpoint
/pingHealth check endpoint

Source: src/cli.rs:37-45:

pub struct HttpCommand {
    /// Config file
    #[clap(short, long)]
    pub config: Option<PathBuf>,

    /// Address to listen to [default: 127.0.0.1:8080]
    #[clap(long, value_name = "IP_ADDRESS:PORT", env = "HTTP_ADDRESS")]
    pub address: Option<std::net::SocketAddr>,

    /// Also start an SSE server on '/sse'
    #[clap(long)]
    pub sse: bool,
}

Common Docker Deployment Errors

Container exits immediately:

  1. Check logs: docker logs <container_name>
  2. Verify environment variables are set
  3. Ensure Elasticsearch URL is accessible from container

Port already in use:

# Check what's using port 8080
lsof -i :8080
# Use different port
docker run -p 8081:8080 ...

Error Handling Reference

Server Error Responses

The server uses the rmcp::Error type for MCP protocol errors:

Source: src/servers/elasticsearch/mod.rs:66-74:

pub fn handle_error(result: Result<Response, elasticsearch::Error>) -> Result<Response, rmcp::Error> {
    match result {
        Ok(resp) => resp.error_for_status_code(),
        Err(e) => {
            tracing::error!("Error: {:?}", &e);
            Err(e)
        }
    }
    .map_err(internal_error)
}

Common Error Messages

ErrorCauseResolution
error decoding response bodyInvalid JSON in ES responseCheck ES version compatibility; verify index mappings
Request failed (remote)ES cluster unreachableVerify ES_URL; check network/firewall
missing passwordUsername set without passwordProvide ES_PASSWORD or use API key auth
Elasticsearch URL is emptyES_URL not setSet ES_URL environment variable

Diagnostic Checklist

When troubleshooting, verify:

  • [ ] ES_URL is set and points to a reachable Elasticsearch cluster
  • [ ] Authentication credentials (API key or username/password) are correct
  • [ ] If using Basic auth, both ES_USERNAME and ES_PASSWORD are set (not ES_lOGIN)
  • [ ] SSL certificate issues: set ES_SSL_SKIP_VERIFY=true for self-signed certs
  • [ ] Docker networking allows container to reach Elasticsearch
  • [ ] Index name is correct (use list_indices tool to verify)
  • [ ] User has necessary Elasticsearch permissions for the requested operations

Getting Help

For additional support:

  1. Search existing GitHub issues
  2. Check the Dependency Dashboard for known dependency-related issues
  3. Enable debug logging by setting RUST_LOG=debug when running the server

Source: https://github.com/elastic/mcp-server-elasticsearch / Human Manual

Monitoring and Health Checks

Related topics: Troubleshooting Guide, Docker Deployment

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Available Endpoints

Continue reading this section for the full explanation and source context.

Section Readiness Probe

Continue reading this section for the full explanation and source context.

Section Liveness Probe

Continue reading this section for the full explanation and source context.

Related topics: Troubleshooting Guide, Docker Deployment

Monitoring and Health Checks

The Elasticsearch MCP Server provides a comprehensive monitoring infrastructure to verify server operational status, validate Elasticsearch connectivity, and troubleshoot deployment issues. This page documents all health check endpoints, monitoring tools, and diagnostic procedures available to operators.

Health Check Endpoints

When running in HTTP mode, the MCP server exposes dedicated health check endpoints under the /_health path. These endpoints integrate with Kubernetes liveness/readiness probes, load balancers, and monitoring systems.

Available Endpoints

EndpointPathMethodPurpose
Readiness/_health/readyGETIndicates server can accept requests
Liveness/_health/liveGETIndicates server process is alive
Ping/pingGETBasic connectivity verification
Hello/GETServer version and endpoint info

Readiness Probe

The readiness endpoint signals when the server is fully initialized and ready to process MCP requests:

GET /_health/ready HTTP/1.1

Response:

HTTP/1.1 200 OK
Ready

The server becomes ready once the tool list is loaded and the Elasticsearch client is initialized. Source: src/protocol/http.rs:1-50

Liveness Probe

The liveness endpoint confirms the server process is running:

GET /_health/live HTTP/1.1

Response:

HTTP/1.1 200 OK
Alive

This endpoint returns immediately without checking Elasticsearch connectivity, making it suitable for detecting crashed processes. Source: src/protocol/http.rs:1-50

Ping Endpoint

The ping endpoint provides a quick health verification:

GET /ping HTTP/1.1

Response:

HTTP/1.1 200 OK
Ready

A successful pong response indicates the server is running and healthy. Source: README.md

Monitoring Tools

The MCP server exposes Elasticsearch monitoring tools that agents can invoke to gather cluster health information. These tools are available as MCP tool calls through the stdio or HTTP interfaces.

Tool Reference

ToolPurposeRead-Only
list_indicesList available Elasticsearch indicesYes
get_shardsRetrieve shard allocation informationYes
get_mappingsFetch index field mappingsYes
searchExecute search queriesYes
esqlRun ESQL queriesYes

Shard Monitoring

The get_shards tool provides detailed shard distribution information across the cluster:

{
  "name": "get_shards",
  "arguments": {
    "index": "optional-index-name"
  }
}

Parameters:

ParameterTypeRequiredDescription
indexStringNoSpecific index name; omit for all indices

Response Fields:

FieldDescription
indexIndex name
shardShard number
prirepPrimary (P) or replica (R)
stateShard state (STARTED, INITIALIZING, etc.)
docsDocument count
storeStore size
nodeNode name housing the shard

This tool was introduced in v0.2.0 for cluster monitoring purposes. Source: src/servers/elasticsearch/base_tools.rs:1-50

Index Listing

The list_indices tool enumerates all indices accessible to the authenticated user:

{
  "name": "list_indices",
  "arguments": {
    "index_pattern": "*"
  }
}

Response Structure:

[
  {
    "index": "index-name",
    "status": "open",
    "doc_count": 12345
  }
]

Mappings Retrieval

The get_mappings tool retrieves field mappings for index analysis:

{
  "name": "get_mappings",
  "arguments": {
    "index": "my-index"
  }
}

Note: There is a known issue where certain valid Elasticsearch mapping definitions with omitted nested types may cause "error decoding response body" errors. This occurs when a property is defined without explicitly specifying "type": "nested". Source: Community Issue #185

Architecture

Health Check Request Flow

graph TD
    A[External Monitor] -->|HTTP GET| B[Main Router]
    B -->|Route| C[Health Router]
    C -->|/ready| D[Readiness Check]
    C -->|/live| E[Liveness Check]
    C -->|/ping| F[Basic Ping]
    
    D -->|Initialize| G[Tool List Loaded]
    G -->|ES Client Ready| H[200 OK]
    
    E --> I[Process Alive]
    I --> J[200 OK]
    
    F --> K[Server Responding]
    K --> L[pong]

HTTP Server Structure

The HTTP server is built using the Axum framework with a layered router configuration:

graph TD
    A[TCP Listener] --> B[Graceful Shutdown Handler]
    B --> C[Main Router]
    
    C -->|/| D[Hello Endpoint]
    C -->|/ping| E[Ping Endpoint]
    C -->|/mcp| F[MCP Handler]
    C -->|/mcp/sse| G[SSE Handler]
    C -->|/_health| H[Health Router]
    
    H -->|/ready| I[Readiness Probe]
    H -->|/live| J[Liveness Probe]

Source: src/protocol/http.rs:1-50

Troubleshooting

Common Issues

#### Authentication Failures

Symptom: 401 Unauthorized errors when the server attempts to connect to Elasticsearch.

Diagnostic Steps:

``bash docker exec <container-id> env | grep ES_ ``

  1. Verify environment variables inside the container:
  1. Confirm credentials are correctly set:
  • ES_API_KEY for API key authentication
  • ES_USERNAME and ES_PASSWORD for basic auth

```bash # Basic auth docker exec <container-id> curl -k -u <username>:<password> <ES_URL>

  1. Test connectivity directly from the container:

# API key docker exec <container-id> curl -k -H "Authorization: ApiKey <api-key>" <ES_URL> ```

Source: README.md

#### Container Logs Analysis

View logs to identify connection or authentication issues:

docker logs <container-id>

Look for these error patterns:

Error PatternLikely Cause
Connection refusedElasticsearch URL incorrect or ES not running
401 UnauthorizedInvalid credentials
certificate verify failedSSL verification issue

#### Elasticsearch Connectivity Verification

From within the container, verify network connectivity:

docker exec <container-id> curl -k -u <username>:<password> <ES_URL>/_cluster/health

A successful response with cluster health JSON confirms the container can reach Elasticsearch.

Health Check Configuration

The default bind address is 127.0.0.1:8080, configurable via:

OptionEnvironment VariableCLI Flag
Bind addressHTTP_ADDRESS--address

Example configuration:

# Environment variable
HTTP_ADDRESS=0.0.0.0:8080

# CLI argument
--address 0.0.0.0:8080

Source: src/cli.rs

Best Practices

Kubernetes Probes

Configure Kubernetes probes to use the health check endpoints:

livenessProbe:
  httpGet:
    path: /_health/live
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /_health/ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

Monitoring Integration

  • Use /ping for load balancer health checks
  • Use /_health/ready for orchestration readiness signals
  • Use /_health/live for process liveness detection
  • Leverage get_shards tool for detailed cluster state monitoring via MCP

Security Considerations

  • Health endpoints do not require authentication by default
  • Restrict access using network policies in production
  • The /ping endpoint returns minimal information suitable for public exposure

Configuration Reference

Health Router Configuration

The health router is mounted at /_health within the main application router:

let health_router = Router::new()
    .route("/ready", get(async || (StatusCode::OK, "Ready\n")))
    .route("/live", get(async || "Alive\n"));

Source: src/protocol/http.rs:1-50

Server Initialization

Health endpoints become available after successful server initialization:

let handler = elasticsearch::ElasticsearchMcp::new_with_config(config.elasticsearch, container_mode)?;

The server is ready when the EsBaseTools handler is constructed with a valid Elasticsearch client. Source: src/lib.rs

Deprecation Notice

The Elasticsearch MCP Server is deprecated as of v0.4.6. For production monitoring workloads, consider migrating to the Elastic Agent Builder MCP endpoint available in Elastic 9.2.0+ and Elasticsearch Serverless projects. Source: README.md

Source: https://github.com/elastic/mcp-server-elasticsearch / Human Manual

Contributing Guide

Related topics: System Architecture

Section Related Pages

Continue reading this section for the full explanation and source context.

Section Prerequisites

Continue reading this section for the full explanation and source context.

Section Initial Setup

Continue reading this section for the full explanation and source context.

Section Running the Server Locally

Continue reading this section for the full explanation and source context.

Related topics: System Architecture

Contributing Guide

Welcome to the Elasticsearch MCP Server contributing guide. This document provides comprehensive instructions for developers who want to contribute to the project, covering development environment setup, coding standards, testing procedures, and submission workflows.

Overview

The Elasticsearch MCP Server is a Rust-based implementation of the Model Context Protocol (MCP) that enables AI agents to interact with Elasticsearch clusters. The project uses the rmcp framework for MCP protocol handling and the official Elasticsearch Rust client for cluster communication.

Contributions are welcome from the community. Before submitting changes, please review this guide thoroughly to ensure your contributions align with the project's standards and requirements.

Development Environment Setup

Prerequisites

RequirementVersionPurpose
Rust1.75+Primary language runtime
CargoLatest stablePackage manager and build tool
Docker24.0+Container runtime for testing
Elasticsearch8.x or 9.xTarget cluster for integration testing

Initial Setup

``bash git clone https://github.com/elastic/mcp-server-elasticsearch.git cd mcp-server-elasticsearch ``

  1. Clone the repository

``bash cargo fetch ``

  1. Install Rust dependencies

``bash cargo build ``

  1. Verify the build compiles successfully

Running the Server Locally

The project provides a helper script for running the server during development:

./scripts/cargo-run.sh

This script wraps the cargo run command with appropriate environment configuration for local development.

Project Structure

mcp-server-elasticsearch/
├── src/
│   ├── servers/
│   │   └── elasticsearch/
│   │       ├── base_tools.rs    # Core MCP tool implementations
│   │       └── mod.rs            # Server configuration and initialization
│   ├── utils/
│   │   ├── interpolator.rs       # Environment variable interpolation
│   │   ├── mod.rs                # Utility module exports
│   │   └── rmcp_ext.rs           # MCP SDK extensions
│   ├── cli.rs                    # Command-line interface
│   └── lib.rs                    # Library entry point
├── tests/                        # Integration tests
├── Makefile                      # Build and development tasks
├── Cargo.toml                    # Rust dependencies and metadata
└── rustfmt.toml                  # Code formatting configuration

Code Style and Standards

Formatting

The project uses rustfmt for consistent code formatting. Configuration is defined in rustfmt.toml:

SettingValueDescription
max_width100Maximum line length
tab_spaces4Indentation size
edition2021Rust edition

Format your code before committing:

cargo fmt --check

Linting

Run clippy for linting checks:

cargo clippy --all-targets --all-features

Address all warnings and errors reported by clippy before submitting your pull request.

Code Organization

The codebase follows these architectural patterns:

  • Tool Implementation: MCP tools are defined using the #[tool] macro and implemented in src/servers/elasticsearch/base_tools.rs
  • Configuration: Configuration parsing uses serde with JSON5 support for comments in config files
  • Error Handling: The project uses anyhow::Error for flexible error handling
  • HTTP Authentication: The EsClientProvider supports authorization header passthrough for HTTP transport mode

Testing

Unit Tests

Run unit tests with:

cargo test

Integration Testing

Integration tests require a running Elasticsearch cluster. Configure the test environment using environment variables:

Environment VariableDescriptionRequired
ES_URLElasticsearch cluster URLYes
ES_API_KEYAPI key for authenticationNo*
ES_USERNAMEUsername for basic authNo*
ES_PASSWORDPassword for basic authNo*

*Either API key or username/password combination required

Build Verification

Use the Makefile to verify the complete build:

make build

MCP Tool Development

Defining New Tools

Tools are defined using the #[tool] attribute macro. The framework expects specific parameters:

#[tool(
    description = "Tool description for LLM context",
    annotations(title = "Display title", read_only_hint = true)
)]
async fn my_tool(
    &self,
    req_ctx: RequestContext<RoleServer>,
    Parameters(ToolParams): Parameters<ToolParams>,
) -> Result<CallToolResult, rmcp::Error> {
    // Implementation
}

Tool Parameters

Parameter types must implement serde::Deserialize and schemars::JsonSchema:

#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]
struct MyToolParams {
    /// Parameter description for schema generation
    param_name: String,
}

Response Format

Return tool results using CallToolResult::success() with a vector of Content items:

Ok(CallToolResult::success(vec![
    Content::text("Description"),
    Content::json(data)?,
]))

Submitting Changes

Branch Strategy

``bash git checkout -b feature/my-feature ``

  1. Create a feature branch from main:
  1. Make your changes following the coding standards

``bash git commit -m "Add support for new ES|QL aggregation function" ``

  1. Commit with clear, descriptive messages:

Pull Request Checklist

  • [ ] Code formatted with cargo fmt
  • [ ] Clippy warnings resolved
  • [ ] Tests pass with cargo test
  • [ ] New tools include parameter documentation
  • [ ] Configuration changes documented in relevant files
  • [ ] Commit messages follow conventional format

Commit Message Format

<type>(<scope>): <description>

[optional body]

Types: feat, fix, docs, style, refactor, test, chore

Build and Release Process

Build Targets

The project supports multiple build targets:

TargetPlatformArchitecture
x86_64-unknown-linux-muslLinuxx86_64
x86_64-apple-darwinmacOSx86_64
aarch64-apple-darwinmacOSARM64
x86_64-pc-windows-msvcWindowsx86_64

Using Makefile

The Makefile provides convenient build targets:

make build       # Build release binary
make test        # Run test suite
make check       # Run formatting and clippy
make clean       # Clean build artifacts

Known Limitations

When contributing, be aware of the following known issues:

  1. Nested Mappings Issue: The get_mappings tool may fail with "error decoding response body" when nested properties omit explicit type specification. See Issue #185.
  1. Basic Auth Configuration: Authentication via environment variables requires specific naming (ES_USERNAME, ES_PASSWORD). See Issue #170.
  1. Platform Binaries: Currently, Linux ARM64 binaries are not published. See Issue #191.

Getting Help

If you encounter issues while contributing:

License

By contributing to this project, you agree that your contributions will be licensed under the Apache License, Version 2.0. See the NOTICE.txt file for details.

Source: https://github.com/elastic/mcp-server-elasticsearch / Human Manual

Doramagic Pitfall Log

Source-linked risks stay visible on the manual page so the preview does not read like a recommendation.

medium Installation risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Installation risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Configuration risk requires verification

May increase setup, validation, or first-run risk for the user.

medium Capability evidence risk requires verification

May increase setup, validation, or first-run risk for the user.

Doramagic Pitfall Log

Found 10 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Installation risk - Installation risk requires verification.

1. Installation risk: Installation risk requires verification

  • Severity: medium
  • Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: identity.distribution | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch

2. Installation risk: Installation risk requires verification

  • Severity: medium
  • Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: community_evidence:github | cevd_5573c160ecdd4e34be6dbf6549fe2529 | https://github.com/elastic/mcp-server-elasticsearch/issues/6

3. Configuration risk: Configuration risk requires verification

  • Severity: medium
  • Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: capability.host_targets | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch

4. Capability evidence risk: Capability evidence risk requires verification

  • Severity: medium
  • Finding: README/documentation is current enough for a first validation pass.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: capability.assumptions | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch

5. Maintenance risk: Maintenance risk requires verification

  • Severity: medium
  • Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch

6. Security or permission risk: Security or permission risk requires verification

  • Severity: medium
  • Finding: no_demo
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: downstream_validation.risk_items | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch

7. Security or permission risk: Security or permission risk requires verification

  • Severity: medium
  • Finding: no_demo
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: risks.scoring_risks | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch

8. Security or permission risk: Security or permission risk requires verification

  • Severity: medium
  • Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: community_evidence:github | cevd_f8732a2deab341d6b739b122459d1243 | https://github.com/elastic/mcp-server-elasticsearch/issues/185

9. Maintenance risk: Maintenance risk requires verification

  • Severity: low
  • Finding: issue_or_pr_quality=unknown。
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch

10. Maintenance risk: Maintenance risk requires verification

  • Severity: low
  • Finding: release_recency=unknown。
  • User impact: May increase setup, validation, or first-run risk for the user.
  • Recommended check: Reproduce the official install and quickstart path in an isolated environment.
  • Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch

Source: Doramagic discovery, validation, and Project Pack records

Community Discussion Evidence

These external discussion links are review inputs, not standalone proof that the project is production-ready.

Sources 7

Count of project-level external discussion links exposed on this manual page.

Use Review before install

Open the linked issues or discussions before treating the pack as ready for your environment.

Community Discussion Evidence

Doramagic exposes project-level community discussion separately from official documentation. Review these links before using mcp-server-elasticsearch with real data or production workflows.

Source: Project Pack community evidence and pitfall evidence