# https://github.com/elastic/mcp-server-elasticsearch 项目说明书

生成时间：2026-05-31 01:03:00 UTC

## 目录

- [项目介绍](#page-intro)
- [版本历史与更新](#page-changelog)
- [系统架构](#page-architecture)
- [通信协议配置](#page-protocols)
- [MCP 工具详解](#page-tools)
- [配置与工具过滤](#page-config)
- [Docker 部署指南](#page-deployment)
- [认证配置](#page-auth)
- [故障排除指南](#page-troubleshooting)
- [安全最佳实践](#page-security)

<a id='page-intro'></a>

## 项目介绍

### 相关页面

相关主题：[系统架构](#page-architecture), [Docker 部署指南](#page-deployment)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [catalog-info.yaml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/catalog-info.yaml)
- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)
- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)
- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)
- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)
- [renovate.json](https://github.com/elastic/mcp-server-elasticsearch/blob/main/renovate.json)
</details>

# 项目介绍

## 概述

Elasticsearch MCP Server 是由 Elastic 公司开发的 Model Context Protocol (MCP) 服务器实现，专门用于将 Elasticsearch 集群与 AI 助手（如 Claude、Cursor 等）进行集成。该项目允许 AI 代理通过标准化接口执行 Elasticsearch 操作，包括索引查询、映射获取、分片状态检查等高级功能。

资料来源：[catalog-info.yaml:4]()

### 项目定位

| 属性 | 值 |
|------|-----|
| 类型 | 库 (library) |
| 所属团队 | devtools-team |
| 生命周期 | beta (测试阶段) |
| 版权 | Elasticsearch B.V. 2025 |

资料来源：[catalog-info.yaml:6-10]()

## 核心架构

### 整体架构图

```mermaid
graph TD
    A["MCP Client<br/>(Claude/Cursor)"] --> B["Elasticsearch MCP Server"]
    B --> C["Elasticsearch Cluster"]
    
    B --> D["base_tools<br/>基础工具集"]
    B --> E["custom_tools<br/>自定义工具"]
    
    D --> D1["list_indices"]
    D --> D2["get_mappings"]
    D --> D3["search"]
    D --> D4["get_shards"]
    D --> D5["esql"]
    
    E --> E1["ESQL 查询"]
    E --> E2["搜索模板"]
    
    C --> F["REST API"]
```

### 组件层次结构

```mermaid
graph TD
    A["ElasticsearchMcp"] --> B["EsBaseTools"]
    B --> C["EsClientProvider"]
    C --> D["Elasticsearch<br/>HTTP Client"]
    
    B --> E["ToolRouter<br/>工具路由器"]
    E --> F["工具处理器"]
    
    A --> G["Configuration<br/>配置管理"]
    G --> H["环境变量解析"]
    G --> I["配置文件加载"]
```

资料来源：[src/servers/elasticsearch/mod.rs:77-93]()

## 工具集详解

### 基础工具 (Base Tools)

项目提供五个核心工具用于日常 Elasticsearch 操作：

| 工具名称 | 功能描述 | 只读 |
|----------|----------|------|
| `list_indices` | 列出所有符合条件的 Elasticsearch 索引 | 是 |
| `get_mappings` | 获取指定索引的字段映射信息 | 是 |
| `search` | 使用 Query DSL 执行搜索查询 | 是 |
| `get_shards` | 获取索引分片分配状态信息 | 是 |
| `esql` | 执行 ES|QL 查询语句 | 是 |

资料来源：[src/servers/elasticsearch/base_tools.rs:1-100]()

### 搜索功能增强

`search` 工具支持以下高级特性：

- **字段选择**：通过 `fields` 参数指定返回字段，减少上下文大小
- **聚合支持**：自动返回聚合结果，支持复杂分析查询
- **Query DSL 完整支持**：支持 query、size、from、sort 等完整查询语法

```rust
// 搜索结果数据结构
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>,
}
```

资料来源：[src/servers/elasticsearch/base_tools.rs:100-130]()

### 自定义工具 (Custom Tools)

支持扩展的工具类型：

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

pub enum EsqlResultFormat {
    Json,   // 默认，输出 JSON 数组或对象
    Value,  // 单属性时仅输出值
}
```

资料来源：[src/servers/elasticsearch/mod.rs:20-35]()

## 配置系统

### 配置结构

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

### 环境变量配置

| 变量名 | 必填 | 说明 |
|--------|------|------|
| `ES_URL` | 是 | Elasticsearch 集群 URL |
| `ES_API_KEY` | 否 | API Key 认证 |
| `ES_USERNAME` | 否 | 用户名（需配合密码使用） |
| `ES_PASSWORD` | 否 | 密码 |
| `ES_SSL_SKIP_VERIFY` | 否 | 跳过 SSL 证书验证 |

资料来源：[src/lib.rs:1-30]()

### 配置加载流程

```mermaid
sequenceDiagram
    participant CLI as 命令行
    participant Config as 配置解析器
    participant Interpolator as 变量插值器
    participant ES as ElasticsearchMcp

    CLI->>Config: 加载配置文件
    Config->>Interpolator: 解析 ${VAR:default} 语法
    Interpolator-->>Config: 返回展开后的配置
    Config->>ES: new_with_config(config)
    ES->>ES: 创建连接池和认证
    ES-->>CLI: 返回处理器实例
```

## 通信协议

### 支持的传输模式

| 模式 | 说明 | 使用场景 |
|------|------|----------|
| `stdio` | 标准输入/输出 | 本地 Claude Desktop 集成 |
| `http` | Streamable HTTP | Web 集成、远程访问 |

资料来源：[src/cli.rs:30-50]()

### HTTP 服务配置

```rust
pub struct HttpCommand {
    /// 配置文件路径
    pub config: Option<PathBuf>,
    
    /// 监听地址 [default: 127.0.0.1:8080]
    pub address: Option<std::net::SocketAddr>,
    
    /// 启用 SSE 服务于 '/sse'
    pub sse: bool,
}
```

| 参数 | 默认值 | 环境变量 |
|------|--------|----------|
| `--address` | 127.0.0.1:8080 | `HTTP_ADDRESS` |
| `--config` | 无 | 无 |
| `--sse` | false | 无 |

资料来源：[src/cli.rs:35-48]()

## 认证机制

### 认证流程

```mermaid
graph LR
    A["请求上下文"] --> B{"授权头存在?"}
    B -->|是| C["使用请求头认证"]
    B -->|否| D{"配置中有凭证?"}
    D -->|API Key| E["EncodedApiKey"]
    D -->|用户名密码| F["Basic Auth"]
    D -->|无| G["匿名访问"]
```

### 凭证优先级

1. HTTP 请求头中的 `Authorization`
2. 配置中的 `api_key`
3. 配置中的 `username` + `password`

资料来源：[src/servers/elasticsearch/mod.rs:80-95]()

## 部署方式

### Docker 部署

```bash
# Stdio 模式
docker run --rm \
  -e ES_URL \
  -e ES_API_KEY \
  docker.elastic.co/mcp/elasticsearch \
  stdio

# HTTP 模式
docker run --rm \
  -e ES_URL \
  -e ES_API_KEY \
  -p 8080:8080 \
  docker.elastic.co/mcp/elasticsearch \
  http
```

### Claude Desktop 配置 (Stdio)

```json
{
  "mcpServers": {
    "elasticsearch-mcp-server": {
      "command": "docker",
      "args": [
        "run", "--rm",
        "-e", "ES_URL",
        "-e", "ES_API_KEY",
        "docker.elastic.co/mcp/elasticsearch",
        "stdio"
      ]
    }
  }
}
```

### HTTP 模式配置

通过 `mcp-proxy` 桥接到 Claude Desktop：

```bash
uv tool install mcp-proxy
```

```json
{
  "mcpServers": {
    "elasticsearch-mcp-server": {
      "command": "/path/to/mcp-proxy",
      "args": [
        "--transport=streamablehttp",
        "--header", "Authorization", "ApiKey <key>",
        "http://host:8080/mcp"
      ]
    }
  }
}
```

## 已知问题与限制

### 社区反馈的问题

| 问题编号 | 描述 | 状态 |
|----------|------|------|
| #185 | `get_mappings` 工具在嵌套类型未显式声明时解码失败 | 待修复 |
| #170 | Basic 认证失败 (401 Unauthorized) | 社区讨论中 |
| #191 | 缺少 Linux ARM64 二进制发布 | 功能请求 |

### 健康检查

HTTP 模式提供健康检查端点：

```bash
curl http://<host>:8080/ping
# 返回: pong
```

## 版本历史

| 版本 | 主要变更 |
|------|----------|
| v0.4.6 | 添加弃用通知 |
| v0.4.5 | 修复用户名环境变量名称 |
| v0.4.4 | 添加 CA 证书支持 |
| v0.4.3 | 默认端口改回 8080 |
| v0.4.2 | 默认端口改为 8000 |
| v0.4.1 | 添加 `CLI_ARGS` 环境变量支持 |
| v0.3.1 | 修复 `npx` 执行缺少 hashbang |
| v0.3.0 | 添加 OpenTelemetry 支持、Smithery 配置 |

## 技术栈

| 组件 | 技术 |
|------|------|
| 语言 | Rust |
| HTTP 客户端 | elasticsearch-rs |
| MCP 框架 | rmcp |
| 序列化 | serde_json, serde_json5 |
| 宏处理 | rmcp_macros |
| CLI | clap |

## 依赖管理

项目使用 Renovate 进行自动化依赖更新：

- 计划：每周一 1:00 后执行
- 配置：继承自 `elastic/renovate-config`

```json
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["local>elastic/renovate-config"],
  "schedule": ["after 1am on monday"]
}
```

资料来源：[renovate.json:1-8]()

## 持续集成

项目使用 Buildkite 进行 CI/CD：

| 流水线 | 触发条件 | 说明 |
|--------|----------|------|
| mcp-server-elasticsearch | PR、推送 | 执行检查 |
| mcp-server-elasticsearch-docker | Tags | 构建并发布 Docker 镜像 |

资料来源：[catalog-info.yaml:20-80]()

---

<a id='page-changelog'></a>

## 版本历史与更新

### 相关页面

相关主题：[项目介绍](#page-intro), [故障排除指南](#page-troubleshooting)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [NOTICE.txt](https://github.com/elastic/mcp-server-elasticsearch/blob/main/NOTICE.txt)
- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)
- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)
- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)
- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)
- [renovate.json](https://github.com/elastic/mcp-server-elasticsearch/blob/main/renovate.json)
</details>

# 版本历史与更新

Elasticsearch MCP Server 是由 Elasticsearch B.V. 开发维护的 Model Context Protocol (MCP) 服务器实现，旨在为 AI 代理提供与 Elasticsearch 集群交互的能力。本页面记录该项目的完整版本历史、功能演进以及重要更新信息。

## 版本发布时间线

```mermaid
timeline
    title Elasticsearch MCP Server 版本发布历史
    v0.2.0 : 新增 get_shards 工具
             灵活认证验证
             索引模式参数
    v0.3.0 : Smithery 配置支持
             OpenTelemetry 支持
             聚合结果返回
             profile 和 explain
    v0.3.1 : 修复 npx hashbang 问题
    v0.4.1 : Dockerfile EXPOSE
             CLI_ARGS 环境变量
    v0.4.2 : 默认端口 8000
    v0.4.3 : 默认端口恢复 8080
    v0.4.4 : 添加 CA 证书
    v0.4.5 : 用户名 ENV 名称更新
    v0.4.6 : 添加弃用通知
```

## 各版本详细说明

### v0.4.6（最新版本）

**发布状态**：当前稳定版本

**主要变更**：添加了项目弃用通知（Deprecation Notice），提示用户项目已进入维护模式。

资料来源：[社区发布说明](https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.6)

---

### v0.4.5

**主要变更**：

| 变更类型 | PR 编号 | 贡献者 | 说明 |
|---------|---------|--------|------|
| 修复 | #158 | @mol91 | 更新用户名环境变量名称 |

该版本修复了环境变量命名问题，使认证配置更加直观。

资料来源：[社区发布说明](https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.5)

---

### v0.4.4

**主要变更**：

| 变更类型 | PR 编号 | 贡献者 | 说明 |
|---------|---------|--------|------|
| 修复 | #145 | @swallez | 添加 CA 证书支持 |

此版本添加了对 CA 证书的支持，增强了 SSL/TLS 连接的安全性验证。

资料来源：[社区发布说明](https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.4)

---

### v0.4.3

**主要变更**：

| 变更类型 | PR 编号 | 贡献者 | 说明 |
|---------|---------|--------|------|
| 修复 | #144 | @swallez | 将默认端口改回 8080 |

此版本将 HTTP 服务器的默认端口从 v0.4.2 的 8000 改回 8080，保持与之前版本的一致性。

资料来源：[社区发布说明](https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.3)

---

### v0.4.2

**主要变更**：

| 变更类型 | PR 编号 | 贡献者 | 说明 |
|---------|---------|--------|------|
| 修复 | #142 | @JoshMock | 将默认端口改为 8000 |

资料来源：[社区发布说明](https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.2)

---

### v0.4.1

**主要变更**：

| 变更类型 | 提交 | 说明 |
|---------|------|------|
| 修复 | 0cc4d1fe | 添加 Dockerfile `EXPOSE 8080` 指令 |
| 修复 | 336f4635 | 添加 `CLI_ARGS` 环境变量作为传参替代方案 |

此版本改进了 Docker 部署体验，提供了更灵活的配置方式。

资料来源：[社区发布说明](https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.1)

---

### v0.3.1

**主要变更**：

| 变更类型 | PR 编号 | 贡献者 | 说明 |
|---------|---------|--------|------|
| 修复 | #122 | @JoshMock | 修复 `npx -y @elastic/mcp-server-elasticsearch` 缺少 hashbang 的问题 |

此版本修复了通过 npx 方式运行时的可执行性问题。

资料来源：[社区发布说明](https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.3.1)

---

### v0.3.0

**主要变更**：

| 变更类型 | PR 编号 | 贡献者 | 功能说明 |
|---------|---------|--------|----------|
| 功能 | #31 | @calclavia | Smithery 配置支持 |
| 功能 | #64 | @anuraaga | OpenTelemetry 支持 |
| 功能 | #46 | @sternbergm | 搜索工具添加聚合结果返回 |

此版本是一个重要的功能版本，引入了多项关键功能：

1. **Smithery 配置**：支持通过 Smithery 平台进行安装配置
2. **OpenTelemetry 支持**：集成了分布式追踪能力，便于监控和调试
3. **聚合结果**：search 工具现在可以返回聚合查询结果

资料来源：[社区发布说明](https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.3.0)

---

### v0.2.0

**主要变更**：

| 变更类型 | PR 编号 | 贡献者 | 功能说明 |
|---------|---------|--------|----------|
| 功能 | #25 | @getsolaris | 新增 `get_shards` 工具 |
| 功能 | #27 | @getsolaris | 更灵活的认证验证 |
| 功能 | #100 | @susan-shu-c | list_indices 工具添加索引模式参数 |

此版本奠定了 MCP Server 的核心工具集基础。

资料来源：[社区发布说明](https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.2.0)

---

## 工具演进历史

### 核心工具列表

| 工具名称 | 首次引入版本 | 功能描述 |
|----------|-------------|----------|
| `list_indices` | v0.2.0 | 列出所有可用的 Elasticsearch 索引 |
| `get_shards` | v0.2.0 | 获取索引分片信息 |
| `search` | 初始版本 | 使用 Query DSL 执行搜索查询 |
| `get_mappings` | 初始版本 | 获取索引映射定义 |
| ES\|QL | v0.3.0 | 执行 ES|QL 查询 |
| Search Template | 后续版本 | 使用搜索模板执行查询 |

### 工具实现架构

```mermaid
graph TD
    A[MCP Client] -->|Request| B[ServerHandler]
    B --> C[EsBaseTools]
    C --> D{工具类型}
    D -->|list_indices| E[cat.indices API]
    D -->|get_shards| F[cat.shards API]
    D -->|search| G[search API]
    D -->|get_mappings| H[mappings API]
    D -->|esql| I[esql API]
    
    E --> J[Elasticsearch Cluster]
    F --> J
    G --> J
    H --> J
    I --> J
```

资料来源：[src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)

---

## 协议与传输模式演进

### 支持的传输模式

| 模式 | 支持版本 | 说明 |
|------|---------|------|
| stdio | v0.2.0 起 | 标准输入输出模式，适用于本地 CLI |
| HTTP | v0.4.x | Streamable HTTP 模式 |
| SSE | v0.4.x | Server-Sent Events（已弃用） |

### HTTP 端点配置

```rust
#[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,
}
```

资料来源：[src/cli.rs:32-47](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)

### HTTP 路由结构

| 端点 | 方法 | 功能 |
|------|------|------|
| `/` | GET | 服务信息 |
| `/ping` | GET | 健康检查 |
| `/mcp` | POST | MCP 请求端点 |
| `/mcp/sse` | GET | SSE 连接端点 |
| `/_health/ready` | GET | 就绪探针 |
| `/_health/live` | GET | 存活探针 |

资料来源：[src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)

---

## 认证机制演进

### 支持的认证方式

| 认证方式 | 配置参数 | 说明 |
|----------|---------|------|
| API Key | `ES_API_KEY` | Base64 编码的 API 密钥 |
| Basic Auth | `ES_USERNAME` + `ES_PASSWORD` | 用户名密码认证 |

### 认证配置代码

```rust
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
        };
        // ...
    }
}
```

资料来源：[src/servers/elasticsearch/mod.rs:94-107](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)

### 已知认证问题

**Issue #170**：部分用户反馈在使用 Docker 部署时，即使环境变量配置正确，仍然出现 401 Unauthorized 错误。建议检查：

1. 环境变量名称是否正确（`ES_USERNAME` 而非 `ES_lOGIN`）
2. Elasticsearch 集群的认证配置
3. 网络连通性

---

## 依赖更新管理

### Renovate 配置

项目使用 Renovate 进行自动化依赖更新管理：

```json
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": [
    "local>elastic/renovate-config"
  ],
  "schedule": [
    "after 1am on monday"
  ]
}
```

资料来源：[renovate.json](https://github.com/elastic/mcp-server-elasticsearch/blob/main/renovate.json)

### 更新策略

- **更新频率**：每周一凌晨 1 点后自动检查更新
- **仪表板**：通过 [Issue #6](https://github.com/elastic/mcp-server-elasticsearch/issues/6) 查看所有待处理和已完成的依赖更新

---

## 已知问题与限制

### get_mappings 工具问题

**Issue #185**：当 mapping 中 nested 属性未显式指定 `"type": "nested"` 时，`get_mappings` 工具会返回 `"error decoding response body"` 错误，尽管该 mapping 在 Elasticsearch 规范中是有效的。

**状态**：社区已报告，等待修复。

### 其他社区关注的问题

| Issue | 标题 | 关注度 |
|-------|------|--------|
| #17 | Support streamable HTTP | 4 评论 |
| #170 | Basic auth failed - 401 Unauthorized | 22 评论 |
| #45 | Add Aggregation results to return fields | 1 评论 |
| #191 | Publish a linux arm64 binary | 3 评论 |
| #173 | Error messages for some functions | 4 评论 |

---

## 版权与许可

```
Elasticsearch MCP Server
Copyright 2025 Elasticsearch B.V.
```

资料来源：[NOTICE.txt](https://github.com/elastic/mcp-server-elasticsearch/blob/main/NOTICE.txt)

---

## 相关资源

| 资源类型 | 链接 |
|---------|------|
| GitHub 仓库 | https://github.com/elastic/mcp-server-elasticsearch |
| 问题反馈 | https://github.com/elastic/mcp-server-elasticsearch/issues |
| 版本发布页 | https://github.com/elastic/mcp-server-elasticsearch/releases |
| MCP 协议文档 | https://modelcontextprotocol.io |
| Renovate 配置 | [renovate.json](https://github.com/elastic/mcp-server-elasticsearch/blob/main/renovate.json) |

---

<a id='page-architecture'></a>

## 系统架构

### 相关页面

相关主题：[项目介绍](#page-intro), [通信协议配置](#page-protocols), [MCP 工具详解](#page-tools)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)
- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)
- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)
- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)
- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)
</details>

# 系统架构

## 概述

Elasticsearch MCP Server 是一个基于 Model Context Protocol (MCP) 的中间件服务，用于将 Elasticsearch 集群与 AI 代理进行连接。它充当协议转换层，将 MCP 协议请求转换为 Elasticsearch HTTP API 调用，并返回结构化结果。

**核心职责**：
- 接收来自 MCP 客户端（如 Claude Desktop、Cursor 等）的标准化工具调用请求
- 验证认证信息并建立与 Elasticsearch 集群的连接
- 将请求路由至相应的工具处理器并执行查询
- 将 Elasticsearch 响应转换回 MCP 协议格式返回

**技术栈**：
- 语言：Rust
- MCP 协议：rmcp (Rust MCP 实现)
- Elasticsearch 客户端：elasticsearch crate

资料来源：[src/lib.rs:1-50](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)

---

## 架构分层

```mermaid
graph TD
    subgraph "接入层"
        A[MCP 客户端]
        B[Stdio Transport]
        C[Streamable HTTP Transport]
    end
    
    subgraph "协议层"
        D[MCP 协议解析器]
        E[工具调用分发]
    end
    
    subgraph "业务层"
        F[EsBaseTools 工具集]
        G[CustomTool 自定义工具]
        H[EsClientProvider 客户端管理]
    end
    
    subgraph "通信层"
        I[Elasticsearch HTTP API]
    end
    
    subgraph "外部服务"
        J[Elasticsearch 集群]
    end
    
    A --> B
    A --> C
    B --> D
    C --> D
    D --> E
    E --> F
    E --> G
    F --> H
    G --> H
    H --> I
    I --> J
```

---

## 服务器模式

MCP Server 支持两种运行模式，通过命令行子命令选择：

### Stdio 模式

标准输入输出模式，适用于本地进程通信场景。这是 MCP 的传统传输方式。

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

配置示例：
```json
{
  "command": "docker",
  "args": ["run", "--rm", "-e", "ES_URL=https://localhost:9200", 
           "-e", "ES_API_KEY=<key>", "mcp-server-elasticsearch", "stdio"],
  "env": {}
}
```

资料来源：[src/cli.rs:30-45](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)

### HTTP 模式

支持远程访问的 HTTP 服务器模式，默认监听 `127.0.0.1:8080`。

```rust
#[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,
}
```

**启动命令示例**：
```bash
./mcp-server-elasticsearch http --address 0.0.0.0:8080
```

> [!NOTE]
> 社区反馈显示，HTTP/SSE 模式在某些 AI 代理（如 n8n）中存在兼容性问题。参见 [Issue #173](https://github.com/elastic/mcp-server-elasticsearch/issues/173)。

---

## 配置系统

### 配置层次结构

```mermaid
graph LR
    A[环境变量] --> B[interpolator]
    C[config.json5] --> B
    B --> D[Configuration]
    D --> E[ElasticsearchMcpConfig]
    D --> F[McpServer]
```

### 主配置结构

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

资料来源：[src/cli.rs:95-105](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)

### Elasticsearch 配置项

| 参数 | 环境变量 | 类型 | 默认值 | 说明 |
|------|----------|------|--------|------|
| url | `ES_URL` | String | - | Elasticsearch 集群地址 |
| api_key | `ES_API_KEY` | Option<String> | None | API Key 认证 |
| username | `ES_USERNAME` | Option<String> | None | 用户名（需配合 password） |
| password | `ES_PASSWORD` | Option<String> | None | 密码（需配合 username） |
| ssl_skip_verify | `ES_SSL_SKIP_VERIFY` | bool | false | 跳过 SSL 证书验证 |

```rust
#[derive(Debug, Serialize, Deserialize)]
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>,
}
```

资料来源：[src/servers/elasticsearch/mod.rs:60-90](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)

### 环境变量插值

配置文件中支持 `${VAR_NAME}` 和 `${VAR_NAME:default_value}` 语法：

```rust
let value = if let Some((name, default)) = expr.split_once(':') {
    lookup(name).unwrap_or(default.to_string())
} else {
    lookup(expr).ok_or_else(|| err(char_no, format!("env variable '{expr}' not defined")))?
};
```

**示例配置**：

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

资料来源：[src/utils/interpolator.rs:40-50](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)

---

## 认证机制

### 认证流程

```mermaid
sequenceDiagram
    participant MCP as MCP 客户端
    participant Server as MCP Server
    participant ES as Elasticsearch
    
    MCP->>Server: 请求 (含 Authorization Header)
    Server->>Server: 检查 Authorization Header
    
    alt 使用请求头中的认证
        Server->>ES: 转发 Authorization Header
    else 使用配置中的认证
        Server->>ES: 使用配置的 API Key 或 Basic Auth
    end
    
    ES-->>Server: 响应
    Server-->>MCP: 处理结果
```

### 认证凭证类型

```rust
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
        };
        
        // ... 构建 Transport
        if let Some(creds) = creds {
            transport = transport.auth(creds);
        }
    }
}
```

### 优先级规则

1. **请求级别**：如果传入的 HTTP 请求包含 `Authorization` Header，则优先使用
2. **配置级别**：否则使用配置文件中的认证信息

```rust
/// 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 {
```

资料来源：[src/servers/elasticsearch/mod.rs:105-130](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)

---

## 工具系统

### 内置工具

| 工具名称 | 功能 | 只读 | 参数 |
|----------|------|------|------|
| `list_indices` | 列出匹配的索引 | 是 | `index_pattern: String` |
| `get_mappings` | 获取索引映射 | 是 | `index: String` |
| `get_shards` | 获取分片信息 | 是 | `index: Option<String>` |
| `search` | 执行搜索查询 | 是 | `index, fields?, query_body` |
| `esql` | 执行 ES\|QL 查询 | 是 | `query: String` |

### 工具定义示例

```rust
#[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> {
    let es_client = self.es_client.get(req_ctx);
    
    let response = es_client
        .cat()
        .indices(CatIndicesParts::Index(&[&index_pattern]))
        .h(&["index", "status", "docs.count"])
        .format("json")
        .send()
        .await;

    let response: Vec<CatIndexResponse> = read_json(response).await?;

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

资料来源：[src/servers/elasticsearch/base_tools.rs:80-105](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)

### 自定义工具

除内置工具外，系统还支持通过配置文件定义自定义工具：

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

**自定义工具配置示例**：

```json
{
  "tools": {
    "custom": {
      "my_esql_tool": {
        "type": "esql",
        "description": "Run specific ES|QL query",
        "parameters": {},
        "query": "FROM my-index | LIMIT 10"
      }
    }
  }
}
```

### SearchTemplate 工具

支持将预定义的搜索模板暴露为 MCP 工具：

```rust
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SearchTemplate {
    TemplateId(String),
    Template(serde_json::Value),
}
```

---

## 数据模型

### 搜索响应

```rust
#[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 Hit {
    #[serde(rename = "_source")]
    pub source: Value,
}
```

### 映射响应

```rust
#[derive(Serialize, Deserialize)]
pub struct 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>,
}
```

> [!WARNING]
> 社区反馈显示，`get_mappings` 工具在处理嵌套类型属性时存在问题。当嵌套属性未显式声明 `"type": "nested"` 时，服务器会抛出 "error decoding response body" 错误。参见 [Issue #185](https://github.com/elastic/mcp-server-elasticsearch/issues/185)。

---

## 请求处理流程

```mermaid
graph TD
    A[接收 MCP 请求] --> B{解析请求类型}
    
    B -->|工具调用| C[分发至工具处理器]
    B -->|资源请求| D[返回资源数据]
    B -->|提示请求| E[返回预定义提示]
    
    C --> F{选择认证方式}
    
    F -->|使用配置的认证| G[从配置构建凭证]
    F -->|使用请求头认证| H[从 Authorization Header 提取]
    
    G --> I[构建 Elasticsearch 客户端]
    H --> I
    
    I --> J[发送 HTTP 请求到 ES]
    J --> K{ES 响应状态}
    
    K -->|成功 2xx| L[读取响应体]
    K -->|错误 4xx/5xx| M[构建错误响应]
    
    L --> N{解析响应格式}
    N -->|JSON| O[反序列化为结构体]
    N -->|纯文本| P[直接返回]
    
    O --> Q[构建 MCP CallToolResult]
    P --> Q
    
    M --> R[返回 rmcp::Error]
    Q --> S[返回给 MCP 客户端]
```

### 错误处理

```rust
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)
}
```

资料来源：[src/servers/elasticsearch/mod.rs:140-155](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)

---

## 核心组件关系

```mermaid
classDiagram
    class ElasticsearchMcp {
        +new_with_config(config, container_mode) EsBaseTools
    }
    
    class EsBaseTools {
        +es_client: EsClientProvider
        +tool_router: ToolRouter~EsBaseTools~
    }
    
    class EsClientProvider {
        -client: Elasticsearch
        +get(context) Elasticsearch
    }
    
    class ElasticsearchMcpConfig {
        +url: String
        +api_key: Option~String~
        +username: Option~String~
        +password: Option~String~
        +ssl_skip_verify: bool
    }
    
    ElasticsearchMcp --> ElasticsearchMcpConfig : 配置
    ElasticsearchMcp --> EsBaseTools : 创建
    EsBaseTools --> EsClientProvider : 持有
    EsClientProvider --> Elasticsearch : HTTP 客户端
```

---

## MCP 服务器配置

```rust
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
#[serde(tag = "type")]
pub enum McpServer {
    Sse(Http),
    StreamableHttp(Http),
    Stdio(Stdio),
}
```

| 类型 | 用途 | 配置项 |
|------|------|--------|
| `Sse` | Server-Sent Events 模式 | url, headers |
| `StreamableHttp` | 可流式传输的 HTTP | url, headers |
| `Stdio` | 标准输入输出模式 | command, args, env |

---

## 启动流程

```mermaid
sequenceDiagram
    participant Main as main.rs
    participant Lib as lib.rs
    participant CLI as cli.rs
    participant Server as MCP Server
    
    Main->>CLI: 解析命令行参数
    Main->>Lib: 调用创建处理器
    Lib->>Lib: 加载配置文件
    Lib->>Lib: 环境变量插值
    Lib->>Lib: 构建 ElasticsearchMcpConfig
    Lib->>Server: new_with_config()
    Server->>Server: 构建 EsClientProvider
    Server->>Server: 注册工具处理器
    Main->>Server: 启动服务器循环
```

初始化流程（简化版）：

```rust
// 1. 加载默认配置模板
let config = r#"{
    "elasticsearch": {
        "url": "${ES_URL}",
        "api_key": "${ES_API_KEY:}",
        "username": "${ES_USERNAME:}",
        "password": "${ES_PASSWORD:}",
        "ssl_skip_verify": "${ES_SSL_SKIP_VERIFY:false}"
    }
}"#.to_string();

// 2. 环境变量插值
let config = interpolator::interpolate_from_env(config)?;

// 3. JSON5 解析（支持注释）
let config: Configuration = serde_json5::from_str(&config)?;

// 4. 构建处理器
let handler = elasticsearch::ElasticsearchMcp::new_with_config(
    config.elasticsearch, 
    container_mode
)?;
```

资料来源：[src/lib.rs:20-45](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)

---

## 安全考虑

### 凭证管理

| 凭证类型 | 存储位置 | 说明 |
|----------|----------|------|
| API Key | 环境变量 | 推荐生产环境使用 |
| 用户名/密码 | 环境变量 | 需配合使用 |
| Authorization Header | HTTP 请求头 | 支持 per-request 认证 |

### 网络安全

- **HTTPS**：当 `ES_URL` 使用 `https://` 时自动启用 TLS 加密
- **容器模式**：自动重写 `localhost` 为 `host.docker.internal` 以支持 Docker 网络

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

### 证书验证

- **验证启用**：`ES_SSL_SKIP_VERIFY=false`（默认）
- **验证跳过**：`ES_SSL_SKIP_VERIFY=true`（仅用于测试环境）

---

<a id='page-protocols'></a>

## 通信协议配置

### 相关页面

相关主题：[系统架构](#page-architecture), [Docker 部署指南](#page-deployment)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)
- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)
- [src/protocol/stdio.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/stdio.rs)
- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)
- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)
- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)
</details>

# 通信协议配置

## 概述

Elasticsearch MCP Server 支持两种通信协议模式，用于与 MCP 客户端建立连接并传输数据。协议配置是整个服务架构的核心组成部分，决定了客户端如何与服务器通信、认证方式如何处理，以及请求如何在 MCP 协议层进行路由。

本项目实现了 **Stdio（标准输入/输出）** 和 **HTTP/SSE（服务器发送事件）** 两种传输模式，分别适用于不同的部署场景和客户端类型。

## 协议架构

```mermaid
graph TD
    A[MCP 客户端] --> B{传输模式选择}
    B -->|Stdio| C[Stdio 协议层]
    B -->|HTTP/SSE| D[HTTP 协议层]
    C --> E[rmcp 框架]
    D --> E
    E --> F[工具路由器 ToolRouter]
    F --> G[Elasticsearch 工具集]
    G --> H[Elasticsearch 集群]
    
    style C fill:#e1f5fe
    style D fill:#fff3e0
```

## 传输模式

### Stdio 模式

Stdio 模式是最基础的通信方式，通过标准输入（stdin）和标准输出（stdout）进行 JSON-RPC 消息的传输。这种模式适用于本地进程调用和命令行工具集成。

**配置参数：**

| 参数 | 标志 | 说明 |
|------|------|------|
| 配置文件 | `-c, --config` | 可选配置文件路径 |
| 传输类型 | `stdio` | 通过 stdin/stdout 通信 |

Stdio 模式的启动命令：

```bash
mcp-server-elasticsearch stdio --config /path/to/config.json
```

### HTTP/SSE 模式

HTTP 模式提供了远程访问能力，支持通过 HTTP 请求与 MCP 服务器交互。该模式使用 Axum 框架构建异步 HTTP 服务器，并可选地启用 SSE（Server-Sent Events）端点实现服务端推送。

**核心配置参数：**

| 参数 | 环境变量 | 默认值 | 说明 |
|------|----------|--------|------|
| 监听地址 | `HTTP_ADDRESS` | `127.0.0.1:8080` | 服务器监听的网络地址 |
| SSE 启用 | `--sse` | 关闭 | 是否启用 SSE 端点 |
| 配置文件 | `-c, --config` | 无 | 配置文件路径 |

HTTP 模式的启动命令：

```bash
mcp-server-elasticsearch http --address 0.0.0.0:8080 --config /path/to/config.json
```

启用 SSE 模式：

```bash
mcp-server-elasticsearch http --address 0.0.0.0:8080 --sse
```

**服务端点：**

| 端点 | 方法 | 功能 |
|------|------|------|
| `/` | GET | 服务器信息 |
| `/ping` | GET | 健康检查 |
| `/mcp/sse` | SSE | SSE 传输端点 |
| `/mcp` | MCP | MCP 协议处理 |
| `/_health/ready` | GET | 就绪探针 |
| `/_health/live` | GET | 存活探针 |

```mermaid
sequenceDiagram
    participant C as MCP 客户端
    participant H as HTTP 服务器
    participant M as MCP 处理层
    participant ES as Elasticsearch
    
    C->>H: HTTP POST /mcp (JSON-RPC)
    H->>M: 转发请求
    M->>ES: 执行查询
    ES-->>M: 返回结果
    M-->>H: JSON-RPC 响应
    H-->>C: HTTP Response
    
    Note over C,H: SSE 模式可选用于服务端推送
    C->>H: GET /mcp/sse
    H-->>C: SSE Stream
```

## 命令行接口结构

源码位置：[src/cli.rs:1-100](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)

### Command 枚举

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

服务器支持两个顶层命令，分别对应不同的协议模式：

- `Stdio` - 启动标准输入/输出服务器
- `Http` - 启动 HTTP 服务器（可选 SSE）

### HttpCommand 配置

```rust
#[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,
}
```

## HTTP 协议实现

源码位置：[src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)

### 健康检查路由

服务器实现了标准的 Kubernetes 就绪/存活探针接口：

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

### 路由聚合

```rust
let main_router = Router::new()
    .route("/", get(hello))
    .route("/ping", get(async || (StatusCode::OK, "Ready\n")))
    .nest("/mcp/sse", sse_router)
    .nest("/mcp", sh_router)
    .nest("/_health", health_router)
    .with_state(());
```

### 服务器启动

```rust
let listener = tokio::net::TcpListener::bind(config.bind).await?;
let server = axum::serve(listener, main_router).with_graceful_shutdown({
    let ct = ct.clone();
    async move {
        ct.cancelled().await;
        tracing::info!("http server cancelled");
    }
});
```

## 认证与客户端上下文

源码位置：[src/servers/elasticsearch/mod.rs:100-150](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)

### Credentials 配置

```rust
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,
}
```

### 认证凭证构建

```rust
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
};
```

### EsClientProvider 客户端提供者

```rust
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 {
        // 根据请求上下文获取客户端实例
    }
}
```

## 配置加载流程

源码位置：[src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)

```mermaid
flowchart LR
    A[启动应用] --> B[解析命令行参数]
    B --> C{协议模式}
    C -->|stdio| D[启动 Stdio 服务器]
    C -->|http| E[启动 HTTP 服务器]
    E --> F[加载配置文件]
    F --> G[环境变量插值]
    G --> H[解析 JSON5 配置]
    H --> I[构建 Elasticsearch 客户端]
    I --> J[初始化工具路由]
    J --> K[等待客户端连接]
```

### 环境变量插值

配置支持 `${VAR_NAME}` 和 `${VAR_NAME:default_value}` 语法：

```rust
let config = interpolator::interpolate_from_env(config)?;
```

### 默认配置模板

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

## 协议选择指南

| 场景 | 推荐模式 | 原因 |
|------|----------|------|
| 本地开发调试 | Stdio | 简单直接，无需网络配置 |
| Claude Desktop / Cursor | Stdio | 原生支持 MCP stdio 协议 |
| 远程服务部署 | HTTP | 支持网络访问和负载均衡 |
| n8n 集成 | HTTP/SSE | 适合工作流自动化 |
| 容器化部署 | 两者皆可 | 根据客户端类型选择 |

## 常见问题

### HTTP 401 认证失败

社区 Issue #170 报告了在使用 Docker 部署时配置了正确的环境变量但仍出现认证失败的问题。解决方案：

1. 确认环境变量 `ES_USERNAME`、`ES_PASSWORD` 或 `ES_API_KEY` 正确设置
2. 使用 `docker exec` 进入容器验证凭证配置
3. 测试与 Elasticsearch 集群的连接：

```bash
# 使用用户名密码
docker exec <container-id> curl -k -u <username>:<password> <ES_URL>

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

### SSE 与 Streamable HTTP

由于 SSE 已被废弃，项目正在迁移到新的 Streamable HTTP 传输模式。详见社区 Issue #17。

## 最佳实践

1. **安全建议**
   - 生产环境优先使用 API Key 认证
   - 通过 HTTPS 连接到 Elasticsearch
   - 使用 AWS Secrets Manager 管理敏感凭证

2. **性能优化**
   - HTTP 模式默认监听本地地址，如需远程访问改为 `0.0.0.0`
   - 使用健康检查端点进行负载均衡器配置

3. **配置管理**
   - 使用配置文件集中管理复杂配置
   - 利用环境变量插值实现环境差异化配置

---

<a id='page-tools'></a>

## MCP 工具详解

### 相关页面

相关主题：[系统架构](#page-architecture), [故障排除指南](#page-troubleshooting)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)
- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)
- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)
- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)
- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)
</details>

# MCP 工具详解

## 概述

MCP Server Elasticsearch 提供了多个 MCP 工具，使 AI Agent 能够与 Elasticsearch 集群进行交互。这些工具通过 Model Context Protocol (MCP) 暴露，允许 LLM 通过自然语言执行索引管理、搜索查询、数据分析等操作。

核心工具定义位于 `EsBaseTools` 结构体中，通过 `#[tool_router]` 宏注册每个工具的处理程序。工具支持通过请求上下文动态获取 Elasticsearch 客户端实例，实现基于请求的认证凭证传递。

## 工具架构

### 工具注册机制

工具通过 Rust 宏 `#[tool]` 和 `#[tool_handler]` 进行声明和实现：

```rust
#[tool_router]
impl EsBaseTools {
    #[tool(
        description = "工具描述",
        annotations(title = "显示标题", read_only_hint = true)
    )]
    async fn tool_name(
        &self,
        req_ctx: RequestContext<RoleServer>,
        Parameters(Params): Parameters<Params>,
    ) -> Result<CallToolResult, rmcp::Error> {
        // 工具实现
    }
}
```

### 客户端提供机制

工具通过 `EsClientProvider` 获取 Elasticsearch 客户端，该提供者支持基于 HTTP 请求 Authorization 头的动态认证：

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

impl EsClientProvider {
    pub fn get(&self, context: RequestContext<RoleServer>) -> Elasticsearch {
        // 从请求上下文中提取认证信息
    }
}
```

## 核心工具列表

### 1. list_indices - 列出索引

| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| index_pattern | String | 是 | 索引名称或通配符模式 |

**实现位置**: `src/servers/elasticsearch/base_tools.rs:73-95`

该工具调用 Elasticsearch Cat API，返回匹配的索引列表：

```rust
async fn list_indices(
    &self,
    req_ctx: RequestContext<RoleServer>,
    Parameters(ListIndicesParams { index_pattern }): Parameters<ListIndicesParams>,
) -> Result<CallToolResult, rmcp::Error> {
    let es_client = self.es_client.get(req_ctx);
    let response = es_client
        .cat()
        .indices(CatIndicesParts::Index(&[&index_pattern]))
        .h(&["index", "status", "docs.count"])
        .format("json")
        .send()
        .await;

    let response: Vec<CatIndexResponse> = read_json(response).await?;
    Ok(CallToolResult::success(vec![
        Content::text(format!("Found {} indices:", response.len())),
        Content::json(response)?,
    ]))
}
```

### 2. get_mappings - 获取索引映射

| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| index | String | 是 | 索引名称 |

**实现位置**: `src/servers/elasticsearch/base_tools.rs:97-120`

> [!NOTE]
> **已知问题**: 当嵌套属性未显式指定 `"type": "nested"` 时，`get_mappings` 工具会返回 `"error decoding response body"` 错误。这是 Issue #185 报告的问题，尽管 Elasticsearch 规范允许省略显式类型声明。

### 3. search - 执行搜索

| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| index | String | 是 | 索引名称 |
| query_body | Map<String, Value> | 是 | 完整的 Elasticsearch Query DSL 对象 |
| fields | Option<Vec<String>> | 否 | 指定返回的字段列表 |

**实现位置**: `src/servers/elasticsearch/base_tools.rs:130-180`

search 工具支持完整的 Elasticsearch Query DSL，包括 query、size、from、sort、aggregations 等参数。

```rust
struct SearchParams {
    index: String,
    fields: Option<Vec<String>>,
    query_body: Map<String, Value>,
}
```

返回结果包含：
- `hits.total` - 匹配文档总数
- `hits.hits` - 文档数组
- `aggregations` - 聚合结果（如果有）

### 4. esql - ES|QL 查询

| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| query | String | 是 | 完整的 ES|QL 查询语句 |

**实现位置**: `src/servers/elasticsearch/mod.rs:46-50`

```rust
pub enum EsqlResultFormat {
    #[default]
    Json,   // 输出为 JSON 对象数组或单个对象
    Value,  // 如果是单个属性，输出其值
}
```

### 5. get_shards - 获取分片信息

| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| index | Option<String> | 否 | 可选的索引名称 |

**实现位置**: `src/servers/elasticsearch/base_tools.rs:41-69`

该工具返回分片的详细信息：

```rust
pub struct CatShardsResponse {
    pub index: String,
    pub shard: usize,
    pub prirep: String,    // primary 或 replica
    pub state: String,    // STARTED, INITIALIZING, etc.
    pub docs: Option<u64>,
    pub store: Option<u64>,
    pub node: String,
}
```

## 自定义工具扩展

### Tools 配置结构

用户可以通过配置文件定义自定义工具：

```rust
pub struct Tools {
    #[serde(flatten)]
    pub incl_excl: Option<IncludeExclude>,
    pub custom: HashMap<String, CustomTool>,
}

pub enum CustomTool {
    Esql(EsqlTool),
    SearchTemplate(SearchTemplateTool),
}
```

### SearchTemplateTool

支持两种搜索模板定义方式：

```rust
pub enum SearchTemplate {
    TemplateId(String),           // 通过模板 ID 引用
    Template(serde_json::Value),   // 内联模板定义
}
```

## 工具响应格式

所有工具通过 `CallToolResult` 返回结果：

```rust
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 Hit {
    #[serde(rename = "_source")]
    pub source: Value,
}
```

## 配置选项

### ElasticsearchMcpConfig

| 配置项 | 环境变量 | 类型 | 默认值 | 说明 |
|--------|----------|------|--------|------|
| url | ES_URL | String | - | Elasticsearch 集群地址 |
| api_key | ES_API_KEY | Option<String> | None | API Key 认证 |
| username | ES_USERNAME | Option<String> | None | 用户名 |
| password | ES_PASSWORD | Option<String> | None | 密码 |
| ssl_skip_verify | ES_SSL_SKIP_VERIFY | bool | false | 跳过 SSL 验证 |
| tools | - | Tools | empty | 自定义工具配置 |

**实现位置**: `src/servers/elasticsearch/mod.rs:24-52`

## 数据流图

```mermaid
graph TD
    A[MCP Client 请求] --> B[RequestContext 解析]
    B --> C{认证方式}
    C -->|API Key| D[Credentials::EncodedApiKey]
    C -->|用户名密码| E[Credentials::Basic]
    C -->|无认证| F[None]
    D --> G[TransportBuilder 配置]
    E --> G
    F --> G
    G --> H[Elasticsearch 客户端]
    H --> I{请求类型}
    I -->|list_indices| J[Cat Indices API]
    I -->|get_mappings| K[Get Mapping API]
    I -->|search| L[Search API]
    I -->|esql| M[ES|QL API]
    I -->|get_shards| N[Cat Shards API]
    J --> O[CatIndexResponse]
    K --> P[Mapping JSON]
    L --> Q[SearchResult]
    M --> R[ES|QL Result]
    N --> S[CatShardsResponse]
    O --> T[CallToolResult]
    P --> T
    Q --> T
    R --> T
    S --> T
```

## HTTP 协议支持

MCP Server 支持通过 HTTP 进行远程访问：

### HttpServerConfig

| 配置项 | 类型 | 说明 |
|--------|------|------|
| bind | SocketAddr | TCP 监听地址 |
| ct | CancellationToken | 取消令牌 |
| keep_alive | Option<Duration> | SSE 保活时间 |
| stateful_mode | bool | 启用状态会话 |
| session_manager | Arc<M> | 会话管理器 |

**实现位置**: `src/protocol/http.rs:13-30`

### 命令行配置

```rust
pub struct HttpCommand {
    pub config: Option<PathBuf>,        // 配置文件路径
    pub address: Option<SocketAddr>,   // 监听地址 [default: 127.0.0.1:8080]
    pub sse: bool,                      // 启用 SSE 端点
}
```

## 已知问题

| Issue | 描述 | 影响 |
|-------|------|------|
| #185 | `get_mappings` 工具在嵌套属性未显式指定 `type: nested` 时失败 | get_mappings 功能受限 |
| #170 | Basic 认证失败 401 Unauthorized | 认证配置问题 |
| #173 | 通过 HTTP/SSE 访问时部分功能返回错误 | HTTP 模式稳定性 |

## 相关文档

- [官方 MCP 协议文档](https://modelcontextprotocol.io/docs/concepts/transports#built-in-transport-types)
- [Elasticsearch MCP Server 发布说明](https://github.com/elastic/mcp-server-elasticsearch/releases)
- [Dependency Dashboard](https://github.com/elastic/mcp-server-elasticsearch/issues/6)

---

<a id='page-config'></a>

## 配置与工具过滤

### 相关页面

相关主题：[MCP 工具详解](#page-tools), [Docker 部署指南](#page-deployment)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)
- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)
- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)
- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)
- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)
</details>

# 配置与工具过滤

## 概述

Elasticsearch MCP Server 的配置与工具过滤系统提供了灵活的运行时自定义能力，允许管理员通过配置文件和环境变量来控制服务器行为、认证方式以及可用工具集。该系统支持两种传输模式（stdio 和 streamable-HTTP），配置通过 JSON5 格式加载，并支持 `${ENV_VAR}` 或 `${ENV_VAR:default}` 语法的环境变量插值。

## 配置架构

### 配置加载流程

```mermaid
graph TD
    A[CLI 启动命令] --> B[加载配置文件]
    B --> C[读取 JSON5 内容]
    C --> D[环境变量插值]
    D --> E[解析为 Configuration]
    E --> F[创建 ElasticsearchMcp]
    
    G[环境变量] -.->|${VAR}| D
```

配置加载逻辑位于 `src/lib.rs` 中，服务器启动时首先读取配置文件，然后通过插值器处理环境变量引用，最后解析为强类型配置结构体。

### 核心配置结构体

#### ElasticsearchMcpConfig

`ElasticsearchMcpConfig` 是服务器的核心配置单元，定义了所有可配置的运行时参数：

| 字段 | 类型 | 说明 | 环境变量 |
|------|------|------|----------|
| `url` | `String` | Elasticsearch 集群 URL | `ES_URL` |
| `api_key` | `Option<String>` | API Key 认证 | `ES_API_KEY` |
| `username` | `Option<String>` | 用户名 | `ES_USERNAME` |
| `password` | `Option<String>` | 密码 | `ES_PASSWORD` |
| `ssl_skip_verify` | `bool` | 跳过 SSL 证书验证 | `ES_SSL_SKIP_VERIFY` |
| `tools` | `Tools` | 工具配置 | - |
| `prompts` | `Vec<String>` | Prompt 模板列表 | - |

资料来源：[src/servers/elasticsearch/mod.rs:55-78]()

### 配置示例

服务器提供了默认配置模板，位于 `src/lib.rs`：

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

该模板展示了配置文件的推荐格式，支持：
- JSON5 语法（注释和多行字符串）
- 环境变量插值
- 默认值指定

## 认证配置

### 认证凭证优先级

系统支持三种认证方式，但同一时间只能使用一种：

1. **API Key 认证**（优先）
2. **用户名/密码认证**
3. **无认证**（适用于信任网络）

认证逻辑在 `ElasticsearchMcp::new_with_config` 方法中实现：

```rust
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
};
```

资料来源：[src/servers/elasticsearch/mod.rs:88-96]()

### HTTP 请求转发认证

`EsClientProvider` 提供了一个重要的功能：支持将 HTTP 请求中的 `Authorization` 头转发到远程 Elasticsearch 实例。这在 MCP 服务器代理认证时尤为重要。

## 环境变量插值系统

### 插值语法

插值器支持两种语法格式：

| 语法 | 说明 | 示例 |
|------|------|------|
| `${VAR}` | 必填变量，不存在则报错 | `${ES_URL}` |
| `${VAR:default}` | 可选变量，默认值为 `default` | `${ES_SSL_SKIP_VERIFY:false}` |

### 插值实现

插值逻辑位于 `src/utils/interpolator.rs`，核心函数签名：

```rust
pub fn interpolate(
    input: String,
    lookup: impl Fn(&str) -> Option<String>,
) -> Result<String, InterpolationError>
```

工作原理：
1. 扫描输入字符串中的 `${...}` 模式
2. 对每个模式调用 `lookup` 函数获取值
3. 支持默认值语法 `name:default`
4. 返回插值后的字符串

资料来源：[src/utils/interpolator.rs]()

### 单元测试示例

```rust
#[test]
fn good_extrapolation() -> anyhow::Result<()> {
    assert_eq!("foo_value01234", expand("${foo}01234")?);
    assert_eq!("foo_value01234\n1234bar_value", expand("${foo}01234\n1234${bar}")?);
    Ok(())
}
```

资料来源：[src/utils/interpolator.rs:47-51]()

## 工具配置与过滤

### 工具注册架构

```mermaid
graph TD
    A[Tools 配置] --> B[IncludeExclude 包含/排除规则]
    A --> C[CustomTool 自定义工具]
    
    C --> D[EsqlTool ES|QL 查询工具]
    C --> E[SearchTemplateTool 搜索模板工具]
    
    F[基础工具集] --> G[EsBaseTools]
    F -->|list_indices| G
    F -->|get_mappings| G
    F -->|search| G
    F -->|get_shards| G
    F -->|esql| G
```

### 工具结构定义

#### Tools 结构体

```rust
#[derive(Debug, Serialize, Deserialize)]
pub struct Tools {
    #[serde(flatten)]
    pub incl_excl: Option<IncludeExclude>,
    pub custom: HashMap<String, CustomTool>,
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `incl_excl` | `Option<IncludeExclude>` | 包含/排除过滤规则 |
| `custom` | `HashMap<String, CustomTool>` | 自定义工具集合 |

资料来源：[src/servers/elasticsearch/mod.rs:27-32]()

#### 自定义工具类型

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

| 工具类型 | 说明 | 配置字段 |
|----------|------|----------|
| `Esql` | ES|QL 查询工具 | `query`, `format` |
| `SearchTemplate` | 搜索模板工具 | `template_id` 或 `template` |

资料来源：[src/servers/elasticsearch/mod.rs:34-48]()

### 基础工具集 (EsBaseTools)

`EsBaseTools` 是 MCP 服务器的核心工具提供者，定义了所有内置工具：

| 工具名称 | 功能 | 参数 |
|----------|------|------|
| `list_indices` | 列出 Elasticsearch 索引 | `index_pattern` |
| `get_mappings` | 获取索引映射 | `index` |
| `search` | 执行搜索查询 | `index`, `fields`, `query_body` |
| `get_shards` | 获取分片信息 | `index`（可选） |
| `esql` | 执行 ES|QL 查询 | `query` |

#### 工具参数定义示例

```rust
#[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 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
    query_body: Map<String, Value>,
}
```

资料来源：[src/servers/elasticsearch/base_tools.rs:112-137]()

### 工具注解系统

每个工具都可以通过 `annotations` 属性添加元数据：

```rust
#[tool(
    description = "List all available Elasticsearch indices",
    annotations(title = "List ES indices", read_only_hint = true)
)]
```

| 注解字段 | 说明 |
|----------|------|
| `title` | 工具显示标题 |
| `read_only_hint` | 仅读提示（优化 LLM 决策） |

## CLI 启动配置

### 命令行结构

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

| 命令 | 说明 | 默认端口 |
|------|------|----------|
| `stdio` | 标准输入/输出模式 | - |
| `http` | Streamable-HTTP 模式 | 8080 |

### HTTP 模式配置

```rust
#[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,
}
```

资料来源：[src/cli.rs]()

### Stdio 模式配置

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

## 客户端提供器

### EsClientProvider 实现

`EsClientProvider` 是对 Elasticsearch 客户端的包装，提供基于请求上下文的客户端实例：

```rust
#[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 {
        // 返回配置好的客户端实例
    }
}
```

资料来源：[src/servers/elasticsearch/mod.rs:106-119]()

### 错误处理

```rust
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)
}
```

资料来源：[src/servers/elasticsearch/mod.rs:121-130]()

## 配置最佳实践

### 生产环境配置

1. **使用环境变量存储敏感信息**
   - API Key 或用户名/密码不应硬编码在配置文件中
   - 推荐使用 `${ES_API_KEY}` 或 `${ES_PASSWORD}` 语法

2. **SSL 证书验证**
   - 生产环境应保持 `ssl_skip_verify: false`
   - 如需跳过验证，明确设置 `${ES_SSL_SKIP_VERIFY:true}`

3. **工具限制**
   - 通过配置文件的 `incl_excl` 规则限制可用工具
   - 使用 `custom` 字段添加预定义的 ES|QL 查询或搜索模板

### 容器化部署

```bash
docker run --rm \
  -e ES_URL=https://elasticsearch:9200 \
  -e ES_API_KEY=your-api-key \
  -e ES_SSL_SKIP_VERIFY=false \
  -p 8080:8080 \
  docker.elastic.co/mcp/elasticsearch \
  http
```

## 已知问题

社区反馈的认证相关问题（#170）表明，在 Docker 容器部署时需要确保：
- 环境变量名称正确（区分大小写）
- `ES_USERNAME` 和 `ES_PASSWORD` 同时设置或使用 API Key
- 检查容器日志中的认证错误信息

---

<a id='page-deployment'></a>

## Docker 部署指南

### 相关页面

相关主题：[认证配置](#page-auth), [通信协议配置](#page-protocols), [安全最佳实践](#page-security)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [Dockerfile](https://github.com/elastic/mcp-server-elasticsearch/blob/main/Dockerfile)
- [Dockerfile-8000](https://github.com/elastic/mcp-server-elasticsearch/blob/main/Dockerfile-8000)
- [.env-example](https://github.com/elastic/mcp-server-elasticsearch/blob/main/.env-example)
- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)
- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)
- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)
</details>

# Docker 部署指南

本文档介绍如何通过 Docker 容器方式部署 Elasticsearch MCP Server。Elasticsearch MCP Server 是基于 Model Context Protocol (MCP) 的 Elasticsearch 集成服务，允许 AI 代理通过标准化接口与 Elasticsearch 集群进行交互。

## 核心概念

### 架构概览

MCP Server 以 Docker 容器的形式运行，提供两种协议支持：

```mermaid
graph TD
    A[AI Agent / MCP Client] -->|Stdio| B[MCP Server 容器<br/>stdio 模式]
    A -->|Streamable HTTP| C[MCP Server 容器<br/>HTTP 模式]
    B -->|HTTPS| D[Elasticsearch 集群]
    C -->|HTTPS| D
```

### 容器模式识别

MCP Server 支持自动检测运行环境的容器模式。当检测到容器运行时，服务器会自动将 `localhost` 替换为容器网络别名，以确保容器内的网络请求能正确路由到宿主机服务（如本地 Elasticsearch 集群）。

资料来源：[src/lib.rs:89-101]()

容器模式通过以下逻辑实现：

```mermaid
graph LR
    A[检测运行环境] --> B{是否容器模式?}
    B -->|是| C[替换 localhost]
    B -->|否| D[保持 localhost]
    C --> E[host.containers.internal<br/>Podman<br/>其他别名]
```

支持的宿主机别名包括：
- `host.containers.internal`（Podman 及部分 Docker 环境）
- 其他平台特定别名

资料来源：[src/servers/elasticsearch/mod.rs:89-95]()

## 环境变量配置

### 必需变量

| 变量名 | 说明 | 示例值 |
|--------|------|--------|
| `ES_URL` | Elasticsearch 集群地址 | `https://localhost:9200` |
| `ES_API_KEY` | API Key 认证密钥 | `base64EncodedApiKey...` |
| `ES_USERNAME` | 基本认证用户名 | `elastic` |
| `ES_PASSWORD` | 基本认证密码 | `password123` |
| `ES_SSL_SKIP_VERIFY` | 跳过 SSL 证书验证 | `true` / `false` |

### 配置优先级

环境变量支持默认值语法，格式为 `${VAR_NAME:default_value}`。当变量未定义时使用默认值。

资料来源：[src/lib.rs:67-77]()

```bash
# .env 文件示例
ES_URL=https://elasticsearch:9200
ES_API_KEY=your_api_key_here
ES_SSL_SKIP_VERIFY=false
```

### 认证方式

MCP Server 支持三种认证方式：

1. **API Key 认证**（推荐）：通过 `ES_API_KEY` 环境变量设置
2. **用户名密码认证**：通过 `ES_USERNAME` 和 `ES_PASSWORD` 环境变量设置
3. **SSL 跳过验证**：仅在开发环境中使用 `ES_SSL_SKIP_VERIFY=true`

> [!IMPORTANT]
> 认证凭证仅存储在环境变量中，不会持久化到磁盘或写入日志。

资料来源：[.env-example]()

## Docker 镜像

### 镜像信息

官方镜像托管在 Elastic 的 Docker Registry：

```
docker.elastic.co/mcp/elasticsearch
```

### 镜像版本

| 标签 | 说明 |
|------|------|
| `latest` | 最新稳定版本 |
| `v0.4.6` | 特定版本号（当前最新） |

### 端口配置

| Dockerfile | 默认端口 | 用途 |
|------------|----------|------|
| `Dockerfile` | 8080 | HTTP 模式监听端口 |
| `Dockerfile-8000` | 8000 | 备用端口配置 |

v0.4.3 之前的版本默认端口为 8000，之后统一改为 8080。

资料来源：[README.md]()

## Stdio 模式部署

Stdio 模式适用于直接与 MCP Client 进程通信的场景。

### 启动命令

```bash
docker run --rm \
  -e ES_URL="https://your-cluster.es.region.amazonaws.com:9200" \
  -e ES_API_KEY="your_api_key" \
  docker.elastic.co/mcp/elasticsearch \
  stdio
```

### Claude Desktop 配置

```json
{
  "mcpServers": {
    "elasticsearch-mcp-server": {
      "command": "docker",
      "args": [
        "run",
        "--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>"
      }
    }
  }
}
```

资料来源：[README.md]()

## HTTP 模式部署

HTTP 模式适用于需要远程访问、多客户端并发连接或通过代理桥接的场景。

### 启动命令

```bash
docker run --rm \
  -e ES_URL="https://your-cluster.es.region.amazonaws.com:9200" \
  -e ES_API_KEY="your_api_key" \
  -p 8080:8080 \
  docker.elastic.co/mcp/elasticsearch \
  http
```

### 端点说明

| 端点 | 方法 | 说明 |
|------|------|------|
| `/mcp` | POST | Streamable HTTP MCP 端点 |
| `/ping` | GET | 健康检查端点 |

### 健康检查

```bash
curl http://<host>:8080/ping
```

成功响应返回 `pong`。

资料来源：[README.md]()

### Claude Desktop 代理配置

由于 Claude Desktop 免费版仅支持 stdio 协议，需要使用 `mcp-proxy` 进行协议桥接：

1. 安装 mcp-proxy：
```bash
uv tool install mcp-proxy
```

2. 配置 Claude Desktop：
```json
{
  "mcpServers": {
    "elasticsearch-mcp-server": {
      "command": "/<home-directory>/.local/bin/mcp-proxy",
      "args": [
        "--transport=streamablehttp",
        "--header", "Authorization", "ApiKey <elasticsearch-API-key>",
        "http://<mcp-server-host>:<mcp-server-port>/mcp"
      ]
    }
  }
}
```

资料来源：[README.md]()

## 故障排查

### 常见问题

#### 认证失败 (401 Unauthorized)

Issue #170 中用户反馈使用 Docker 部署时环境变量配置正确但仍出现认证失败：

- 确认 `ES_USERNAME`、`ES_PASSWORD` 环境变量名称拼写正确（区分大小写）
- v0.4.5 版本修复了用户名环境变量名称问题，确保使用正确的变量名
- 验证 Elasticsearch 集群的认证配置

#### 连接超时

如果容器无法连接到 Elasticsearch 集群：

```bash
# 从容器内部测试连接
docker exec <container-id> curl -k -u <username>:<password> <ES_URL>
```

#### 容器模式 localhost 问题

如果容器内访问宿主机 Elasticsearch 失败，检查容器是否正确识别容器模式。MCP Server 会自动将 `localhost` 替换为网络别名。

资料来源：[src/servers/elasticsearch/mod.rs:89-95]()

### 日志查看

```bash
# 查看容器日志
docker logs <container-id>

# 实时跟踪日志
docker logs -f <container-id>
```

日志中可能出现的错误类型：
- Elasticsearch 连接失败
- 认证错误
- 网络连接问题

### 验证连接

1. 检查容器状态：
```bash
docker ps | grep elasticsearch-mcp-server
```

2. 测试健康端点：
```bash
curl http://<host>:8080/ping
```

3. 通过 MCP Client 测试功能（如 `list_indices`、`get_shards`）

## 安全最佳实践

### 凭证管理

| 安全措施 | 说明 |
|----------|------|
| 环境变量存储 | 凭证仅存储在环境变量中 |
| 定期轮换 | 生产环境建议 30-90 天轮换 API Key |
| 最小权限 | 使用仅读权限的 API Key |
| 不提交凭证 | 禁止将凭证提交到版本控制 |

### 网络安全

- 使用 HTTPS 协议 (`ES_URL` 以 `https://` 开头)
- 配置正确的安全组和网络 ACL
- 生产环境避免使用 `ES_SSL_SKIP_VERIFY=true`

### AWS 部署建议

在 AWS 环境中部署时：
- 使用 AWS Secrets Manager 管理凭证
- 通过 IAM 角色控制 EKS/EC2 访问权限
- 配置 VPC 安全组规则

资料来源：[README.md]()

## CLI_ARGS 环境变量

v0.4.1 版本新增 `CLI_ARGS` 环境变量支持，可作为传递命令行参数的替代方式：

```bash
docker run --rm \
  -e ES_URL="https://elasticsearch:9200" \
  -e ES_API_KEY="your_key" \
  -e CLI_ARGS="--config /path/to/config.json" \
  docker.elastic.co/mcp/elasticsearch \
  stdio
```

资料来源：[README.md]()
</details>

---

<a id='page-auth'></a>

## 认证配置

### 相关页面

相关主题：[Docker 部署指南](#page-deployment), [故障排除指南](#page-troubleshooting)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)
- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)
- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)
- [.env-example](https://github.com/elastic/mcp-server-elasticsearch/blob/main/.env-example)
- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)
</details>

# 认证配置

## 概述

Elasticsearch MCP Server 支持两种主要的认证方式与 Elasticsearch 集群建立安全连接。本页详细说明认证配置的工作原理、配置参数以及常见问题的排查方法。

认证配置在 MCP Server 启动时通过环境变量或配置文件加载，用于建立与 Elasticsearch 集群的信任连接。所有认证凭证仅在运行时内存中处理，不会持久化到磁盘或日志中。

## 认证方式

MCP Server 支持两种认证方式：

| 认证方式 | 配置参数 | 说明 |
|---------|---------|------|
| API Key 认证 | `ES_API_KEY` | 使用 Elasticsearch API 密钥进行认证 |
| 用户名密码认证 | `ES_USERNAME` + `ES_PASSWORD` | 使用用户名和密码进行 Basic 认证 |

> [!NOTE]
> API Key 认证优先于用户名密码认证。如果同时配置了 API Key 和用户名密码，系统将使用 API Key。

### 认证凭证优先级

```mermaid
graph TD
    A[启动 MCP Server] --> B{是否配置 ES_API_KEY?}
    B -->|是| C[使用 API Key 认证]
    B -->|否| D{是否配置 ES_USERNAME?}
    D -->|是| E{是否配置 ES_PASSWORD?}
    E -->|是| F[使用 Basic 认证]
    E -->|否| G[无认证]
    D -->|否| G
    C --> H[连接 Elasticsearch]
    F --> H
    G --> H
```

## 配置参数详解

### 环境变量配置

| 环境变量 | 类型 | 必填 | 默认值 | 说明 |
|---------|------|------|--------|------|
| `ES_URL` | String | 是 | - | Elasticsearch 集群地址，如 `https://localhost:9200` |
| `ES_API_KEY` | String | 否 | 空 | API Key 认证凭证 |
| `ES_USERNAME` | String | 否 | 空 | Basic 认证用户名 |
| `ES_PASSWORD` | String | 否 | 空 | Basic 认证密码 |
| `ES_SSL_SKIP_VERIFY` | Boolean | 否 | `false` | 是否跳过 SSL 证书验证 |

> [!CAUTION]
> `ES_SSL_SKIP_VERIFY=true` 会绕过 SSL 证书验证，仅在测试环境中使用。生产环境应配置正确的 CA 证书。

### 配置文件格式

除了环境变量，还可以通过配置文件指定认证信息。配置文件支持 JSON5 格式（允许注释和多行字符串）：

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

配置文件中的 `${VAR:default}` 语法表示环境变量插值，如果环境变量未设置则使用默认值。

## 认证实现架构

### 核心组件

```mermaid
classDiagram
    class ElasticsearchMcpConfig {
        +String url
        +Option~String~ api_key
        +Option~String~ username
        +Option~String~ password
        +bool ssl_skip_verify
    }
    
    class ElasticsearchMcp {
        +new_with_config(config, container_mode) EsBaseTools
    }
    
    class EsClientProvider {
        +Elasticsearch client
        +get(context) Elasticsearch
    }
    
    class Credentials {
        <<enumeration>>
        EncodedApiKey(String)
        Basic(String, String)
    }
    
    ElasticsearchMcpConfig --> ElasticsearchMcp : 配置输入
    ElasticsearchMcp --> EsClientProvider : 创建客户端
    ElasticsearchMcpConfig --> Credentials : 生成凭证
    Credentials --> EsClientProvider : 注入传输层
```

### 凭证生成逻辑

凭证生成在 `ElasticsearchMcp::new_with_config` 方法中完成：

```rust
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
};
```

资料来源：[src/servers/elasticsearch/mod.rs:57-64](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)

### 传输层配置

凭证创建后，通过 Elasticsearch Rust 客户端的 `TransportBuilder` 注入到传输层：

```rust
let mut transport = elasticsearch::http::transport::TransportBuilder::new(pool);
if let Some(creds) = creds {
    transport = transport.auth(creds);
}
// ... 继续配置 SSL 等选项
```

资料来源：[src/servers/elasticsearch/mod.rs:66-70](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)

## 运行时认证

### HTTP 请求上下文认证

`EsClientProvider` 支持从传入的 HTTP 请求中提取 `Authorization` 头，用于对远程 ES 实例进行认证：

```rust
pub fn get(&self, context: RequestContext<RoleServer>) -> Elasticsearch {
    // 从请求上下文中获取 Authorization 头
}
```

资料来源：[src/servers/elasticsearch/mod.rs:97-101](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)

### 容器模式下的 localhost 重写

当 MCP Server 在 Docker 容器中运行时，`rewrite_localhost` 函数会将 `localhost` URL 重写为 `host.docker.internal`，以便容器可以正确访问宿主机上的 Elasticsearch 服务：

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

资料来源：[src/servers/elasticsearch/mod.rs:51-53](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)

## 配置示例

### 使用 API Key 认证

```bash
# 环境变量方式
export ES_URL=https://elasticsearch.example.com:9200
export ES_API_KEY=your_api_key_here

# 运行 MCP Server
docker run -e ES_URL -e ES_API_KEY elastic/mcp-server-elasticsearch
```

### 使用用户名密码认证

```bash
# 环境变量方式
export ES_URL=https://elasticsearch.example.com:9200
export ES_USERNAME=elastic
export ES_PASSWORD=your_password

# 运行 MCP Server
docker run -e ES_URL -e ES_USERNAME -e ES_PASSWORD elastic/mcp-server-elasticsearch
```

### 使用 .env 文件

```bash
# 创建 .env 文件
cat > .env << 'EOF'
ES_URL=https://elasticsearch.example.com:9200
ES_USERNAME=elastic
ES_PASSWORD=your_password
ES_SSL_SKIP_VERIFY=false
EOF

# 运行 MCP Server
docker run --env-file .env elastic/mcp-server-elasticsearch
```

## 常见问题排查

### 401 Unauthorized 错误

**问题描述**：认证失败，返回 401 Unauthorized 错误。

**可能原因**：
- 凭证配置错误（用户名/密码不匹配）
- API Key 格式不正确或已过期
- Elasticsearch 安全策略阻止了该凭证

**排查步骤**：

1. 验证环境变量是否正确设置：
```bash
docker exec <container-id> env | grep ES_
```

2. 直接测试 Elasticsearch 连接：
```bash
# 使用 Basic 认证
docker exec <container-id> curl -k -u <username>:<password> <ES_URL>

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

3. 检查凭证是否有正确的索引访问权限

### 认证凭证优先级问题

**问题描述**：同时配置了 API Key 和用户名密码，但使用了错误的认证方式。

根据代码逻辑，API Key 具有最高优先级。如果希望使用 Basic 认证，请确保不设置 `ES_API_KEY` 环境变量。

### 容器内连接问题

**问题描述**：在 Docker 容器中运行时报连接错误。

当 ES_URL 使用 `localhost` 时，容器内的进程无法访问宿主机的 Elasticsearch。需要使用 `rewrite_localhost` 功能或修改 ES_URL 为宿主机的实际 IP 地址。

## 安全最佳实践

| 安全措施 | 说明 |
|---------|------|
| 使用 AWS Secrets Manager | 生产环境应使用 AWS Secrets Manager 或类似服务管理凭证 |
| 定期轮换 API Key | 建议每 30-90 天轮换一次生产环境的 API Key |
| 最小权限原则 | 为 MCP Server 创建只读用户，仅授予必要的索引访问权限 |
| 启用 SSL/TLS | 生产环境必须使用 HTTPS 协议 |
| 避免 SSL 跳过验证 | 生产环境不应设置 `ES_SSL_SKIP_VERIFY=true` |

> [!WARNING]
> 切勿将凭证直接写入配置文件并提交到版本控制系统。所有凭证都应通过环境变量或密钥管理服务注入。

## 相关文档

- [官方部署文档](https://github.com/elastic/mcp-server-elasticsearch#deploy-the-mcp-server-container)
- [Elasticsearch API Keys 文档](https://www.elastic.co/docs/deploy-manage/api-keys)
- [Elasticsearch 用户和角色文档](https://www.elastic.co/docs/deploy-manage/users-roles)

---

<a id='page-troubleshooting'></a>

## 故障排除指南

### 相关页面

相关主题：[认证配置](#page-auth), [Docker 部署指南](#page-deployment)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)
- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)
- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)
- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)
- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)
</details>

# 故障排除指南

本页面提供 Elasticsearch MCP Server 部署和运行过程中常见问题的诊断和解决方案。

---

## 1. 认证失败 (401 Unauthorized)

### 问题描述

用户反馈在使用 Docker 部署 MCP Server 时，已正确配置了 `ES_USERNAME`、`ES_PASSWORD` 环境变量，但仍然收到 "401 Unauthorized" 认证失败错误。

资料来源：[issues/170](https://github.com/elastic/mcp-server-elasticsearch/issues/170)

### 可能原因

MCP Server 支持两种认证方式：**API Key** 和 **用户名/密码**。认证优先级如下：

1. 如果设置了 `api_key`，优先使用 API Key 认证
2. 如果设置了 `username`，使用 Basic Auth（必须同时设置 `password`）
3. 如果两者都未设置，使用匿名访问

资料来源：[src/servers/elasticsearch/mod.rs:58-65](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L58-L65)

```rust
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
};
```

### 解决方案

#### 方案一：使用 API Key 认证

```bash
docker run -e ES_URL=https://your-cluster.es.region.amazonaws.com \
           -e ES_API_KEY=your_api_key_here \
           -p 8080:8080 \
           elastic/mcp-server-elasticsearch
```

#### 方案二：使用用户名密码认证

```bash
docker run -e ES_URL=https://your-cluster.es.region.amazonaws.com \
           -e ES_USERNAME=your_username \
           -e ES_PASSWORD=your_password \
           -p 8080:8080 \
           elastic/mcp-server-elasticsearch
```

> [!IMPORTANT]
> 确保 `ES_USERNAME` 和 `ES_PASSWORD` **同时设置**。只设置其中一个将导致认证失败。

### 验证认证配置

在容器内测试认证连接：

```bash
# 使用 Basic Auth 测试
docker exec <container-id> curl -k -u <username>:<password> <ES_URL>

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

---

## 2. 网络连接问题

### 容器内无法连接 Elasticsearch

#### 问题表现

容器日志显示连接超时或拒绝连接：

```
Error: Connection refused
```

#### 诊断步骤

1. **验证 Elasticsearch URL**

确保 `ES_URL` 格式正确且可访问：

```bash
docker exec <container-id> curl -k https://your-es-cluster:9200
```

2. **检查网络连通性**

```bash
docker exec <container-id> ping <es-host>
docker exec <container-id> telnet <es-host> 9200
```

3. **验证 SSL 配置**

如果使用自签名证书，需要设置 `ES_SSL_SKIP_VERIFY=true`：

资料来源：[src/servers/elasticsearch/mod.rs:71-72](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L71-L72)

```bash
docker run -e ES_URL=https://your-cluster.es.region.amazonaws.com \
           -e ES_API_KEY=your_api_key \
           -e ES_SSL_SKIP_VERIFY=true \
           -p 8080:8080 \
           elastic/mcp-server-elasticsearch
```

### localhost 重写问题 (容器模式)

当 MCP Server 以容器模式运行时，URL 中的 `localhost` 会自动重写为 `host.docker.internal`，以便容器能够访问宿主机上的服务。

资料来源：[src/servers/elasticsearch/mod.rs:42-44](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L42-L44)

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

---

## 3. get_mappings 工具响应解码错误

### 问题描述

使用 `get_mappings` 工具时，服务器返回错误：

```
"Request failed (remote): error decoding response body"
```

资料来源：[issues/185](https://github.com/elastic/mcp-server-elasticsearch/issues/185)

### 根本原因

当索引 mapping 中嵌套属性没有显式指定 `"type": "nested"` 时，ES 返回的响应可能包含非标准字段格式，导致 JSON 解码失败。

### 临时解决方案

在定义 mapping 时，确保嵌套类型显式声明：

```json
{
  "properties": {
    "nested_field": {
      "type": "nested",
      "properties": {
        "name": { "type": "keyword" }
      }
    }
  }
}
```

---

## 4. HTTP/Streamable HTTP 模式问题

### 问题描述

无法通过 HTTP 协议远程访问 MCP Server。

### 配置说明

MCP Server 支持两种传输模式：

| 模式 | 命令 | 默认地址 | 用途 |
|------|------|----------|------|
| Stdio | `stdio` | - | 本地进程通信 |
| Streamable HTTP | `http` | `127.0.0.1:8080` | 远程访问 |

资料来源：[src/cli.rs:30-47](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs#L30-L47)

### 启动 HTTP 服务器

```bash
# 基本 HTTP 模式
mcp-server-elasticsearch http --address 0.0.0.0:8080

# 启用 SSE 回退（已废弃）
mcp-server-elasticsearch http --sse
```

### 验证 HTTP 服务

```bash
curl http://<host>:8080/ping
```

预期响应：`pong`

### 健康检查

Streamable HTTP 模式提供 `/ping` 端点用于健康检查：

```bash
curl http://localhost:8080/ping
```

---

## 5. 环境变量插值问题

### 问题描述

配置文件中使用 `${VAR_NAME}` 语法引用环境变量时，变量未被正确展开。

### 机制说明

MCP Server 使用 `interpolator` 模块处理环境变量插值：

资料来源：[src/utils/interpolator.rs:1-50](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs#L1-L50)

**支持的语法：**

| 语法 | 说明 |
|------|------|
| `${VAR}` | 展开环境变量，变量不存在则报错 |
| `${VAR:default}` | 展开环境变量，变量不存在则使用默认值 |

### 示例配置

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

资料来源：[src/lib.rs:20-33](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs#L20-L33)

### 常见错误

```
missing closing braces    # 缺少闭合大括号
env variable 'XXX' not defined  # 环境变量未定义
```

---

## 6. 工具执行错误

### 问题：esql 工具查询失败

#### 错误表现

ES|QL 查询返回错误响应。

#### 诊断步骤

1. 检查 ES|QL 语法是否正确
2. 验证用户是否有执行 ES|QL 的权限
3. 检查 Elasticsearch 版本是否支持 ES|QL（8.x+）

### 问题：search 工具返回空结果

#### 错误表现

search 工具成功执行但返回空 `hits` 数组。

#### 可能原因

- 查询条件与现有文档不匹配
- 索引名称拼写错误
- 时间范围过滤条件问题

### 问题：list_indices 工具无响应

#### 诊断

```bash
# 验证索引列表可访问
docker exec <container-id> curl -k -u user:pass <ES_URL>/_cat/indices?v
```

---

## 7. 日志分析

### 容器日志查看

```bash
docker logs <container-id>
```

### 日志级别配置

通过环境变量 `RUST_LOG` 设置日志级别：

```bash
docker run -e RUST_LOG=debug \
           -e ES_URL=https://your-cluster:9200 \
           -e ES_API_KEY=your_key \
           elastic/mcp-server-elasticsearch
```

### 常见日志关键词

| 关键词 | 含义 |
|--------|------|
| `Error: Connection refused` | 无法连接到 Elasticsearch |
| `401 Unauthorized` | 认证失败 |
| `error decoding response body` | 响应解析错误（通常与 mapping 格式相关）|
| `missing password` | 使用用户名认证但未提供密码 |

---

## 8. 配置验证清单

在报告问题前，请确认以下配置项：

| 检查项 | 说明 | 验证命令 |
|--------|------|----------|
| ES_URL 格式 | 必须以 `http://` 或 `https://` 开头 | `echo $ES_URL` |
| 认证凭证 | API Key 或 用户名+密码 | 检查环境变量 |
| 网络连通性 | 容器可访问 ES 集群 | `docker exec <id> curl <ES_URL>` |
| SSL 配置 | 自签名证书需设置 `ES_SSL_SKIP_VERIFY=true` | 检查日志 |
| 权限 | 用户对索引有读取权限 | ES 角色检查 |

---

## 9. 获取帮助

如果以上指南未能解决您的问题：

1. 收集以下信息：
   - MCP Server 版本：`docker logs <container-id> | grep version`
   - 完整错误日志
   - 配置文件（脱敏后）
   - Elasticsearch 集群版本

2. 在 [GitHub Issues](https://github.com/elastic/mcp-server-elasticsearch/issues) 创建问题时：
   - 描述复现步骤
   - 附上相关日志
   - 说明环境和版本信息

---

<a id='page-security'></a>

## 安全最佳实践

### 相关页面

相关主题：[认证配置](#page-auth), [Docker 部署指南](#page-deployment)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)
- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)
- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)
- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)
- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)
- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)

</details>

# 安全最佳实践

本文档介绍 Elasticsearch MCP Server 的安全最佳实践，涵盖身份认证、凭证管理、传输加密、网络配置等关键安全领域。

## 身份认证配置

Elasticsearch MCP Server 支持两种身份认证方式：**API Key 认证** 和 **基本认证（用户名/密码）**。

### 认证方式对比

| 认证方式 | 环境变量 | 说明 |
|---------|---------|------|
| API Key | `ES_API_KEY` | 推荐用于生产环境，安全性更高 |
| 基本认证 | `ES_USERNAME` + `ES_PASSWORD` | 适用于传统用户名密码场景 |
| SSL 跳过验证 | `ES_SSL_SKIP_VERIFY` | 仅在开发/测试环境使用 |

### 配置认证参数

认证配置通过 `ElasticsearchMcpConfig` 结构体管理：

```rust
// 资料来源：src/servers/elasticsearch/mod.rs:88-102
pub struct ElasticsearchMcpConfig {
    /// 集群 URL
    pub url: String,

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

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

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

    /// 是否跳过 SSL 证书验证
    #[serde(default, deserialize_with = "deserialize_bool_from_anything")]
    pub ssl_skip_verify: bool,
}
```

### API Key 认证配置

```bash
docker run --rm \
  -e ES_URL="https://your-elasticsearch:9200" \
  -e ES_API_KEY="your-api-key-here" \
  -p 8080:8080 \
  docker.elastic.co/mcp/elasticsearch \
  http
```

### 基本认证配置

```bash
docker run --rm \
  -e ES_URL="https://your-elasticsearch:9200" \
  -e ES_USERNAME="elastic" \
  -e ES_PASSWORD="your-password" \
  -p 8080:8080 \
  docker.elastic.co/mcp/elasticsearch \
  http
```

## 凭证安全管理

### 凭证存储原则

Elasticsearch MCP Server 遵循严格的凭证安全管理原则：

- **API 密钥和密码**：仅存储在传递给容器的环境变量中
- **不持久化到磁盘**：凭证不会写入文件系统
- **不记录到日志**：敏感信息不会出现在日志输出中

```rust
// 资料来源：src/servers/elasticsearch/mod.rs:72-79
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
};
```

### 环境变量插值

配置文件支持环境变量插值，使用 `${VAR_NAME}` 或 `${VAR_NAME:default}` 语法：

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

```rust
// 资料来源：src/lib.rs:48-52
let config = interpolator::interpolate_from_env(config)?;
```

### 生产环境凭证管理建议

| 推荐做法 | 说明 |
|---------|------|
| AWS Secrets Manager | 使用 AWS Secrets Manager 存储和轮换凭证 |
| AWS Systems Manager Parameter Store | 使用 Parameter Store 管理敏感参数 |
| 定期轮换 | API 密钥建议每 30-90 天轮换一次 |
| 最小权限 | 使用只读访问特定索引的 API 密钥 |

## 传输加密

### HTTPS 通信

MCP Server 与 Elasticsearch 集群之间的通信采用 HTTPS 加密：

```mermaid
graph LR
    A[MCP Server] -->|HTTPS/TLS| B[Elasticsearch Cluster]
    B -->|加密响应| A
```

当 `ES_URL` 使用 `https://` 协议时，通信自动加密：

```bash
# 正确的 HTTPS 配置
ES_URL="https://your-elasticsearch:9200"
```

### SSL 证书验证

#### 生产环境配置

生产环境应保持 SSL 证书验证启用：

```bash
# 默认情况下 ssl_skip_verify 为 false，保持验证
docker run --rm \
  -e ES_URL="https://your-elasticsearch:9200" \
  -e ES_API_KEY="your-api-key" \
  docker.elastic.co/mcp/elasticsearch \
  stdio
```

#### 开发/测试环境配置

仅在本地开发或使用自签名证书时禁用验证：

```bash
docker run --rm \
  -e ES_URL="https://localhost:9200" \
  -e ES_API_KEY="your-api-key" \
  -e ES_SSL_SKIP_VERIFY=true \
  docker.elastic.co/mcp/elasticsearch \
  stdio
```

> ⚠️ **警告**：禁用 SSL 验证会使通信暴露于中间人攻击风险，仅限于受信任的内部网络。

## 网络安全配置

### HTTP 服务监听地址

HTTP 模式下，默认监听地址为 `127.0.0.1:8080`：

```rust
// 资料来源：src/cli.rs:28-32
pub struct HttpCommand {
    /// 监听地址 [默认: 127.0.0.1:8080]
    #[clap(long, value_name = "IP_ADDRESS:PORT", env = "HTTP_ADDRESS")]
    pub address: Option<std::net::SocketAddr>,

    /// 同时启动 SSE 服务器在 '/sse'
    #[clap(long)]
    pub sse: bool,
}
```

### 安全监听建议

| 场景 | 推荐配置 | 说明 |
|-----|---------|------|
| 本地开发 | `127.0.0.1:8080` | 仅本地访问 |
| Docker 网络 | `0.0.0.0:8080` | 容器间通信 |
| 公网部署 | 使用反向代理 + TLS | 添加额外安全层 |

### Docker 网络安全

容器模式下，自动重写 localhost 引用：

```rust
// 资料来源：src/servers/elasticsearch/mod.rs:67-68
if container_mode {
    rewrite_localhost(&mut url)?;
}
```

## 常见安全问题排查

### 401 Unauthorized 错误

社区反馈：Issue #170 中许多用户遇到基本认证失败的问题。

#### 排查步骤

1. **验证环境变量配置**：
   ```bash
   docker exec <container-id> env | grep ES_
   ```

2. **测试 Elasticsearch 连接**：
   ```bash
   # 使用 API Key
   docker exec <container-id> curl -k -H "Authorization: ApiKey <api-key>" <ES_URL>
   
   # 使用用户名密码
   docker exec <container-id> curl -k -u <username>:<password> <ES_URL>
   ```

3. **检查凭证是否正确传递**：
   - 确认 `ES_USERNAME` 和 `ES_PASSWORD` 同时设置
   - 确认 API Key 格式正确（不带 "ApiKey" 前缀）

### SSL 证书错误

```bash
# 检查 Elasticsearch SSL 配置
docker exec <container-id> curl -v <ES_URL>
```

### 容器日志分析

```bash
docker logs <container-id>
```

查看日志中的错误信息：

- Elasticsearch 连接失败
- 身份认证错误
- 网络连接问题

## 数据安全

### 数据存储

| 层面 | 说明 |
|-----|------|
| 传输中数据 | MCP Server 与 Elasticsearch 之间的通信加密 |
| 静态数据 | 容器不本地存储数据，所有数据保留在 Elasticsearch 集群 |
| 临时数据 | 容器重启后清除所有临时数据 |

### 数据访问控制

建议在 Elasticsearch 层面配置：

- 基于角色的访问控制 (RBAC)
- 字段级安全
- 索引级权限

```json
{
  "roles": [
    {
      "name": "mcp_readonly",
      "indices": [
        {
          "names": ["allowed-index-*"],
          "privileges": ["read", "view_index_metadata"]
        }
      ]
    }
  ]
}
```

## 审计与监控

### 健康检查端点

HTTP 模式提供健康检查端点：

```bash
curl http://<host>:8080/ping
```

成功响应返回 `pong`。

### MCP 端点

```bash
# MCP 协议端点
http://<host>:8080/mcp
```

## 最佳实践清单

### 部署前检查

- [ ] 使用 HTTPS 连接到 Elasticsearch
- [ ] 配置有效的 API Key 或用户名密码
- [ ] 不在生产环境设置 `ES_SSL_SKIP_VERIFY=true`
- [ ] 使用只读权限的 API 密钥

### 容器配置检查

- [ ] 凭证通过环境变量传递，不写入配置文件
- [ ] 容器日志不包含敏感信息
- [ ] 网络访问限制在必要范围

### 运维检查

- [ ] 定期轮换 API 密钥（30-90 天）
- [ ] 监控认证失败日志
- [ ] 审计 Elasticsearch 访问日志

## 相关资源

- [Elasticsearch API Keys 文档](https://www.elastic.co/docs/deploy-manage/api-keys)
- [Elasticsearch 用户角色文档](https://www.elastic.co/docs/deploy-manage/users-roles)
- [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/)
- [Model Context Protocol 文档](https://modelcontextprotocol.io/)

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：elastic/mcp-server-elasticsearch

摘要：发现 10 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：安装坑 - 依赖 Docker 环境。

## 1. 安装坑 · 依赖 Docker 环境

- 严重度：medium
- 证据强度：runtime_trace
- 发现：安装/运行入口包含 Docker 命令：docker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio
- 对用户的影响：非工程用户可能没有 Docker，启动成本明显增加。
- 建议检查：标注 Docker 前置条件，并提供非 Docker 路径或失败提示。
- 复现命令：`docker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio`
- 防护动作：Docker 前置条件未说明时，不把项目标成普通用户低门槛。
- 证据：identity.distribution | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | docker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio

## 2. 安装坑 · 来源证据：Dependency Dashboard

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Dependency Dashboard
- 对用户的影响：可能阻塞安装或首次运行。
- 建议检查：来源问题仍为 open，Pack Agent 需要复核是否仍影响当前版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_5573c160ecdd4e34be6dbf6549fe2529 | https://github.com/elastic/mcp-server-elasticsearch/issues/6 | 来源讨论提到 docker 相关条件，需在安装/试用前复核。

## 3. 配置坑 · 可能修改宿主 AI 配置

- 严重度：medium
- 证据强度：source_linked
- 发现：项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。
- 对用户的影响：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。
- 建议检查：列出会写入的配置文件、目录和卸载/回滚步骤。
- 防护动作：涉及宿主配置目录时必须给回滚路径，不能只给安装命令。
- 证据：capability.host_targets | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | host_targets=mcp_host, claude, cursor

## 4. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 建议检查：将假设转成下游验证清单。
- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。
- 证据：capability.assumptions | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | README/documentation is current enough for a first validation pass.

## 5. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。
- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。
- 证据：evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | last_activity_observed missing

## 6. 安全/权限坑 · 下游验证发现风险项

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：下游已经要求复核，不能在页面中弱化。
- 建议检查：进入安全/权限治理复核队列。
- 防护动作：下游风险存在时必须保持 review/recommendation 降级。
- 证据：downstream_validation.risk_items | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | no_demo; severity=medium

## 7. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 建议检查：把风险写入边界卡，并确认是否需要人工复核。
- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。
- 证据：risks.scoring_risks | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | no_demo; severity=medium

## 8. 安全/权限坑 · 来源证据：get_mappings tool fails with "error decoding response body" when nested type is omitted in properties

- 严重度：medium
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：get_mappings tool fails with "error decoding response body" when nested type is omitted in properties
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 建议检查：来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。
- 防护动作：不得脱离来源链接放大为确定性结论；需要标注适用版本和复核状态。
- 证据：community_evidence:github | cevd_f8732a2deab341d6b739b122459d1243 | https://github.com/elastic/mcp-server-elasticsearch/issues/185 | 来源讨论提到 api key 相关条件，需在安装/试用前复核。

## 9. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。
- 防护动作：issue/PR 响应未知时，必须提示维护风险。
- 证据：evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | issue_or_pr_quality=unknown

## 10. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。
- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。
- 证据：evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | release_recency=unknown

<!-- canonical_name: elastic/mcp-server-elasticsearch; human_manual_source: deepwiki_human_wiki -->
