{
  "canonical_name": "elastic/mcp-server-elasticsearch",
  "compilation_id": "pack_cda4d488af99420487fe2a1578e2f7d7",
  "created_at": "2026-05-31T01:21:43.064615+00:00",
  "created_by": "project-pack-compiler",
  "feedback": {
    "carrier_selection_notes": [
      "viable_asset_types=mcp_config, recipe, host_instruction, eval, preflight",
      "recommended_asset_types=mcp_config, recipe, host_instruction, eval, preflight"
    ],
    "evidence_delta": {
      "confirmed_claims": [
        "identity_anchor_present",
        "capability_and_host_targets_present",
        "install_path_declared_or_better"
      ],
      "missing_required_fields": [],
      "must_verify_forwarded": [
        "Run or inspect `docker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio` in an isolated environment.",
        "Confirm the project exposes the claimed capability to at least one target host."
      ],
      "quickstart_execution_scope": "allowlisted_sandbox_smoke",
      "sandbox_command": "docker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio",
      "sandbox_container_image": "docker.elastic.co/mcp/elasticsearch",
      "sandbox_execution_backend": "docker",
      "sandbox_planner_decision": "deterministic_isolated_install",
      "sandbox_validation_id": "sbx_b96078911c064ea59db267764802848e"
    },
    "feedback_event_type": "project_pack_compilation_feedback",
    "learning_candidate_reasons": [],
    "template_gaps": []
  },
  "identity": {
    "canonical_id": "project_cc0542a2a96f2781ca87b8b23eb8e57b",
    "canonical_name": "elastic/mcp-server-elasticsearch",
    "homepage_url": null,
    "license": "unknown",
    "repo_url": "https://github.com/elastic/mcp-server-elasticsearch",
    "slug": "mcp-server-elasticsearch",
    "source_packet_id": "phit_81cbb06e36d247419b264ab65a087e74",
    "source_validation_id": "dval_a637409e3fd74426bc5c840f395c1308"
  },
  "merchandising": {
    "best_for": "需要工具连接与集成能力，并使用 mcp_host的用户",
    "github_forks": 141,
    "github_stars": 666,
    "one_liner_en": "Elasticsearch MCP Server",
    "one_liner_zh": "Elasticsearch MCP Server",
    "primary_category": {
      "category_id": "tool-integrations",
      "confidence": "high",
      "name_en": "Tool Integrations",
      "name_zh": "工具连接与集成",
      "reason": "matched_keywords:mcp, api, server"
    },
    "target_user": "使用 mcp_host, claude, cursor 等宿主 AI 的用户",
    "title_en": "mcp-server-elasticsearch",
    "title_zh": "mcp-server-elasticsearch 能力包",
    "visible_tags": [
      {
        "label_en": "MCP Tools",
        "label_zh": "MCP 工具",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "product_domain-mcp-tools",
        "type": "product_domain"
      },
      {
        "label_en": "Knowledge Base Q&A",
        "label_zh": "知识库问答",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "user_job-knowledge-base-q-a",
        "type": "user_job"
      },
      {
        "label_en": "Workflow Automation",
        "label_zh": "流程自动化",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "core_capability-workflow-automation",
        "type": "core_capability"
      },
      {
        "label_en": "Node-based Workflow",
        "label_zh": "节点式流程编排",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "workflow_pattern-node-based-workflow",
        "type": "workflow_pattern"
      },
      {
        "label_en": "Evaluation Suite",
        "label_zh": "评测体系",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "selection_signal-evaluation-suite",
        "type": "selection_signal"
      }
    ]
  },
  "packet_id": "phit_81cbb06e36d247419b264ab65a087e74",
  "page_model": {
    "artifacts": {
      "artifact_slug": "mcp-server-elasticsearch",
      "files": [
        "PROJECT_PACK.json",
        "QUICK_START.md",
        "PROMPT_PREVIEW.md",
        "HUMAN_MANUAL.md",
        "AI_CONTEXT_PACK.md",
        "BOUNDARY_RISK_CARD.md",
        "PITFALL_LOG.md",
        "REPO_INSPECTION.json",
        "REPO_INSPECTION.md",
        "CAPABILITY_CONTRACT.json",
        "EVIDENCE_INDEX.json",
        "CLAIM_GRAPH.json"
      ],
      "required_files": [
        "PROJECT_PACK.json",
        "QUICK_START.md",
        "PROMPT_PREVIEW.md",
        "HUMAN_MANUAL.md",
        "AI_CONTEXT_PACK.md",
        "BOUNDARY_RISK_CARD.md",
        "PITFALL_LOG.md",
        "REPO_INSPECTION.json"
      ]
    },
    "detail": {
      "capability_source": "Project Hit Packet + DownstreamValidationResult",
      "commands": [
        {
          "command": "docker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio",
          "label": "Docker · 官方安装入口",
          "source": "https://github.com/elastic/mcp-server-elasticsearch#readme",
          "verified": true
        }
      ],
      "display_tags": [
        "MCP 工具",
        "知识库问答",
        "流程自动化",
        "节点式流程编排",
        "评测体系"
      ],
      "eyebrow": "工具连接与集成",
      "glance": [
        {
          "body": "判断自己是不是目标用户。",
          "label": "最适合谁",
          "value": "需要工具连接与集成能力，并使用 mcp_host的用户"
        },
        {
          "body": "先理解能力边界，再决定是否继续。",
          "label": "核心价值",
          "value": "Elasticsearch MCP Server"
        },
        {
          "body": "未完成验证前保持审慎。",
          "label": "继续前",
          "value": "publish to Doramagic.ai project surfaces"
        }
      ],
      "guardrail_source": "Boundary & Risk Card",
      "guardrails": [
        {
          "body": "Prompt Preview 只展示流程，不证明项目已安装或运行。",
          "label": "Check 1",
          "value": "不要把试用当真实运行"
        },
        {
          "body": "mcp_host, claude, cursor",
          "label": "Check 2",
          "value": "确认宿主兼容"
        },
        {
          "body": "publish to Doramagic.ai project surfaces",
          "label": "Check 3",
          "value": "先隔离验证"
        }
      ],
      "mode": "mcp_config, recipe, host_instruction, eval, preflight",
      "pitfall_log": {
        "items": [
          {
            "body": "Project evidence flags a installation risk. Review the linked source before relying on this workflow.",
            "category": "Installation risk",
            "evidence": [
              "identity.distribution | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch"
            ],
            "severity": "medium",
            "suggested_check": "Reproduce the official install and quickstart path in an isolated environment.",
            "title": "Installation risk requires verification",
            "user_impact": "May increase setup, validation, or first-run risk for the user."
          },
          {
            "body": "Project evidence flags a installation risk. Review the linked source before relying on this workflow.",
            "category": "Installation risk",
            "evidence": [
              "community_evidence:github | cevd_5573c160ecdd4e34be6dbf6549fe2529 | https://github.com/elastic/mcp-server-elasticsearch/issues/6"
            ],
            "severity": "medium",
            "suggested_check": "Reproduce the official install and quickstart path in an isolated environment.",
            "title": "Installation risk requires verification",
            "user_impact": "May increase setup, validation, or first-run risk for the user."
          },
          {
            "body": "Project evidence flags a configuration risk. Review the linked source before relying on this workflow.",
            "category": "Configuration risk",
            "evidence": [
              "capability.host_targets | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch"
            ],
            "severity": "medium",
            "suggested_check": "Reproduce the official install and quickstart path in an isolated environment.",
            "title": "Configuration risk requires verification",
            "user_impact": "May increase setup, validation, or first-run risk for the user."
          },
          {
            "body": "README/documentation is current enough for a first validation pass.",
            "category": "Capability evidence risk",
            "evidence": [
              "capability.assumptions | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch"
            ],
            "severity": "medium",
            "suggested_check": "Reproduce the official install and quickstart path in an isolated environment.",
            "title": "Capability evidence risk requires verification",
            "user_impact": "May increase setup, validation, or first-run risk for the user."
          },
          {
            "body": "Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.",
            "category": "Maintenance risk",
            "evidence": [
              "evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch"
            ],
            "severity": "medium",
            "suggested_check": "Reproduce the official install and quickstart path in an isolated environment.",
            "title": "Maintenance risk requires verification",
            "user_impact": "May increase setup, validation, or first-run risk for the user."
          },
          {
            "body": "no_demo",
            "category": "Security or permission risk",
            "evidence": [
              "downstream_validation.risk_items | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch"
            ],
            "severity": "medium",
            "suggested_check": "Reproduce the official install and quickstart path in an isolated environment.",
            "title": "Security or permission risk requires verification",
            "user_impact": "May increase setup, validation, or first-run risk for the user."
          },
          {
            "body": "no_demo",
            "category": "Security or permission risk",
            "evidence": [
              "risks.scoring_risks | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch"
            ],
            "severity": "medium",
            "suggested_check": "Reproduce the official install and quickstart path in an isolated environment.",
            "title": "Security or permission risk requires verification",
            "user_impact": "May increase setup, validation, or first-run risk for the user."
          },
          {
            "body": "Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.",
            "category": "Security or permission risk",
            "evidence": [
              "community_evidence:github | cevd_f8732a2deab341d6b739b122459d1243 | https://github.com/elastic/mcp-server-elasticsearch/issues/185"
            ],
            "severity": "medium",
            "suggested_check": "Reproduce the official install and quickstart path in an isolated environment.",
            "title": "Security or permission risk requires verification",
            "user_impact": "May increase setup, validation, or first-run risk for the user."
          },
          {
            "body": "issue_or_pr_quality=unknown。",
            "category": "Maintenance risk",
            "evidence": [
              "evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch"
            ],
            "severity": "low",
            "suggested_check": "Reproduce the official install and quickstart path in an isolated environment.",
            "title": "Maintenance risk requires verification",
            "user_impact": "May increase setup, validation, or first-run risk for the user."
          },
          {
            "body": "release_recency=unknown。",
            "category": "Maintenance risk",
            "evidence": [
              "evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch"
            ],
            "severity": "low",
            "suggested_check": "Reproduce the official install and quickstart path in an isolated environment.",
            "title": "Maintenance risk requires verification",
            "user_impact": "May increase setup, validation, or first-run risk for the user."
          }
        ],
        "source": "ProjectPitfallLog + ProjectHitPacket + validation + community signals",
        "summary": "Found 10 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Installation risk - Installation risk requires verification.",
        "title": "Pitfall Log"
      },
      "snapshot": {
        "contributors": 22,
        "forks": 141,
        "license": "unknown",
        "note": "站点快照，非实时质量证明；用于开工前背景判断。",
        "stars": 666
      },
      "source_url": "https://github.com/elastic/mcp-server-elasticsearch",
      "steps": [
        {
          "body": "不安装项目，先体验能力节奏。",
          "code": "preview",
          "title": "先试 Prompt"
        },
        {
          "body": "理解输入、输出、失败模式和边界。",
          "code": "manual",
          "title": "读说明书"
        },
        {
          "body": "把上下文交给宿主 AI 继续工作。",
          "code": "context",
          "title": "带给 AI"
        },
        {
          "body": "进入主力环境前先完成安装入口与风险边界验证。",
          "code": "verify",
          "title": "沙箱验证"
        }
      ],
      "subtitle": "Elasticsearch MCP Server",
      "title": "mcp-server-elasticsearch 能力包",
      "trial_prompt": "# mcp-server-elasticsearch - Prompt Preview\n\n> Copy the prompt below into your AI host before installing anything.\n> Its purpose is to let you safely feel the project's workflow, not to claim the project has already run.\n\n## Copy this prompt\n\n```text\nYou are using an independent Doramagic capability pack for elastic/mcp-server-elasticsearch.\n\nProject:\n- Name: mcp-server-elasticsearch\n- Repository: https://github.com/elastic/mcp-server-elasticsearch\n- Summary: Elasticsearch MCP Server\n- Host target: mcp_host, claude, cursor\n\nGoal:\nHelp me evaluate this project for the following task without installing it yet: Elasticsearch MCP Server\n\nBefore taking action:\n1. Restate my task, success standard, and boundary.\n2. Identify whether the next step requires tools, browser access, network access, filesystem access, credentials, package installation, or host configuration.\n3. Use only the Doramagic Project Pack, the upstream repository, and the source-linked evidence listed below.\n4. If a real command, install step, API call, file write, or host integration is required, mark it as \"requires post-install verification\" and ask for approval first.\n5. If evidence is missing, say \"evidence is missing\" instead of filling the gap.\n\nPreviewable capabilities:\n- Environment Variable Interpolation: Substitute environment variables in configuration using ${VAR} or ${VAR:default} syntax (Inputs: String with ${VAR} or ${VAR:default} placeholders; Outputs: Interpolated string)\n\nCapabilities that require post-install verification:\n- Elasticsearch Index Management: List and explore Elasticsearch indices with their status, document counts, and metadata (Inputs: index_pattern: string (default '*'); Outputs: Array of index objects with name, status, doc count)\n- Index Mapping Retrieval: Retrieve field mappings for specified Elasticsearch indices to understand data schemas (Inputs: index: string; Outputs: Mapping response with field definitions and types)\n- Full-text Search: Execute search queries against Elasticsearch indices with support for aggregations and source field filtering (Inputs: index: string, query_body: object, fields: array (optional _source fields); Outputs: Hits with sources, aggregations, total count)\n- ES|QL Query Execution: Run ES|QL (Elasticsearch Query Language) queries for data analysis and transformation (Inputs: query: string, params: object (optional); Outputs: Columns metadata and result rows)\n- Shard Distribution Analysis: View shard allocation and distribution across nodes for debugging and performance analysis (Inputs: index: string (optional); Outputs: Shard details including index, shard num, primary/replica, state, docs count, node)\n\nCore service flow:\n1. page-project-introduction: Project Introduction. Produce one small intermediate artifact and wait for confirmation.\n2. page-available-tools: Available MCP Tools. Produce one small intermediate artifact and wait for confirmation.\n3. page-architecture: System Architecture. Produce one small intermediate artifact and wait for confirmation.\n4. page-protocols: MCP Protocol Configuration. Produce one small intermediate artifact and wait for confirmation.\n5. page-deployment: Docker Deployment. Produce one small intermediate artifact and wait for confirmation.\n\nSource-backed evidence to keep in mind:\n- https://github.com/elastic/mcp-server-elasticsearch\n- https://github.com/elastic/mcp-server-elasticsearch#readme\n- src/utils/interpolator.rs\n- elastic-mcp.json5\n- README.md\n- catalog-info.yaml\n- NOTICE.txt\n- src/servers/elasticsearch/base_tools.rs\n- src/servers/elasticsearch/mod.rs\n- src/lib.rs\n\nFirst response rules:\n1. Start Step 1 only.\n2. Explain the one service action you will perform first.\n3. Ask exactly three questions about my target workflow, success standard, and sandbox boundary.\n4. Stop and wait for my answers.\n\nStep 1 follow-up protocol:\n- After I answer the first three questions, stay in Step 1.\n- Produce six parts only: clarified task, success standard, boundary conditions, two or three options, tradeoffs for each option, and one recommendation.\n- End by asking whether I confirm the recommendation.\n- Do not move to Step 2 until I explicitly confirm.\n\nConversation rules:\n- Advance one step at a time and wait for confirmation after each small artifact.\n- Write outputs as recommendations or planned checks, not as completed execution.\n- Do not claim tests passed, files changed, commands ran, APIs were called, or the project was installed.\n- If the user asks for execution, first provide the sandbox setup, expected output, rollback, and approval checkpoint.\n```\n",
      "voices": [
        {
          "body": "来源平台：github。github/github_issue: Dependency Dashboard（https://github.com/elastic/mcp-server-elasticsearch/issues/6）；github/github_issue: Dependency Dashboard（https://github.com/elastic/mcp-server-elasticsearch/issues/6）；github/github_issue: Dependency Dashboard（https://github.com/elastic/mcp-server-elasticsearch/issues/6）；github/github_issue: get_mappings tool fails with \"error decoding response body\" when nested （https://github.com/elastic/mcp-server-elasticsearch/issues/185）；github/github_issue: get_mappings tool fails with \"error decoding response body\" when nested （https://github.com/elastic/mcp-server-elasticsearch/issues/185）；github/github_release: v0.4.6（https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.6）；github/github_release: v0.4.6（https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.6）；github/github_release: v0.4.5（https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.5）；github/github_release: v0.4.5（https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.5）；github/github_release: v0.4.4（https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.4）；github/github_release: v0.4.4（https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.4）；github/github_release: v0.4.3（https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.3）。这些是项目级外部声音，不作为单独质量证明。",
          "items": [
            {
              "kind": "github_issue",
              "source": "github",
              "title": "Dependency Dashboard",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/issues/6"
            },
            {
              "kind": "github_issue",
              "source": "github",
              "title": "Dependency Dashboard",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/issues/6"
            },
            {
              "kind": "github_issue",
              "source": "github",
              "title": "Dependency Dashboard",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/issues/6"
            },
            {
              "kind": "github_issue",
              "source": "github",
              "title": "get_mappings tool fails with \"error decoding response body\" when nested ",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/issues/185"
            },
            {
              "kind": "github_issue",
              "source": "github",
              "title": "get_mappings tool fails with \"error decoding response body\" when nested ",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/issues/185"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.4.6",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.6"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.4.6",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.6"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.4.5",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.5"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.4.5",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.5"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.4.4",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.4"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.4.4",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.4"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.4.3",
              "url": "https://github.com/elastic/mcp-server-elasticsearch/releases/tag/v0.4.3"
            }
          ],
          "status": "已收录 12 条来源",
          "title": "社区讨论"
        }
      ]
    },
    "homepage_card": {
      "category": "工具连接与集成",
      "desc": "Elasticsearch MCP Server",
      "effort": "安装已验证",
      "forks": 141,
      "icon": "link",
      "name": "mcp-server-elasticsearch 能力包",
      "risk": "可发布",
      "slug": "mcp-server-elasticsearch",
      "stars": 666,
      "tags": [
        "MCP 工具",
        "知识库问答",
        "流程自动化",
        "节点式流程编排",
        "评测体系"
      ],
      "thumb": "gray",
      "type": "MCP 配置"
    },
    "manual": {
      "markdown": "# https://github.com/elastic/mcp-server-elasticsearch Project Manual\n\nGenerated at: 2026-05-31 01:04:06 UTC\n\n## Table of Contents\n\n- [Project Introduction](#page-project-introduction)\n- [Available MCP Tools](#page-available-tools)\n- [System Architecture](#page-architecture)\n- [MCP Protocol Configuration](#page-protocols)\n- [Docker Deployment](#page-deployment)\n- [Authentication and Security](#page-authentication)\n- [Configuration Reference](#page-configuration-reference)\n- [Troubleshooting Guide](#page-troubleshooting)\n- [Monitoring and Health Checks](#page-monitoring)\n- [Contributing Guide](#page-contributing)\n\n<a id='page-project-introduction'></a>\n\n## Project Introduction\n\n### Related Pages\n\nRelated topics: [System Architecture](#page-architecture), [Available MCP Tools](#page-available-tools), [Docker Deployment](#page-deployment)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n- [catalog-info.yaml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/catalog-info.yaml)\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)\n- [renovate.json](https://github.com/elastic/mcp-server-elasticsearch/blob/main/renovate.json)\n- [NOTICE.txt](https://github.com/elastic/mcp-server-elasticsearch/blob/main/NOTICE.txt)\n</details>\n\n# Project Introduction\n\n## Overview\n\nThe 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.\n\nSource: [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n\n### Deprecation Notice\n\n> [!CAUTION]\n> This MCP server is deprecated and will only receive critical security updates going forward. It has been superseded by the [Elastic Agent Builder](https://ela.st/agent-builder-docs) [MCP endpoint](https://ela.st/agent-builder-mcp), which is available in Elastic 9.2.0+ and Elasticsearch Serverless projects.\n\nSource: [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n\n## Project Metadata\n\nThe project is classified as a beta-stage library owned by the DevTools team at Elastic.\n\n| Attribute | Value |\n|-----------|-------|\n| **Project Name** | mcp-server-elasticsearch |\n| **Type** | Library (MCP Server) |\n| **Lifecycle** | Beta |\n| **Owner** | group:devtools-team |\n| **CI/CD** | Buildkite Pipeline |\n| **Copyright** | Copyright 2025 Elasticsearch B.V. |\n\nSource: [catalog-info.yaml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/catalog-info.yaml)\n\n## Architecture\n\n### High-Level Architecture\n\n```mermaid\ngraph TD\n    A[AI Agent / MCP Client] -->|MCP Protocol| B[MCP Server]\n    B --> C[Elasticsearch Cluster]\n    \n    subgraph \"MCP Server Components\"\n        D[CLI Layer<br/>stdio/http] --> E[Protocol Handler]\n        E --> F[Tool Router]\n        F --> G[Elasticsearch Client]\n    end\n    \n    subgraph \"Tools\"\n        H[list_indices]\n        I[get_mappings]\n        J[search]\n        K[esql]\n        L[get_shards]\n        M[Custom Tools]\n    end\n    \n    G --> H\n    G --> I\n    G --> J\n    G --> K\n    G --> L\n    G --> M\n```\n\n### Server Modes\n\nThe MCP server supports two primary transport modes:\n\n| Mode | Description | Use Case |\n|------|-------------|----------|\n| **Stdio** | Standard input/output communication | Local MCP clients, Claude Desktop, Cursor |\n| **HTTP/SSE** | HTTP with Server-Sent Events | Remote deployment, web-based clients, n8n integration |\n\nSource: [src/cli.rs:19-35](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n### Configuration Structure\n\n```mermaid\ngraph LR\n    A[Config File<br/>JSON5] --> B[Interpolator]\n    B --> C[Configuration]\n    \n    subgraph \"Elasticsearch Config\"\n        D[url]\n        E[api_key]\n        F[username/password]\n        G[ssl_skip_verify]\n    end\n    \n    subgraph \"MCP Servers Config\"\n        H[Stdio servers]\n        I[Streamable HTTP servers]\n        J[SSE servers]\n    end\n```\n\nSource: [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs) and [src/cli.rs:63-80](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n## Core Components\n\n### ElasticsearchMcpConfig\n\nThe main configuration struct for the Elasticsearch MCP server.\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `url` | `String` | Required | Cluster URL |\n| `api_key` | `Option<String>` | None | API key authentication |\n| `username` | `Option<String>` | None | Username for basic auth |\n| `password` | `Option<String>` | None | Password for basic auth |\n| `ssl_skip_verify` | `bool` | `false` | Skip SSL certificate verification |\n| `tools` | `Tools` | Empty | Custom tools configuration |\n| `prompts` | `Vec<String>` | Empty | Prompts to expose |\n\nSource: [src/servers/elasticsearch/mod.rs:64-85](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\n### EsClientProvider\n\nA wrapper around the Elasticsearch client that provides request-context-aware client instances.\n\n```rust\npub struct EsClientProvider(Elasticsearch);\n```\n\nThe provider supports authentication via:\n- **API Key**: `Credentials::EncodedApiKey(api_key)`\n- **Basic Auth**: `Credentials::Basic(username, password)`\n- **Per-request Auth**: Extracts `Authorization` header from incoming HTTP requests\n\nSource: [src/servers/elasticsearch/mod.rs:88-106](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\n## Available Tools\n\n### Base Tools\n\n| Tool | Description | Read Only |\n|------|-------------|-----------|\n| `list_indices` | List all available Elasticsearch indices | Yes |\n| `get_mappings` | Retrieve index mappings | Yes |\n| `search` | Perform Elasticsearch query DSL search | Yes |\n| `esql` | Execute ES|QL queries | Yes |\n| `get_shards` | Get shard information for indices | Yes |\n\nSource: [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n\n### Custom Tools\n\nThe server supports extensible custom tools through the `Tools` struct:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `incl_excl` | `Option<IncludeExclude>` | Include/exclude filter for tools |\n| `custom` | `HashMap<String, CustomTool>` | Map of custom tool definitions |\n\nSupported custom tool types:\n\n| Type | Description |\n|------|-------------|\n| `Esql` | ES|QL query tool with configurable result format |\n| `SearchTemplate` | Search template tool (by ID or inline) |\n\nSource: [src/servers/elasticsearch/mod.rs:1-65](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\n### ES|QL Result Formats\n\n| Format | Description |\n|--------|-------------|\n| `json` (default) | Output as JSON array or single object |\n| `value` | If single object with single property, output only value |\n\nSource: [src/servers/elasticsearch/mod.rs:28-34](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\n## Data Models\n\n### Search Result\n\n```rust\npub struct SearchResult {\n    pub hits: Hits,\n    #[serde(default)]\n    pub aggregations: IndexMap<String, Value>,\n}\n\npub struct Hits {\n    pub total: Option<TotalHits>,\n    pub hits: Vec<Hit>,\n}\n\npub struct TotalHits {\n    pub value: u64,\n}\n\npub struct Hit {\n    #[serde(rename = \"_source\")]\n    pub source: Value,\n}\n```\n\nSource: [src/servers/elasticsearch/base_tools.rs:100-122](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n\n### ES|QL Response\n\n```rust\npub struct EsqlQueryResponse {\n    pub is_partial: Option<bool>,\n    pub columns: Vec<Column>,\n    pub values: Vec<Vec<Value>>,\n}\n\npub struct Column {\n    pub name: String,\n    #[serde(rename = \"type\")]\n    pub type_: String,\n}\n```\n\nSource: [src/servers/elasticsearch/base_tools.rs:155-169](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n\n## Transport Protocols\n\n### Stdio Transport\n\nUsed for local MCP client connections. Compatible with Claude Desktop, Cursor, and VS Code.\n\n```json\n{\n  \"mcpServers\": {\n    \"elasticsearch\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@elastic/mcp-server-elasticsearch\"]\n    }\n  }\n}\n```\n\nSource: [src/cli.rs:42-55](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n### HTTP Transport\n\nHTTP server with optional SSE support for remote deployments.\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/` | GET | Hello endpoint |\n| `/ping` | GET | Health check |\n| `/ready` | GET | Readiness probe |\n| `/live` | GET | Liveness probe |\n| `/mcp/sse` | GET | SSE endpoint |\n| `/mcp` | POST | MCP JSON-RPC handler |\n\nSource: [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n\n## Environment Variable Interpolation\n\nThe configuration file supports environment variable interpolation using `${VAR}` or `${VAR:default}` syntax.\n\n```rust\nfn interpolate(name: String, lookup: impl Fn(&str) -> Option<String>) \n    -> Result<String, InterpolationError>\n```\n\n| Syntax | Behavior |\n|--------|----------|\n| `${VAR}` | Required - fails if not defined |\n| `${VAR:default}` | Optional - uses default if not defined |\n\nSource: [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)\n\n## CLI Commands\n\n### Stdio Command\n\n```bash\nmcp-server-elasticsearch stdio --config <path>\n```\n\nSource: [src/cli.rs:36-41](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n### HTTP Command\n\n```bash\nmcp-server-elasticsearch http [OPTIONS]\n```\n\n| Option | Environment Variable | Default |\n|--------|---------------------|---------|\n| `--config <path>` | - | None |\n| `--address <ip:port>` | `HTTP_ADDRESS` | `127.0.0.1:8080` |\n| `--sse` | - | Disabled |\n\nSource: [src/cli.rs:19-33](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n## Dependency Management\n\nThe project uses Renovate for automated dependency updates.\n\n| Setting | Value |\n|---------|-------|\n| Schema | `https://docs.renovatebot.com/renovate-schema.json` |\n| Base Config | `local>elastic/renovate-config` |\n| Schedule | `after 1am on monday` |\n| Status | Rate-limited |\n\nSource: [renovate.json](https://github.com/elastic/mcp-server-elasticsearch/blob/main/renovate.json)\n\n## Known Issues\n\n### Community-Reported Issues\n\n| Issue | Description |\n|-------|-------------|\n| #185 | `get_mappings` tool fails with \"error decoding response body\" when nested type is omitted in properties |\n| #170 | Basic auth failed - 401 Unauthorized despite correct credentials |\n| #191 | Missing Linux ARM64 binary releases |\n| #17 | Request for streamable HTTP transport support |\n\nSource: [GitHub Issues](https://github.com/elastic/mcp-server-elasticsearch/issues)\n\n## Quick Reference\n\n### Minimum Requirements\n\n- Elasticsearch cluster (version 8.x or 9.x)\n- Authentication credentials (API key or username/password)\n- Docker (for container deployment)\n- MCP-compatible client\n\n### Default Configuration\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL:}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n  }\n}\n```\n\nSource: [src/lib.rs:36-45](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n### Version History\n\n| Version | Key Changes |\n|---------|-------------|\n| v0.4.6 | Deprecation notice added |\n| v0.4.5 | ENV name fix for username |\n| v0.4.4 | CA certificates added |\n| v0.4.3 | Default port set to 8080 |\n| v0.4.2 | Default port changed to 8000 |\n| v0.3.1 | Hashbang fix for npx execution |\n| v0.3.0 | OpenTelemetry support, aggregation results |\n| v0.2.0 | `get_shards` tool added |\n\nSource: [GitHub Releases](https://github.com/elastic/mcp-server-elasticsearch/releases)\n\n---\n\n<a id='page-available-tools'></a>\n\n## Available MCP Tools\n\n### Related Pages\n\nRelated topics: [System Architecture](#page-architecture), [Troubleshooting Guide](#page-troubleshooting)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n</details>\n\n# Available MCP Tools\n\nThe 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.\n\n## Overview\n\nThe 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.\n\n```mermaid\ngraph TD\n    A[MCP Client] -->|tool_request| B[EsBaseTools]\n    B --> C[Elasticsearch Cluster]\n    \n    subgraph Tools\n        D[list_indices]\n        E[get_mappings]\n        F[search]\n        G[esql]\n        H[get_shards]\n    end\n    \n    C -->|response| B\n    B -->|tool_result| A\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:30-36](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L30-L36)\n\n## Core Tools\n\nCore tools are built-in MCP tools that provide fundamental Elasticsearch operations. They are implemented in `EsBaseTools` and registered via the `#[tool_router]` macro.\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:1-40](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L1-L40)\n\n### list_indices\n\nLists all available Elasticsearch indices matching a specified pattern.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `index_pattern` | String | Yes | Index pattern to filter indices (e.g., `*`, `logs-*`) |\n\n**Implementation Details:**\n\nThe tool uses the Elasticsearch `_cat/indices` API with JSON response format, requesting the `index`, `status`, and `docs.count` fields.\n\n```rust\n#[tool(\n    description = \"List all available Elasticsearch indices\",\n    annotations(title = \"List ES indices\", read_only_hint = true)\n)]\nasync fn list_indices(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(ListIndicesParams { index_pattern }): Parameters<ListIndicesParams>,\n) -> Result<CallToolResult, rmcp::Error>\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:70-92](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L70-L92)\n\n### get_mappings\n\nRetrieves field mappings for a specific Elasticsearch index.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `index` | String | Yes | Name of the Elasticsearch index |\n\n**Implementation Details:**\n\nThe tool calls the `_mapping` endpoint for the specified index and returns the complete mapping definition.\n\n```rust\n#[tool(\n    description = \"Get field mappings for a specific Elasticsearch index\",\n    annotations(title = \"Get ES index mappings\", read_only_hint = true)\n)]\nasync fn get_mappings(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(GetMappingsParams { index }): Parameters<GetMappingsParams>,\n) -> Result<CallToolResult, rmcp::Error>\n```\n\n**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](https://github.com/elastic/mcp-server-elasticsearch/issues/185).\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:95-115](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L95-L115)\n\n### search\n\nPerforms an Elasticsearch search using the Query DSL.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `index` | String | Yes | Name of the Elasticsearch index to search |\n| `fields` | `Vec<String>` | No | Specific fields to return, augments `_source` |\n| `query_body` | `Map<String, Value>` | Yes | Complete Elasticsearch query DSL object |\n\n**Implementation Details:**\n\nThe 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.\n\nThe response includes both search hits and aggregations:\n\n```rust\n#[derive(Serialize, Deserialize)]\npub struct SearchResult {\n    pub hits: Hits,\n    #[serde(default)]\n    pub aggregations: IndexMap<String, Value>,\n}\n```\n\n```rust\n#[tool(\n    description = \"Perform an Elasticsearch search with the provided query DSL.\",\n    annotations(title = \"Elasticsearch search DSL query\", read_only_hint = true)\n)]\nasync fn search(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(SearchParams {\n        index,\n        fields,\n        query_body,\n    }): Parameters<SearchParams>,\n) -> Result<CallToolResult, rmcp::Error>\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:118-165](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L118-L165)\n\n### esql\n\nExecutes an ES|QL query against Elasticsearch.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `query` | String | Yes | Complete ES|QL query |\n\n**Response Formats:**\n\nThe tool supports different output formats configured via the `format` parameter:\n\n| Format | Description |\n|--------|-------------|\n| `json` (default) | Output as JSON array of objects or single object |\n| `value` | If single object with single property, output only its value |\n\n**Source:** [src/servers/elasticsearch/mod.rs:40-55](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L40-L55)\n\n### get_shards\n\nRetrieves shard allocation information for all or specific indices.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `index` | `Option<String>` | No | Optional index name to filter shards |\n\n**Implementation Details:**\n\nThe tool uses the Elasticsearch `_cat/shards` API with JSON format, requesting `index`, `shard`, `prirep`, `state`, `docs`, `store`, and `node` fields.\n\n```rust\n#[tool(\n    description = \"Get shard information for all or specific indices.\",\n    annotations(title = \"Get ES shard information\", read_only_hint = true)\n)]\nasync fn get_shards(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(GetShardsParams { index }): Parameters<GetShardsParams>,\n) -> Result<CallToolResult, rmcp::Error>\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:168-200](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L168-L200)\n\n## Custom Tools\n\nCustom 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.\n\n**Source:** [src/servers/elasticsearch/mod.rs:15-30](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L15-L30)\n\n### Tool Definition Structure\n\n```rust\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(tag = \"type\", rename_all = \"snake_case\")]\npub enum CustomTool {\n    Esql(EsqlTool),\n    SearchTemplate(SearchTemplateTool),\n}\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct ToolBase {\n    pub description: String,\n    pub parameters: IndexMap<String, schemars::schema::SchemaObject>,\n    pub annotations: Option<ToolAnnotations>,\n}\n```\n\n### EsqlTool\n\nPre-configured ES|QL queries that can be exposed as tools. Includes a base definition with description, parameters schema, and the query to execute.\n\n**Source:** [src/servers/elasticsearch/mod.rs:32-55](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L32-L55)\n\n### SearchTemplateTool\n\nPre-configured search templates that accept parameters at runtime. Supports two template specification modes:\n\n| Mode | Description |\n|------|-------------|\n| `template_id` | Reference an existing saved search template by ID |\n| `template` | Inline template definition as JSON |\n\n**Source:** [src/servers/elasticsearch/mod.rs:57-72](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L57-L72)\n\n## Tool Configuration\n\nTools are configured in the server configuration file under the `tools` section:\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY}\"\n  },\n  \"tools\": {\n    \"incl_excl\": {\n      \"include\": [\"custom_tool_1\"],\n      \"exclude\": [\"custom_tool_2\"]\n    },\n    \"custom\": {\n      \"my_esql_query\": {\n        \"type\": \"esql\",\n        \"description\": \"Count documents by status\",\n        \"parameters\": {},\n        \"query\": \"FROM my-index | STATS count = COUNT(*)\"\n      }\n    }\n  }\n}\n```\n\n**Source:** [src/lib.rs:45-65](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs#L45-L65)\n\n## Server Capabilities\n\nEach tool set reports its capabilities through the `get_info()` method:\n\n```rust\nfn get_info(&self) -> ServerInfo {\n    ServerInfo {\n        protocol_version: ProtocolVersion::V_2025_03_26,\n        capabilities: ServerCapabilities::builder().enable_tools().build(),\n        server_info: Implementation::from_build_env(),\n        instructions: Some(\"Provides access to Elasticsearch\".to_string()),\n    }\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:27-36](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L27-L36)\n\n## Transport Support\n\nTools can be accessed through multiple transport protocols:\n\n| Transport | Description | Use Case |\n|-----------|-------------|----------|\n| `stdio` | Direct process communication | Local clients, Claude Desktop |\n| `streamable-http` | HTTP-based with session support | Web integrations, remote access |\n| `sse` | Server-Sent Events (deprecated) | Legacy compatibility |\n\n**Source:** [src/cli.rs:20-35](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs#L20-L35)\n\n## Response Structure\n\nAll tools return results wrapped in `CallToolResult`:\n\n```rust\nOk(CallToolResult::success(vec![\n    Content::text(format!(\"Found {} indices:\", response.len())),\n    Content::json(response)?,\n]))\n```\n\nThe server returns:\n- Text summary with counts or status\n- JSON content with the full response data\n\n## Community Considerations\n\nWhen using these tools, be aware of the following community-reported issues:\n\n- **Aggregation results in search**: Some agents may not receive aggregation results properly. The [enhancement request #45](https://github.com/elastic/mcp-server-elasticsearch/issues/45) tracks improvements to aggregation handling.\n- **get_mappings with nested types**: Valid Elasticsearch mappings with implicit nested types may cause decoding errors. See [issue #185](https://github.com/elastic/mcp-server-elasticsearch/issues/185).\n- **HTTP transport limitations**: When accessing via HTTP/SSE, certain tool combinations may return errors. This is discussed in [issue #173](https://github.com/elastic/mcp-server-elasticsearch/issues/173).\n\n---\n\n<a id='page-architecture'></a>\n\n## System Architecture\n\n### Related Pages\n\nRelated topics: [MCP Protocol Configuration](#page-protocols), [Available MCP Tools](#page-available-tools)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)\n- [catalog-info.yaml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/catalog-info.yaml)\n</details>\n\n# System Architecture\n\n## Overview\n\nThe 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.\n\n**Project Type:** Library component (Backstage classification)  \n**Owner:** devtools-team  \n**Lifecycle:** Beta (deprecated as of v0.4.6)  \n**Source:** [catalog-info.yaml:1-56]()\n\n## High-Level Architecture\n\nThe server follows a layered architecture with distinct separation between transport handling, protocol implementation, and tool execution:\n\n```mermaid\ngraph TD\n    subgraph Transport Layer\n        STDIOC[Stdio Transport]\n        HTTPC[HTTP Transport]\n        SSEC[SSE Transport]\n    end\n    \n    subgraph Protocol Layer\n        MCP[Model Context Protocol]\n    end\n    \n    subgraph Server Layer\n        ESMC[ElasticsearchMcp]\n        BASET[EsBaseTools]\n    end\n    \n    subgraph Tools\n        SEARCH[search]\n        LISTIDX[list_indices]\n        GETMAP[get_mappings]\n        GETSHARDS[get_shards]\n        ESQL[esql]\n    end\n    \n    subgraph Elasticsearch\n        ES[Elasticsearch Cluster]\n    end\n    \n    STDIOC --> MCP\n    HTTPC --> MCP\n    SSEC --> MCP\n    MCP --> ESMC\n    ESMC --> BASET\n    BASET --> SEARCH\n    BASET --> LISTIDX\n    BASET --> GETMAP\n    BASET --> GETSHARDS\n    BASET --> ESQL\n    SEARCH --> ES\n    LISTIDX --> ES\n    GETMAP --> ES\n    GETSHARDS --> ES\n    ESQL --> ES\n```\n\n## Transport Layer\n\nThe server supports multiple transport mechanisms, configurable via command-line arguments:\n\n### Stdio Transport\n\nThe default transport mode for local MCP client integrations. Communicates via standard input/output streams using JSON-RPC messages.\n\n```rust\npub enum Command {\n    Stdio(StdioCommand),\n    Http(HttpCommand),\n}\n\npub struct StdioCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n}\n```\n\n**Source:** [src/cli.rs:19-29]()\n\n### HTTP Transport\n\nSupports remote deployments with optional Server-Sent Events (SSE) fallback:\n\n```rust\npub struct HttpCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n\n    /// Address to listen to [default: 127.0.0.1:8080]\n    #[clap(long, value_name = \"IP_ADDRESS:PORT\", env = \"HTTP_ADDRESS\")]\n    pub address: Option<std::net::SocketAddr>,\n\n    /// Also start an SSE server on '/sse'\n    #[clap(long)]\n    pub sse: bool,\n}\n```\n\n| Parameter | Type | Default | Environment Variable |\n|-----------|------|---------|---------------------|\n| config | PathBuf | None | - |\n| address | SocketAddr | 127.0.0.1:8080 | HTTP_ADDRESS |\n| sse | bool | false | - |\n\n**Source:** [src/cli.rs:31-47]()\n\n### Runtime Entry Points\n\nThe CLI determines which transport to initialize based on the subcommand:\n\n```rust\npub async fn run_stdio(cmd: StdioCommand, container_mode: bool) -> anyhow::Result<()> {\n    tracing::info!(\"Starting stdio server\");\n    let handler = setup_services(&cmd.config, container_mode).await?;\n    let service = handler.serve(stdio()).await.inspect_err(|e| {\n        tracing::error!(\"serving error: {:?}\", e);\n    })?;\n    // ...\n}\n\npub async fn run_http(cmd: HttpCommand, container_mode: bool) -> anyhow::Result<()> {\n    let handler = setup_services(&cmd.config, container_mode).await?;\n    let server_provider = move || handler.clone();\n    // ...\n}\n```\n\n**Source:** [src/lib.rs:1-100]()\n\n## Configuration System\n\n### Configuration Structure\n\nThe server uses JSON5 format for configuration files, with support for comments and environment variable interpolation:\n\n```rust\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct Configuration {\n    pub elasticsearch: elasticsearch::ElasticsearchMcpConfig,\n    #[serde(default)]\n    pub mcp_servers: HashMap<String, McpServer>,\n}\n```\n\n**Source:** [src/cli.rs:104-111]()\n\n### Elasticsearch Configuration\n\n```rust\npub struct ElasticsearchMcpConfig {\n    /// Cluster URL\n    pub url: String,\n\n    /// API key\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub api_key: Option<String>,\n\n    /// Username\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub username: Option<String>,\n\n    /// Password\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub password: Option<String>,\n\n    /// Should we skip SSL certificate verification?\n    #[serde(default, deserialize_with = \"deserialize_bool_from_anything\")]\n    pub ssl_skip_verify: bool,\n\n    /// Search templates to expose as tools or resources\n    #[serde(default)]\n    pub tools: Tools,\n\n    /// Prompts\n    #[serde(default)]\n    pub prompts: Vec<String>,\n}\n```\n\n| Parameter | Required | Default | Environment Variable |\n|-----------|----------|---------|---------------------|\n| url | Yes | - | ES_URL |\n| api_key | No | - | ES_API_KEY |\n| username | No | - | ES_USERNAME |\n| password | No | - | ES_PASSWORD |\n| ssl_skip_verify | No | false | ES_SSL_SKIP_VERIFY |\n\n**Source:** [src/servers/elasticsearch/mod.rs:1-100]()\n\n### Environment Variable Interpolation\n\nThe configuration parser supports `${VAR_NAME}` and `${VAR_NAME:default_value}` syntax:\n\n```rust\nfn expand(name: &str) -> Result<String, InterpolationError> {\n    let lookup = |s: &str| match s {\n        \"foo\" => Some(\"foo_value\".to_string()),\n        \"bar\" => Some(\"bar_value\".to_string()),\n        _ => None,\n    };\n    interpolate(name.to_string(), lookup)\n}\n```\n\n**Source:** [src/utils/interpolator.rs:1-50]()\n\n## Core Server Components\n\n### ElasticsearchMcp Server\n\nThe main server implementation wraps the Elasticsearch client and provides tool routing:\n\n```rust\npub struct ElasticsearchMcp {}\n\nimpl ElasticsearchMcp {\n    pub fn new_with_config(\n        config: ElasticsearchMcpConfig, \n        container_mode: bool\n    ) -> anyhow::Result<base_tools::EsBaseTools> {\n        let creds = if let Some(api_key) = config.api_key.clone() {\n            Some(Credentials::EncodedApiKey(api_key))\n        } else if let Some(username) = config.username.clone() {\n            let pwd = config.password.clone().ok_or(anyhow::Error::msg(\"missing password\"))?;\n            Some(Credentials::Basic(username, pwd))\n        } else {\n            None\n        };\n\n        let url = config.url.as_str();\n        if url.is_empty() {\n            return Err(anyhow::Error::msg(\"Elasticsearch URL is empty\"));\n        }\n\n        let mut url = Url::parse(url)?;\n        if container_mode {\n            rewrite_localhost(&mut url)?;\n        }\n\n        let pool = elasticsearch::http::transport::SingleNodeConnectionPool::new(url.clone());\n        let mut transport = elasticsearch::http::transport::TransportBuilder::new(pool);\n        if let Some(creds) = creds {\n            transport = transport.auth(creds);\n        }\n        // ...\n    }\n}\n```\n\n**Source:** [src/servers/elasticsearch/mod.rs:1-100]()\n\n### EsClientProvider\n\nA wrapper around the Elasticsearch client that supports per-request authentication:\n\n```rust\n#[derive(Clone)]\npub struct EsClientProvider(Elasticsearch);\n\nimpl EsClientProvider {\n    pub fn new(client: Elasticsearch) -> Self {\n        EsClientProvider(client)\n    }\n\n    /// If the incoming request is a http request and has an `Authorization` header, use it\n    /// to authenticate to the remote ES instance.\n    pub fn get(&self, context: RequestContext<RoleServer>) -> Elasticsearch {\n        // Authentication context handling\n    }\n}\n```\n\n**Source:** [src/servers/elasticsearch/mod.rs:100-150]()\n\n### EsBaseTools\n\nThe core tool provider implementing the MCP tool protocol:\n\n```rust\n#[derive(Clone)]\npub struct EsBaseTools {\n    es_client: EsClientProvider,\n    tool_router: ToolRouter<EsBaseTools>,\n}\n\nimpl EsBaseTools {\n    pub fn new(es_client: Elasticsearch) -> Self {\n        Self {\n            es_client: EsClientProvider::new(es_client),\n            tool_router: Self::tool_router(),\n        }\n    }\n}\n\n#[tool_handler]\nimpl ServerHandler for EsBaseTools {\n    fn get_info(&self) -> ServerInfo {\n        ServerInfo {\n            protocol_version: ProtocolVersion::V_2025_03_26,\n            capabilities: ServerCapabilities::builder().enable_tools().build(),\n            server_info: Implementation::from_build_env(),\n            instructions: Some(\"Provides access to Elasticsearch\".to_string()),\n        }\n    }\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:1-100]()\n\n## Tool System\n\n### Available Tools\n\n| Tool | Description | Read Only |\n|------|-------------|-----------|\n| list_indices | List all available Elasticsearch indices | Yes |\n| get_mappings | Retrieve index mappings | Yes |\n| get_shards | Get shard information for indices | Yes |\n| search | Perform Elasticsearch search with Query DSL | Yes |\n| esql | Execute ES\\|QL queries | Yes |\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:100-200]()\n\n### Tool Parameter Definitions\n\n```rust\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct ListIndicesParams {\n    /// Index pattern of Elasticsearch indices to list\n    pub index_pattern: String,\n}\n\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct GetMappingsParams {\n    /// Name of the Elasticsearch index to get mappings for\n    index: String,\n}\n\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct SearchParams {\n    /// Name of the Elasticsearch index to search\n    index: String,\n\n    /// Name of the fields that need to be returned (optional)\n    fields: Option<Vec<String>>,\n\n    /// Complete Elasticsearch query DSL object that can include query, size, from, sort, etc.\n    query_body: Map<String, Value>,\n}\n\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct EsqlQueryParams {\n    /// Complete Elasticsearch ES|QL query\n    query: String,\n}\n\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct GetShardsParams {\n    /// Optional index name to get shard information for\n    index: Option<String>,\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:100-200]()\n\n### Custom Tools\n\nThe server supports extensible custom tools via configuration:\n\n```rust\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(tag = \"type\", rename_all = \"snake_case\")]\npub enum CustomTool {\n    Esql(EsqlTool),\n    SearchTemplate(SearchTemplateTool),\n}\n\npub struct EsqlTool {\n    #[serde(flatten)]\n    base: ToolBase,\n    query: String,\n    #[serde(default)]\n    format: EsqlResultFormat,\n}\n\n#[derive(Debug, Serialize, Deserialize, Default)]\n#[serde(rename_all = \"snake_case\")]\npub enum EsqlResultFormat {\n    #[default]\n    Json,\n    Value,\n}\n```\n\n**Source:** [src/servers/elasticsearch/mod.rs:20-50]()\n\n## Data Models\n\n### Search Response\n\n```rust\n#[derive(Serialize, Deserialize)]\npub struct SearchResult {\n    pub hits: Hits,\n    #[serde(default)]\n    pub aggregations: IndexMap<String, Value>,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct Hits {\n    pub total: Option<TotalHits>,\n    pub hits: Vec<Hit>,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct TotalHits {\n    pub value: u64,\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:50-70]()\n\n### Index Mappings Response\n\n```rust\npub type MappingResponse = HashMap<String, Mappings>;\n\n#[derive(Serialize, Deserialize)]\npub struct Mappings {\n    pub mappings: Mapping,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct Mapping {\n    #[serde(rename = \"_meta\", skip_serializing_if = \"Option::is_none\")]\n    pub meta: Option<JsonObject>,\n    properties: HashMap<String, MappingProperty>,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct MappingProperty {\n    #[serde(rename = \"type\")]\n    pub type_: String,\n    #[serde(flatten)]\n    pub settings: HashMap<String, serde_json::Value>,\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:100-130]()\n\n### ES|QL Response\n\n```rust\n#[derive(Serialize, Deserialize)]\npub struct EsqlQueryResponse {\n    pub is_partial: Option<bool>,\n    pub columns: Vec<Column>,\n    pub values: Vec<Vec<Value>>,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct Column {\n    pub name: String,\n    #[serde(rename = \"type\")]\n    pub type_: String,\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:130-150]()\n\n## Server Initialization Flow\n\n```mermaid\nsequenceDiagram\n    participant CLI as Command Line\n    participant Config as Config Loader\n    participant Interpolator as Env Interpolator\n    participant Server as ElasticsearchMcp\n    participant Transport as MCP Transport\n    \n    CLI->>Config: Load config file\n    Config->>Interpolator: Expand ${VAR} placeholders\n    Interpolator->>Config: Expanded config\n    Config->>Server: Parse JSON5\n    Server->>Server: Create ES client with auth\n    CLI->>Transport: Start transport (stdio/http)\n    Transport->>Server: Serve MCP requests\n```\n\n**Source:** [src/lib.rs:1-100]()\n\n## Known Limitations\n\n### Community-Reported Issues\n\n1. **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.\n\n2. **HTTP Transport Complexity (Issue #17)**: Support for streamable HTTP is a requested enhancement. Currently, the server supports stdio and HTTP/SSE transports only.\n\n3. **Basic Auth Configuration (Issue #170)**: Users have reported confusion with authentication configuration when deploying via Docker, requiring careful setup of environment variables.\n\n## Architecture Summary\n\nThe Elasticsearch MCP Server implements a clean separation of concerns:\n\n1. **Transport Layer**: Handles protocol-agnostic communication (stdio/HTTP/SSE)\n2. **Protocol Layer**: Implements MCP specification for tool discovery and invocation\n3. **Service Layer**: Manages Elasticsearch connections and authentication\n4. **Tool Layer**: Provides domain-specific tools for Elasticsearch operations\n\nThis 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.\n\n---\n\n<a id='page-protocols'></a>\n\n## MCP Protocol Configuration\n\n### Related Pages\n\nRelated topics: [Docker Deployment](#page-deployment), [System Architecture](#page-architecture)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n</details>\n\n# MCP Protocol Configuration\n\n## Overview\n\nThe 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](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n\nThe 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.\n\n---\n\n## Protocol Types\n\nThe server supports three transport protocols, defined as an enum in the CLI module:\n\n| Protocol | Description | Use Case |\n|----------|-------------|----------|\n| `Stdio` | Direct stdin/stdout communication | Local MCP clients (Claude Desktop, Cursor, VS Code) |\n| `StreamableHttp` | HTTP-based streaming protocol | Web integrations, remote access, concurrent clients |\n| `Sse` | Server-Sent Events (deprecated) | Legacy HTTP support |\n\nSource: [src/cli.rs:28-33](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n### Configuration Structure\n\n```rust\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(rename_all = \"kebab-case\")]\n#[serde(tag = \"type\")]\npub enum McpServer {\n    Sse(Http),\n    StreamableHttp(Http),\n    Stdio(Stdio),\n}\n```\n\n#### Stdio Configuration\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `command` | String | Yes | Command to run (e.g., \"npx\", \"docker\") |\n| `args` | Vec<String> | Yes | Command arguments |\n| `env` | HashMap<String, String> | No | Environment variables |\n\nSource: [src/cli.rs:6-14](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n#### HTTP Configuration\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `url` | String | Yes | URL of the server |\n| `headers` | HashMap<String, String> | No | HTTP headers to send with requests |\n\nSource: [src/cli.rs:17-25](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n---\n\n## CLI Commands\n\nThe server provides two main command variants for starting the server:\n\n```rust\n#[derive(Debug, Subcommand)]\npub enum Command {\n    Stdio(StdioCommand),\n    Http(HttpCommand),\n}\n```\n\nSource: [src/cli.rs:45-49](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n### Stdio Command\n\n```rust\n#[derive(Debug, Args)]\npub struct StdioCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n}\n```\n\nSource: [src/cli.rs:57-62](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n**Usage:**\n\n```bash\ndocker run -i --rm \\\n  -e ES_URL \\\n  -e ES_API_KEY \\\n  docker.elastic.co/mcp/elasticsearch \\\n  stdio\n```\n\n### HTTP Command\n\n```rust\n#[derive(Debug, Args)]\npub struct HttpCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n\n    /// Address to listen to [default: 127.0.0.1:8080]\n    #[clap(long, value_name = \"IP_ADDRESS:PORT\", env = \"HTTP_ADDRESS\")]\n    pub address: Option<std::net::SocketAddr>,\n\n    /// Also start an SSE server on '/sse'\n    #[clap(long)]\n    pub sse: bool,\n}\n```\n\nSource: [src/cli.rs:52-56](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n**Usage:**\n\n```bash\ndocker run -p 8080:8080 \\\n  -e ES_URL \\\n  -e ES_API_KEY \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --address 0.0.0.0:8080\n```\n\n---\n\n## HTTP Server Configuration\n\nThe HTTP protocol implementation provides fine-grained control over server behavior through the `HttpServerConfig` struct:\n\n```rust\npub struct HttpServerConfig<M: SessionManager = LocalSessionManager> {\n    /// TCP address to bind to\n    pub bind: SocketAddr,\n\n    /// Parent cancellation token. `serve_with_config` will return a child token\n    pub ct: CancellationToken,\n\n    /// Streamable http server option\n    pub keep_alive: Option<Duration>,\n\n    /// Streamable http server option\n    pub stateful_mode: bool,\n\n    /// Streamable http server option\n    pub session_manager: Arc<M>,\n}\n```\n\nSource: [src/protocol/http.rs:9-21](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n\n### Configuration Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `bind` | SocketAddr | 127.0.0.1:8080 | TCP address to bind to |\n| `ct` | CancellationToken | - | Parent cancellation token for graceful shutdown |\n| `keep_alive` | Option<Duration> | None | SSE keep-alive interval for connection maintenance |\n| `stateful_mode` | bool | false | Enable stateful session management |\n| `session_manager` | Arc<M> | NeverSessionManager | Session manager implementation |\n\nSource: [src/lib.rs:75-88](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n### Protocol Implementation\n\nThe `HttpProtocol` struct provides the server startup logic:\n\n```rust\npub struct HttpProtocol {}\n\nimpl HttpProtocol {\n    pub async fn serve_with_config<S: Service<RoleServer>, M: SessionManager>(\n        server_provider: impl Into<ServerProvider<S>>,\n        config: HttpServerConfig<M>,\n    ) -> std::io::Result<CancellationToken> { ... }\n}\n```\n\nSource: [src/protocol/http.rs:25-37](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n\n---\n\n## Server Setup Flow\n\nThe following diagram shows how the server initializes and configures the MCP protocol based on user input:\n\n```mermaid\ngraph TD\n    A[Start Server] --> B{Command Type?}\n    B -->|stdio| C[Initialize StdioCommand]\n    B -->|http| D[Initialize HttpCommand]\n    \n    C --> E[Read Config File]\n    D --> F[Parse CLI Args]\n    F --> G{Config File Provided?}\n    G -->|Yes| H[Load from File]\n    G -->|No| I[Use Environment Variables]\n    E --> J[setup_services]\n    H --> J\n    I --> J\n    \n    J --> K[Create ElasticsearchMcpConfig]\n    K --> L[Build ServerProvider]\n    L --> M{Protocol Type?}\n    M -->|Stdio| N[Start Stdio Server]\n    M -->|Http| O[HttpProtocol::serve_with_config]\n    \n    O --> P[Create HttpServerConfig]\n    P --> Q[Initialize StreamableHttpServer]\n    Q --> R[Bind to Address]\n    R --> S[Listen for Connections]\n```\n\n---\n\n## Configuration File Format\n\nThe server accepts JSON configuration files that can include both Elasticsearch connection settings and MCP server definitions:\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n  },\n  \"mcp_servers\": {\n    \"my-server\": {\n      \"type\": \"streamableHttp\",\n      \"url\": \"http://localhost:8080\",\n      \"headers\": {}\n    }\n  }\n}\n```\n\nSource: [src/lib.rs:95-106](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n### Environment Variable Expansion\n\nConfiguration files support environment variable interpolation using `${VAR}` or `${VAR:default}` syntax:\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `ES_URL` | Elasticsearch cluster URL | Required |\n| `ES_API_KEY` | API key for authentication | None |\n| `ES_USERNAME` | Username for basic auth | None |\n| `ES_PASSWORD` | Password for basic auth | None |\n| `ES_SSL_SKIP_VERIFY` | Skip SSL certificate verification | false |\n| `HTTP_ADDRESS` | HTTP server bind address | 127.0.0.1:8080 |\n\nSource: [src/servers/elasticsearch/mod.rs:28-46](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\n---\n\n## Available Tools\n\nRegardless of protocol configuration, the server exposes these tools to connected MCP clients:\n\n| Tool | Description | Read Only |\n|------|-------------|-----------|\n| `list_indices` | List all available Elasticsearch indices | Yes |\n| `get_mappings` | Get field mappings for a specific index | Yes |\n| `search` | Perform Elasticsearch search with Query DSL | Yes |\n| `esql` | Execute ESQL queries | No |\n| `get_shards` | Get shard information for indices | Yes |\n\nSource: [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n\n---\n\n## Deployment Considerations\n\n### Local Development\n\nFor local development with stdio protocol, use the default configuration with environment variables:\n\n```bash\nexport ES_URL=https://localhost:9200\nexport ES_API_KEY=your-api-key\ndocker run -i --rm \\\n  -e ES_URL -e ES_API_KEY \\\n  docker.elastic.co/mcp/elasticsearch \\\n  stdio\n```\n\n### Production HTTP Deployment\n\nFor production deployments requiring remote access:\n\n```bash\ndocker run -p 8080:8080 \\\n  -e ES_URL=https://your-cluster.es.amazonaws.com:9200 \\\n  -e ES_API_KEY=your-api-key \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --address 0.0.0.0:8080\n```\n\n### Address Binding Behavior\n\n| Mode | Default Address | Container Mode Default |\n|------|-----------------|------------------------|\n| HTTP | 127.0.0.1:8080 | 0.0.0.0:8080 |\n| Stdio | N/A (uses stdin/stdout) | N/A |\n\nSource: [src/lib.rs:68-76](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n---\n\n## Known Issues and Limitations\n\n### Authentication Issues\n\nIssue #170 documents cases where basic authentication fails with 401 Unauthorized despite correct credentials. Users should verify:\n\n1. `ES_USERNAME` and `ES_PASSWORD` are both set\n2. The Elasticsearch cluster supports basic authentication\n3. No conflicting authentication headers in MCP client configuration\n\n### HTTP Transport Status\n\nAs documented in Issue #17, the server previously only supported stdio mode. Streamable-HTTP support was added to address modern deployment requirements. Users requiring HTTP transport should ensure their MCP client also supports the streamable-HTTP protocol specification.\n\n---\n\n## References\n\n- [Model Context Protocol Specification](https://modelcontextprotocol.io/specification/latest/basic/transports)\n- [Streamable HTTP Transport](https://modelcontextprotocol.io/docs/concepts/transports#streamable-http)\n- [Elasticsearch MCP Server Releases](https://github.com/elastic/mcp-server-elasticsearch/releases)\n\n---\n\n<a id='page-deployment'></a>\n\n## Docker Deployment\n\n### Related Pages\n\nRelated topics: [MCP Protocol Configuration](#page-protocols), [Authentication and Security](#page-authentication), [Configuration Reference](#page-configuration-reference)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs) - Main library entry point with container mode and service setup\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs) - Command-line interface definitions\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs) - Elasticsearch server implementation\n- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md) - Main documentation with deployment instructions\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs) - Base tools implementation\n</details>\n\n# Docker Deployment\n\nThe 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.\n\n## Architecture Overview\n\nThe 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.\n\n```mermaid\ngraph TD\n    A[MCP Client] --> B{Docker Container}\n    B --> C[Elasticsearch MCP Server]\n    C --> D{Protocol Mode}\n    D -->|Stdio| E[Direct Stdio Communication]\n    D -->|HTTP| F[Streamable HTTP Endpoint]\n    F --> G[Port 8080 or 8000]\n    C --> H[Elasticsearch Cluster]\n    \n    I[Environment Variables] --> C\n    J[Config File] --> C\n```\n\n## Container Image\n\nThe 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.\n\n| Property | Value |\n|----------|-------|\n| Image Registry | `docker.elastic.co/mcp/elasticsearch` |\n| Default Port | 8080 |\n| Alternative Port | 8000 |\n| Base Image | Distroless/static (minimal attack surface) |\n| User | Non-root (security hardened) |\n\n## Environment Variables\n\nThe 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.\n\n### Authentication Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `ES_URL` | Yes | Elasticsearch cluster URL (e.g., `https://your-cluster.es.amazonaws.com:9200`) |\n| `ES_API_KEY` | Conditional | Elasticsearch API key for authentication (required if not using username/password) |\n| `ES_USERNAME` | Conditional | Username for basic authentication |\n| `ES_PASSWORD` | Conditional | Password for basic authentication |\n| `ES_SSL_SKIP_VERIFY` | No | Set to `true` to skip SSL/TLS certificate verification (not recommended for production) |\n\nSource: [src/lib.rs:setup_services()](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n### Network Variables\n\n| Variable | Description |\n|----------|-------------|\n| `HTTP_ADDRESS` | Socket address for HTTP server binding (format: `IP:PORT`) |\n| `CLI_ARGS` | Additional command-line arguments passed to the binary |\n\n## Running in Stdio Mode\n\nThe 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.\n\n### Basic Stdio Command\n\n```bash\ndocker run -i --rm \\\n  -e ES_URL=\"https://your-cluster.es.us-east-1.es.amazonaws.com:443\" \\\n  -e ES_API_KEY=\"your-api-key-here\" \\\n  docker.elastic.co/mcp/elasticsearch \\\n  stdio\n```\n\n### Claude Desktop Configuration\n\nTo integrate the MCP server with Claude Desktop, add the following configuration to your Claude Desktop settings file:\n\n```json\n{\n  \"mcpServers\": {\n    \"elasticsearch-mcp-server\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\", \"-i\", \"--rm\",\n        \"-e\", \"ES_URL\",\n        \"-e\", \"ES_API_KEY\",\n        \"docker.elastic.co/mcp/elasticsearch\",\n        \"stdio\"\n      ],\n      \"env\": {\n        \"ES_URL\": \"<elasticsearch-cluster-url>\",\n        \"ES_API_KEY\": \"<elasticsearch-api-key>\"\n      }\n    }\n  }\n}\n```\n\n## Running in HTTP Mode\n\nThe 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.\n\n### Basic HTTP Command\n\n```bash\ndocker run --rm \\\n  -e ES_URL=\"https://your-cluster.es.us-east-1.es.amazonaws.com:443\" \\\n  -e ES_API_KEY=\"your-api-key-here\" \\\n  -p 8080:8080 \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http\n```\n\n### HTTP Endpoints\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/mcp` | POST/GET | Streamable-HTTP MCP endpoint |\n| `/ping` | GET | Health check endpoint (returns `pong`) |\n\nSource: [src/lib.rs:run_http()](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n### HTTP-SSE Mode\n\nFor environments that require Server-Sent Events (SSE) for backwards compatibility, the HTTP server can be started with SSE support enabled:\n\n```bash\ndocker run --rm \\\n  -e ES_URL \\\n  -e ES_API_KEY \\\n  -p 8080:8080 \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --sse\n```\n\nNote that SSE is deprecated in favor of streamable-HTTP. The streamable-HTTP protocol provides better streaming support and should be preferred for new deployments.\n\n### HTTP Address Configuration\n\nBy 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:\n\n```bash\ndocker run --rm \\\n  -e ES_URL \\\n  -e ES_API_KEY \\\n  -p 0.0.0.0:8080:8080 \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --address 0.0.0.0:8080\n```\n\nThe server also respects the `HTTP_ADDRESS` environment variable for configuration.\n\n## Container Mode Host Resolution\n\nThe 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.\n\nThe following host aliases are checked in order:\n\n| Alias | Platform |\n|-------|----------|\n| `host.docker.internal` | Docker Desktop (Linux, macOS, Windows) |\n| `docker.for.host.internal` | Legacy Docker for macOS |\n| `host.containers.internal` | Podman and other container runtimes |\n\nSource: [src/servers/elasticsearch/mod.rs:container_mode()](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\nIf `localhost` is detected and no alias resolves successfully, the server logs a warning but continues operation:\n\n```rust\ntracing::warn!(\"Container mode: could not find a replacement for 'localhost'\");\n```\n\n## Configuration File\n\nFor 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.\n\n### Example Configuration File\n\n```json5\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n  }\n}\n```\n\n### Running with Configuration File\n\n```bash\ndocker run --rm \\\n  -v /path/to/config.json:/config.json:ro \\\n  -p 8080:8080 \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --config /config.json\n```\n\nThe configuration file supports environment variable interpolation using the `${VAR}` and `${VAR:default}` syntax.\n\n## Security Considerations\n\n### Credential Handling\n\nThe Elasticsearch MCP Server follows security best practices for credential management:\n\n- **API keys and passwords**: Stored only in environment variables passed to the container. They are never persisted to disk or included in logs.\n- **Environment variables**: Set when running the container. Use secret management services like AWS Secrets Manager or AWS Systems Manager Parameter Store in production environments.\n- **Non-root user**: The container runs as a non-root user for security hardening.\n\n### Network Security\n\n| Security Feature | Implementation |\n|-----------------|----------------|\n| TLS/SSL | Enabled automatically when `ES_URL` uses `https://` |\n| Certificate Validation | Enabled by default; disabled with `ES_SSL_SKIP_VERIFY=true` |\n| Localhost Binding | HTTP server binds to `127.0.0.1:8080` by default |\n| Port Exposure | Only required ports should be exposed to the network |\n\n### Best Practices\n\n- Rotate API keys regularly (every 30-90 days for production)\n- Use API keys with minimal required permissions\n- Never commit credentials to version control\n- Use secret management services for credential storage\n- Restrict network access to the container using firewall rules\n\n## Troubleshooting\n\n### Connection Issues\n\nIf the container fails to connect to Elasticsearch, verify the following:\n\n1. **Check container logs**: View logs using `docker logs <container-id>` to identify authentication or connection errors.\n\n2. **Test Elasticsearch connectivity**: From within the container:\n   ```bash\n   docker exec <container-id> curl -k -u <username>:<password> <ES_URL>\n   ```\n   Or with an API key:\n   ```bash\n   docker exec <container-id> curl -k -H \"Authorization: ApiKey <api-key>\" <ES_URL>\n   ```\n\n3. **Verify network access**: Ensure the container can reach the Elasticsearch cluster. For cloud deployments, check security groups and network ACLs.\n\n### Authentication Failures\n\nCommon authentication issues and solutions:\n\n| Issue | Solution |\n|-------|----------|\n| 401 Unauthorized | Verify `ES_USERNAME` and `ES_PASSWORD` are correct; check for typos in environment variable names |\n| API key rejected | Ensure the API key has sufficient permissions for the operations being performed |\n| Certificate errors | If using a self-signed certificate, set `ES_SSL_SKIP_VERIFY=true` (development only) |\n\n### Port Binding Issues\n\nIf port 8080 is already in use, either stop the conflicting service or use an alternative port:\n\n```bash\ndocker run --rm \\\n  -e ES_URL \\\n  -e ES_API_KEY \\\n  -p 8081:8080 \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --address 0.0.0.0:8080\n```\n\n### Health Check Verification\n\nVerify the server is running correctly by checking the health endpoint:\n\n```bash\ncurl http://localhost:8080/ping\n```\n\nA successful response returns `pong`, indicating the server is operational.\n\n## Building the Docker Image\n\nFor development or custom deployments, you can build the Docker image locally using the provided Makefile:\n\n```bash\nmake docker-build\n```\n\nThe Makefile targets include:\n\n| Target | Description |\n|--------|-------------|\n| `docker-build` | Build the default Docker image |\n| `docker-build-8000` | Build the image with port 8000 as default |\n| `docker-push` | Push the built image to the registry |\n\n## Limitations and Known Issues\n\nThe following limitations are relevant to Docker deployment:\n\n- **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](https://github.com/elastic/mcp-server-elasticsearch/issues/185).\n\n- **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.\n\n- **ARM64 support**: The project currently publishes Linux AMD64 binaries. ARM64 support is requested by the community (issue [#191](https://github.com/elastic/mcp-server-elasticsearch/issues/191)) but not yet available.\n\n---\n\n<a id='page-authentication'></a>\n\n## Authentication and Security\n\n### Related Pages\n\nRelated topics: [Docker Deployment](#page-deployment), [Troubleshooting Guide](#page-troubleshooting)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n</details>\n\n# Authentication and Security\n\nThe 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.\n\n## Overview\n\nThe MCP server handles authentication at two distinct layers:\n\n| Layer | Purpose | Source |\n|-------|---------|--------|\n| **Server Configuration** | Establishes baseline credentials for connecting to Elasticsearch | Environment variables or config file |\n| **Per-Request Auth** | Allows MCP clients to inject authentication for specific requests | HTTP `Authorization` header |\n\nThis 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.\n\n## Configuration Options\n\nThe `ElasticsearchMcpConfig` struct in `src/servers/elasticsearch/mod.rs` defines the supported authentication parameters:\n\n```rust\npub struct ElasticsearchMcpConfig {\n    /// Cluster URL\n    pub url: String,\n\n    /// API key\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub api_key: Option<String>,\n\n    /// Username\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub username: Option<String>,\n\n    /// Password\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub password: Option<String>,\n\n    /// Should we skip SSL certificate verification?\n    #[serde(default, deserialize_with = \"deserialize_bool_from_anything\")]\n    pub ssl_skip_verify: bool,\n}\n```\n\nSource: [src/servers/elasticsearch/mod.rs:98-120]()\n\n### Supported Authentication Methods\n\n| Method | Configuration | Priority |\n|--------|---------------|----------|\n| **API Key** | `ES_API_KEY` environment variable | Highest |\n| **Basic Authentication** | `ES_USERNAME` + `ES_PASSWORD` environment variables | Fallback |\n| **No Authentication** | Neither configured | When no credentials needed |\n\nThe credential resolution logic follows this precedence:\n\n```rust\nlet creds = if let Some(api_key) = config.api_key.clone() {\n    Some(Credentials::EncodedApiKey(api_key))\n} else if let Some(username) = config.username.clone() {\n    let pwd = config.password.clone().ok_or(anyhow::Error::msg(\"missing password\"))?;\n    Some(Credentials::Basic(username, pwd))\n} else {\n    None\n};\n```\n\nSource: [src/servers/elasticsearch/mod.rs:160-168]()\n\n### Environment Variable Mapping\n\n| Environment Variable | Config Field | Description |\n|---------------------|--------------|-------------|\n| `ES_URL` | `url` | Elasticsearch cluster endpoint |\n| `ES_API_KEY` | `api_key` | Base64-encoded API key |\n| `ES_USERNAME` | `username` | Username for basic auth |\n| `ES_PASSWORD` | `password` | Password for basic auth |\n| `ES_SSL_SKIP_VERIFY` | `ssl_skip_verify` | Disable TLS verification (not recommended) |\n\nThe configuration template demonstrates environment variable interpolation:\n\n```json\n{\n    \"elasticsearch\": {\n        \"url\": \"${ES_URL}\",\n        \"api_key\": \"${ES_API_KEY:}\",\n        \"username\": \"${ES_USERNAME:}\",\n        \"password\": \"${ES_PASSWORD:}\",\n        \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n    }\n}\n```\n\nSource: [src/lib.rs:56-66]()\n\n## Per-Request Authentication\n\nThe `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.\n\n```rust\npub fn get(&self, context: RequestContext<RoleServer>) -> Cow<'_, Elasticsearch> {\n    let client = &self.0;\n\n    let Some(mut auth) = context\n        .extensions\n        .get::<Parts>()\n        .and_then(|p| p.headers.get(header::AUTHORIZATION))\n        .and_then(|h| h.to_str().ok())\n    else {\n        // No auth\n        return Cow::Borrowed(client);\n    };\n\n    // MCP inspector insists on sending a bearer token and prepends \"Bearer\" to the value provided\n    if auth.starts_with(\"Bearer ApiKey \") || auth.starts_with(\"Bearer Basic \") {\n        auth = auth.trim_start_matches(\"Bearer \");\n    }\n\n    let transport = client\n        .transport()\n        .clone_with_auth(Some(Credentials::AuthorizationHeader(auth.to_string())));\n\n    Cow::Owned(Elasticsearch::new(transport))\n}\n```\n\nSource: [src/servers/elasticsearch/mod.rs:126-151]()\n\n### Authorization Header Handling\n\nThe server intelligently processes the `Authorization` header by:\n\n1. Extracting the header value from the incoming HTTP request\n2. Stripping `Bearer ` prefixes that some MCP clients (like the MCP Inspector) automatically prepend\n3. Creating a new Elasticsearch client transport with the extracted credentials\n4. Returning an owned `Cow<Elasticsearch>` to ensure the per-request client is used\n\n### Supported Per-Request Formats\n\n| Format | Example Header | Notes |\n|--------|---------------|-------|\n| `ApiKey <key>` | `Authorization: ApiKey VGhpcyBpcyBhbiBhcGkga2V5...` | Direct API key |\n| `Basic <credentials>` | `Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=` | Base64-encoded username:password |\n| `Bearer ApiKey <key>` | `Authorization: Bearer ApiKey VGhpcyBpcyBhbiBhcGkga2V5...` | MCP Inspector format for API key |\n| `Bearer Basic <credentials>` | `Authorization: Bearer Basic dXNlcm5hbWU6cGFzc3dvcmQ=` | MCP Inspector format for basic auth |\n\n## Deployment Modes and Authentication\n\nThe MCP server supports multiple transport modes that interact differently with authentication:\n\n### Stdio Mode\n\nIn 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.\n\n```rust\n#[derive(Debug, Subcommand)]\npub enum Command {\n    Stdio(StdioCommand),\n    Http(HttpCommand),\n}\n\n#[derive(Debug, Args)]\npub struct StdioCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n}\n```\n\nSource: [src/cli.rs:42-52]()\n\n### HTTP/SSE Mode\n\nIn 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.\n\n```rust\n#[derive(Debug, Args)]\npub struct HttpCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n\n    /// Address to listen to [default: 127.0.0.1:8080]\n    #[clap(long, value_name = \"IP_ADDRESS:PORT\", env = \"HTTP_ADDRESS\")]\n    pub address: Option<std::net::SocketAddr>,\n\n    /// Also start an SSE server on '/sse'\n    #[clap(long)]\n    pub sse: bool,\n}\n```\n\nSource: [src/cli.rs:30-41]()\n\n## Authentication Flow Diagram\n\n```mermaid\nsequenceDiagram\n    participant Client as MCP Client\n    participant MCP as MCP Server\n    participant ES as Elasticsearch\n\n    Note over MCP: Configuration Load\n    MCP->>MCP: Read ES_URL, ES_API_KEY/ES_USERNAME/ES_PASSWORD\n    MCP->>MCP: Create base Elasticsearch client\n\n    Note over Client,MCP: Per-Request Auth (HTTP mode only)\n    Client->>MCP: HTTP Request + Authorization header\n    MCP->>MCP: Extract Authorization header\n    \n    alt Authorization header present\n        MCP->>MCP: Clone transport with new credentials\n        MCP->>ES: Request with per-request auth\n    else No Authorization header\n        MCP->>ES: Request with base client auth\n    end\n    \n    ES-->>MCP: Response\n    MCP-->>Client: MCP Response\n```\n\n## SSL/TLS Configuration\n\n### Certificate Verification\n\nBy default, the server validates SSL/TLS certificates when connecting to Elasticsearch. To disable verification (not recommended for production):\n\n```bash\nES_SSL_SKIP_VERIFY=true\n```\n\nThis sets `ssl_skip_verify: true` in the configuration, which is passed to the Elasticsearch HTTP transport.\n\n### Container Mode URL Rewriting\n\nWhen running inside a container, localhost connections may need URL rewriting to reach the host machine:\n\n```rust\nif container_mode {\n    rewrite_localhost(&mut url)?;\n}\n```\n\nThis ensures that `http://localhost:9200` in a container context resolves to the actual host machine's Elasticsearch instance.\n\n## Common Issues and Troubleshooting\n\n### Issue: Basic Auth Failed - 401 Unauthorized\n\nA frequently reported issue (#170) involves authentication failures even when credentials are correctly configured:\n\n**Symptoms:**\n- Server logs show `401 Unauthorized`\n- Environment variables `ES_USERNAME`, `ES_PASSWORD` are confirmed correct inside the container\n\n**Potential Causes:**\n\n| Cause | Solution |\n|-------|----------|\n| Conflicting env var names | Use `ES_USERNAME` and `ES_PASSWORD` (v0.4.5 updated env name) |\n| Empty password string | Ensure `ES_PASSWORD` is not empty; use quotes if special characters present |\n| API key takes precedence | If `ES_API_KEY` is set, it overrides username/password |\n\n**Diagnostic Steps:**\n\n1. Verify all environment variables are correctly set\n2. Test connectivity directly to Elasticsearch with the same credentials\n3. For HTTP mode, check if a proxy is stripping or modifying the Authorization header\n\n### MCP Inspector Compatibility\n\nThe MCP Inspector prepends `Bearer ` to authentication values. The server handles this by stripping the prefix:\n\n```rust\nif auth.starts_with(\"Bearer ApiKey \") || auth.starts_with(\"Bearer Basic \") {\n    auth = auth.trim_start_matches(\"Bearer \");\n}\n```\n\nThis ensures compatibility with tools that follow the OAuth2 bearer token convention.\n\n## Security Best Practices\n\n| Practice | Recommendation |\n|----------|----------------|\n| **Credential Storage** | Use secrets management systems (AWS Secrets Manager, HashiCorp Vault) rather than plain environment variables |\n| **SSL Verification** | Keep `ES_SSL_SKIP_VERIFY=false` in production; only disable for local development |\n| **API Keys** | Prefer API keys over username/password for machine-to-machine authentication |\n| **Network Exposure** | Bind HTTP server to localhost (`127.0.0.1`) when possible; restrict network access |\n| **Proxy Authentication** | When using a reverse proxy, ensure it properly forwards or handles the Authorization header |\n\n## Related Documentation\n\n- [Model Context Protocol Authentication](https://modelcontextprotocol.io/docs/concepts/transports)\n- [Elasticsearch API Keys](https://www.elastic.co/docs/deploy-manage/api-keys)\n- [Elasticsearch User Management](https://www.elastic.co/docs/deploy-manage/users-roles)\n- [Docker Deployment Guide](#) - For container-specific authentication configuration\n\n---\n\n<a id='page-configuration-reference'></a>\n\n## Configuration Reference\n\n### Related Pages\n\nRelated topics: [Docker Deployment](#page-deployment), [Authentication and Security](#page-authentication)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)\n- [.env-example](https://github.com/elastic/mcp-server-elasticsearch/blob/main/.env-example)\n</details>\n\n# Configuration Reference\n\nThe Elasticsearch MCP Server supports flexible configuration through configuration files and environment variables. This reference documents all available configuration options, their purposes, and usage patterns.\n\n## Overview\n\nThe server configuration defines how the MCP server connects to Elasticsearch and which tools and features to expose. Configuration can be provided through:\n\n1. **Configuration file** (JSON or JSON5 format) specified via CLI\n2. **Environment variables** for containerized deployments\n3. **Default values** built into the binary\n\nSource: [src/lib.rs:66-85](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs#L66-L85)\n\n## Configuration File Structure\n\nThe configuration file uses JSON5 format, which extends JSON with support for comments and trailing commas. This allows for human-readable configuration with documentation.\n\n```json5\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\",\n    \"tools\": {\n      \"custom\": {\n        // Custom tools configuration\n      }\n    },\n    \"prompts\": []\n  }\n}\n```\n\nSource: [src/lib.rs:66-79](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs#L66-L79)\n\n## Elasticsearch Configuration Options\n\nThe `ElasticsearchMcpConfig` struct defines all connection and behavior settings:\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `url` | String | *(required)* | Elasticsearch cluster URL (e.g., `https://localhost:9200`) |\n| `api_key` | Option<String> | `None` | API key for authentication |\n| `username` | Option<String> | `None` | Username for basic authentication |\n| `password` | Option<String> | `None` | Password for basic authentication |\n| `ssl_skip_verify` | bool | `false` | Skip SSL certificate verification (not recommended for production) |\n| `tools` | Tools | `{}` | Custom tools configuration (ESQL, search templates) |\n| `prompts` | Vec<String> | `[]` | List of prompt identifiers to expose |\n\nSource: [src/servers/elasticsearch/mod.rs:101-129](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L101-L129)\n\n## Environment Variable Interpolation\n\nThe configuration system supports environment variable interpolation using `${VAR}` or `${VAR:default}` syntax. This enables containerized deployments and integration with orchestration systems.\n\n### Syntax\n\n| Pattern | Behavior |\n|---------|----------|\n| `${VAR}` | Required variable - server fails if not set |\n| `${VAR:default}` | Optional variable with default value |\n\n### Example Usage\n\n```bash\n# With all environment variables\nES_URL=https://elasticsearch:9200 \\\nES_API_KEY=my-api-key \\\n./elastic-mcp stdio --config config.json5\n\n# Using defaults (empty strings for optional vars)\nES_URL=https://elasticsearch:9200 \\\n./elastic-mcp stdio\n```\n\nThe interpolator replaces `${VAR}` patterns with actual environment variable values before JSON parsing occurs.\n\nSource: [src/utils/interpolator.rs:1-50](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs#L1-L50)\n\n```mermaid\ngraph TD\n    A[Config File or Built-in Defaults] --> B[Environment Variable Interpolation]\n    B --> C[JSON5 Parsing]\n    C --> D[serde_json5 Deserialization]\n    D --> E[ElasticsearchMcpConfig]\n    E --> F[Server Initialization]\n    \n    G[Environment Variables] -.->|${VAR} replacement| B\n```\n\n## Authentication Configuration\n\nThe server supports multiple authentication methods. Only one should be configured per deployment.\n\n### API Key Authentication\n\n```json5\n{\n  \"elasticsearch\": {\n    \"url\": \"https://elasticsearch:9200\",\n    \"api_key\": \"${ES_API_KEY}\"\n  }\n}\n```\n\n### Username/Password Authentication\n\n```json5\n{\n  \"elasticsearch\": {\n    \"url\": \"https://elasticsearch:9200\",\n    \"username\": \"${ES_USERNAME}\",\n    \"password\": \"${ES_PASSWORD}\"\n  }\n}\n```\n\n### Authentication Priority\n\nWhen multiple authentication methods are specified:\n\n1. `api_key` takes precedence over `username`/`password`\n2. Both `username` and `password` must be present for basic auth\n\nSource: [src/servers/elasticsearch/mod.rs:70-81](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L70-L81)\n\n## CLI Configuration\n\n### Stdio Mode\n\nRun the server in stdio mode for local integration with MCP clients:\n\n```bash\nelastic-mcp stdio [OPTIONS]\n```\n\n| Option | Description |\n|--------|-------------|\n| `-c, --config <PATH>` | Path to configuration file |\n\nSource: [src/cli.rs:38-45](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs#L38-L45)\n\n### HTTP Mode\n\nRun the server as an HTTP server for remote access:\n\n```bash\nelastic-mcp http [OPTIONS]\n```\n\n| Option | Environment Variable | Default | Description |\n|--------|---------------------|---------|-------------|\n| `-c, --config <PATH>` | - | `None` | Path to configuration file |\n| `--address <ADDR>` | `HTTP_ADDRESS` | `127.0.0.1:8080` | Listen address |\n| `--sse` | - | `false` | Enable SSE endpoint at `/mcp/sse` |\n\nSource: [src/cli.rs:26-37](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs#L26-L37)\n\n### Address Binding Behavior\n\nThe server binds to different addresses based on execution mode:\n\n| Mode | Default Address | Description |\n|------|-----------------|--------------|\n| Stdio | N/A | No network binding required |\n| HTTP | `127.0.0.1:8080` | Localhost only for security |\n| HTTP (container) | `0.0.0.0:8080` | All interfaces for container networking |\n\nSource: [src/lib.rs:90-99](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs#L90-L99)\n\n## Container Mode\n\nWhen 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.\n\n### Supported Host Aliases\n\nContainer mode rewrites `localhost` to one of these addresses (in order of priority):\n\n| Platform | Host Alias |\n|----------|------------|\n| Docker Desktop | `host.docker.internal` |\n| Podman | `host.containers.internal` |\n| Kubernetes | `host.containers.internal` |\n\nSource: [src/servers/elasticsearch/mod.rs:158-175](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L158-L175)\n\n```mermaid\ngraph TD\n    A[Container Mode Enabled] --> B{URL host = localhost?}\n    B -->|Yes| C[Resolve alias addresses]\n    B -->|No| E[Use URL as-is]\n    C --> D[Rewrite to resolved address]\n    D --> E\n    E --> F[Create ES Client]\n    \n    F --> G[host.docker.internal]\n    F --> H[host.containers.internal]\n```\n\n## Custom Tools Configuration\n\nThe `Tools` struct allows exposing custom ES|QL queries and search templates as MCP tools:\n\n```json5\n{\n  \"elasticsearch\": {\n    \"url\": \"https://elasticsearch:9200\",\n    \"tools\": {\n      \"custom\": {\n        \"esql_query\": {\n          \"type\": \"esql\",\n          \"description\": \"Execute ES|QL query\",\n          \"parameters\": { /* JSON Schema */ },\n          \"query\": \"FROM my-index | LIMIT 10\"\n        },\n        \"search_template\": {\n          \"type\": \"search_template\",\n          \"description\": \"Execute search template\",\n          \"template\": {\n            \"id\": \"my-template\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n### ES|QL Tool Configuration\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `type` | String | Must be `\"esql\"` |\n| `description` | String | Human-readable tool description |\n| `parameters` | SchemaObject | JSON Schema for parameters |\n| `query` | String | ES|QL query to execute |\n| `format` | String | Output format: `json` (default) or `value` |\n\nSource: [src/servers/elasticsearch/mod.rs:35-68](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L35-L68)\n\n## Complete Configuration Example\n\n```json5\n{\n  \"elasticsearch\": {\n    // Connection settings\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\",\n    \n    // Custom tools\n    \"tools\": {\n      \"custom\": {\n        \"log_analysis\": {\n          \"type\": \"esql\",\n          \"description\": \"Analyze recent error logs\",\n          \"query\": \"FROM logs-* | WHERE level == 'ERROR' | LIMIT 100\"\n        }\n      }\n    },\n    \n    // Prompts to expose\n    \"prompts\": []\n  }\n}\n```\n\n## Environment Variable Reference\n\n| Variable | Required | Description |\n|----------|----------|--------------|\n| `ES_URL` | Yes | Elasticsearch cluster URL |\n| `ES_API_KEY` | No* | API key for authentication |\n| `ES_USERNAME` | No* | Username for basic auth |\n| `ES_PASSWORD` | No* | Password for basic auth |\n| `ES_SSL_SKIP_VERIFY` | No | Set to `true` to skip SSL verification |\n| `CLI_ARGS` | No | Alternative to CLI arguments |\n| `HTTP_ADDRESS` | No | HTTP server listen address |\n\n*Either `ES_API_KEY` or both `ES_USERNAME` and `ES_PASSWORD` should be set.\n\nSource: [.env-example](https://github.com/elastic/mcp-server-elasticsearch/blob/main/.env-example)\n\n## Known Configuration Issues\n\n### Basic Auth 401 Unauthorized\n\nIf using basic authentication fails with 401 errors, verify that:\n1. Both `ES_USERNAME` and `ES_PASSWORD` are set\n2. The Elasticsearch user has sufficient permissions\n3. The credentials are correctly passed to the container\n\n### Container Mode URL Resolution\n\nContainer mode requires the host alias to be resolvable. If you see warnings about failing to rewrite `localhost`, ensure:\n- Docker Desktop is running (for `host.docker.internal`)\n- Podman socket is active (for `host.containers.internal`)\n\nSource: [src/servers/elasticsearch/mod.rs:169-170](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L169-L170)\n\n## Configuration Schema\n\nThe complete JSON Schema for validation:\n\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"type\": \"object\",\n  \"required\": [\"elasticsearch\"],\n  \"properties\": {\n    \"elasticsearch\": {\n      \"type\": \"object\",\n      \"required\": [\"url\"],\n      \"properties\": {\n        \"url\": { \"type\": \"string\", \"format\": \"uri\" },\n        \"api_key\": { \"type\": [\"string\", \"null\"] },\n        \"username\": { \"type\": [\"string\", \"null\"] },\n        \"password\": { \"type\": [\"string\", \"null\"] },\n        \"ssl_skip_verify\": { \"type\": \"boolean\" },\n        \"tools\": { \"$ref\": \"#/definitions/Tools\" },\n        \"prompts\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } }\n      }\n    }\n  }\n}\n```\n\nSource: [src/servers/elasticsearch/mod.rs:101-129](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L101-L129)\n\n---\n\n<a id='page-troubleshooting'></a>\n\n## Troubleshooting Guide\n\n### Related Pages\n\nRelated topics: [Authentication and Security](#page-authentication), [Monitoring and Health Checks](#page-monitoring), [Available MCP Tools](#page-available-tools)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)\n</details>\n\n# Troubleshooting Guide\n\nThis guide covers common issues encountered when deploying and using the Elasticsearch MCP Server, with solutions based on the codebase and reported community issues.\n\n## Authentication Failures\n\n### 401 Unauthorized with Basic Auth\n\nUsers deploying via Docker have reported authentication failures even when credentials appear correct.\n\n**Common Causes:**\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| Environment variable name | `ES_lOGIN` is a typo; use `ES_USERNAME` | Use `ES_USERNAME` and `ES_PASSWORD` correctly |\n| Missing password | Username provided without password | Always provide `ES_PASSWORD` when `ES_USERNAME` is set |\n| Container env setup | Variables not properly passed to container | Verify `-e` flags in docker run command |\n\n**Source:** The server validates credentials in `src/servers/elasticsearch/mod.rs:47-54`:\n\n```rust\nlet creds = if let Some(api_key) = config.api_key.clone() {\n    Some(Credentials::EncodedApiKey(api_key))\n} else if let Some(username) = config.username.clone() {\n    let pwd = config.password.clone().ok_or(anyhow::Error::msg(\"missing password\"))?;\n    Some(Credentials::Basic(username, pwd))\n} else {\n    None\n};\n```\n\n**Verification Steps:**\n\n1. Enter the container and confirm environment variables:\n   ```bash\n   docker exec -it <container_name> env | grep ES_\n   ```\n\n2. Verify the correct variable names are used:\n   - `ES_URL` - Elasticsearch cluster URL\n   - `ES_USERNAME` - Username (NOT `ES_lOGIN`)\n   - `ES_PASSWORD` - Password\n   - `ES_API_KEY` - API key (alternative to username/password)\n\n3. Test authentication directly against Elasticsearch using the same credentials.\n\n### API Key Authentication\n\nWhen using API key authentication, ensure the key is properly formatted and has sufficient permissions.\n\n**Configuration:**\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY:}\"\n  }\n}\n```\n\nThe server will use `api_key` if provided, falling back to username/password authentication. Source: `src/servers/elasticsearch/mod.rs:47`\n\n## Configuration Issues\n\n### Empty Elasticsearch URL\n\nThe server fails to start with an empty `ES_URL`:\n\n```\nError: \"Elasticsearch URL is empty\"\n```\n\n**Source:** `src/servers/elasticsearch/mod.rs:53-55`:\n\n```rust\nlet url = config.url.as_str();\nif url.is_empty() {\n    return Err(anyhow::Error::msg(\"Elasticsearch URL is empty\"));\n}\n```\n\n**Solution:** Ensure `ES_URL` is set to a valid Elasticsearch endpoint (e.g., `https://localhost:9200`).\n\n### SSL Certificate Verification Failures\n\nFor development or testing with self-signed certificates:\n\n**Configuration option:**\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n  }\n}\n```\n\nSet `ES_SSL_SKIP_VERIFY=true` to skip SSL verification. Source: `src/servers/elasticsearch/mod.rs:33-34`\n\n### Environment Variable Interpolation\n\nThe server supports `${VAR_NAME:default_value}` syntax in configuration files.\n\n**Source:** `src/utils/interpolator.rs:17-38`:\n\n```rust\nif line.starts_with(\"${\") {\n    if let Some(end) = line.find(\"$}\") {\n        let expr = &line[2..end];\n        let value = if let Some((name, default)) = expr.split_once(':') {\n            lookup(name).unwrap_or(default.to_string())\n        } else {\n            lookup(expr).ok_or_else(|| err(...))?\n        };\n        result.push_str(&value);\n    }\n}\n```\n\n**Example:**\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL:http://localhost:9200}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n  }\n}\n```\n\n### Config File Parsing Errors\n\nConfiguration files support JSON5 (JSON with comments and trailing commas).\n\n**Error format for parsing failures:**\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"http://localhost:9200\"\n    // Missing comma above causes parsing error\n  }\n}\n```\n\n**Source:** `src/lib.rs:58-63`:\n\n```rust\nlet config: Configuration = match serde_json5::from_str(&config) {\n    Ok(c) => c,\n    Err(serde_json5::Error::Message { msg, location }) if location.is_some() => {\n        let location = location.unwrap();\n        anyhow::bail!(\"Failed to parse config: {msg}, at line {line} column {column}\");\n    }\n    Err(err) => return Err(err)?,\n};\n```\n\n## Tool-Specific Issues\n\n### get_mappings Decoding Error\n\n**Issue:** `get_mappings` tool fails with \"error decoding response body\" when index mappings contain nested properties defined without explicit `\"type\": \"nested\"`.\n\nThis is a known limitation when Elasticsearch returns mappings that are technically valid but contain implicit nested type declarations.\n\n**Source:** The tool uses `read_json` to parse responses in `src/servers/elasticsearch/base_tools.rs:140-150`:\n\n```rust\nasync fn get_mappings(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(GetMappingsParams { index }): Parameters<GetMappingsParams>,\n) -> Result<CallToolResult, rmcp::Error> {\n    let es_client = self.es_client.get(req_ctx);\n    let response = es_client.indices().get_mapping(GetMappingParts::Index(&[&index])).send().await;\n    let mapping: GetMappingResponse = read_json(response).await?;\n}\n```\n\n**Workaround:** Ensure your Elasticsearch index mappings explicitly define the `type` property for nested fields:\n\n```json\n{\n  \"mappings\": {\n    \"properties\": {\n      \"nested_field\": {\n        \"type\": \"nested\"\n      }\n    }\n  }\n}\n```\n\n### search Tool Aggregation Results\n\nThe search tool returns aggregation results alongside hits:\n\n**Source:** `src/servers/elasticsearch/base_tools.rs:153-177`:\n\n```rust\nlet response: SearchResult = read_json(response).await?;\nlet mut results: Vec<Content> = Vec::new();\n\n// Send result stats only if it's not pure aggregation results\nif response.aggregations.is_empty() || !response.hits.hits.is_empty() {\n    let total = response.hits.total.map(|t| t.value).unwrap_or(0);\n    results.push(Content::text(format!(\"Found {} hits:\", total)));\n}\n\n// Include aggregations if present\nif !response.aggregations.is_empty() {\n    results.push(Content::text(\"Aggregations:\"));\n    results.push(Content::json(response.aggregations)?);\n}\n```\n\n### ES|QL Query Response Format\n\nES|QL queries transform columnar results into object format:\n\n**Source:** `src/servers/elasticsearch/base_tools.rs:186-203`:\n\n```rust\nlet response: EsqlQueryResponse = read_json(response).await?;\n\n// Transform response into an array of objects\nlet mut objects: Vec<Value> = Vec::new();\nfor row in response.values.into_iter() {\n    let mut obj = Map::new();\n    for (i, value) in row.into_iter().enumerate() {\n        obj.insert(response.columns[i].name.clone(), value);\n    }\n    objects.push(Value::Object(obj));\n}\n```\n\n## Deployment Issues\n\n### Docker Container Mode\n\nWhen running in Docker, the server rewrites `localhost` references to enable container-to-container communication.\n\n**Source:** `src/servers/elasticsearch/mod.rs:57`:\n\n```rust\nif container_mode {\n    rewrite_localhost(&mut url)?;\n}\n```\n\n**Default Ports:**\n\n| Mode | Default Address | Environment Variable |\n|------|-----------------|----------------------|\n| Docker (HTTP) | `0.0.0.0:8080` | `HTTP_ADDRESS` |\n| Local (HTTP) | `127.0.0.1:8080` | `HTTP_ADDRESS` |\n| Stdio | N/A | N/A |\n\n**Source:** `src/lib.rs:47-53`:\n\n```rust\nlet address: SocketAddr = if let Some(addr) = cmd.address {\n    addr\n} else if container_mode {\n    SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 8080)\n} else {\n    SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080)\n};\n```\n\n### HTTP Transport Endpoints\n\nWhen running in HTTP mode:\n\n| Endpoint | Purpose |\n|----------|---------|\n| `/mcp` | Streamable-HTTP MCP endpoint |\n| `/ping` | Health check endpoint |\n\n**Source:** `src/cli.rs:37-45`:\n\n```rust\npub struct HttpCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n\n    /// Address to listen to [default: 127.0.0.1:8080]\n    #[clap(long, value_name = \"IP_ADDRESS:PORT\", env = \"HTTP_ADDRESS\")]\n    pub address: Option<std::net::SocketAddr>,\n\n    /// Also start an SSE server on '/sse'\n    #[clap(long)]\n    pub sse: bool,\n}\n```\n\n### Common Docker Deployment Errors\n\n**Container exits immediately:**\n\n1. Check logs: `docker logs <container_name>`\n2. Verify environment variables are set\n3. Ensure Elasticsearch URL is accessible from container\n\n**Port already in use:**\n\n```bash\n# Check what's using port 8080\nlsof -i :8080\n# Use different port\ndocker run -p 8081:8080 ...\n```\n\n## Error Handling Reference\n\n### Server Error Responses\n\nThe server uses the `rmcp::Error` type for MCP protocol errors:\n\n**Source:** `src/servers/elasticsearch/mod.rs:66-74`:\n\n```rust\npub fn handle_error(result: Result<Response, elasticsearch::Error>) -> Result<Response, rmcp::Error> {\n    match result {\n        Ok(resp) => resp.error_for_status_code(),\n        Err(e) => {\n            tracing::error!(\"Error: {:?}\", &e);\n            Err(e)\n        }\n    }\n    .map_err(internal_error)\n}\n```\n\n### Common Error Messages\n\n| Error | Cause | Resolution |\n|-------|-------|------------|\n| `error decoding response body` | Invalid JSON in ES response | Check ES version compatibility; verify index mappings |\n| `Request failed (remote)` | ES cluster unreachable | Verify ES_URL; check network/firewall |\n| `missing password` | Username set without password | Provide ES_PASSWORD or use API key auth |\n| `Elasticsearch URL is empty` | ES_URL not set | Set ES_URL environment variable |\n\n## Diagnostic Checklist\n\nWhen troubleshooting, verify:\n\n- [ ] `ES_URL` is set and points to a reachable Elasticsearch cluster\n- [ ] Authentication credentials (API key or username/password) are correct\n- [ ] If using Basic auth, both `ES_USERNAME` and `ES_PASSWORD` are set (not `ES_lOGIN`)\n- [ ] SSL certificate issues: set `ES_SSL_SKIP_VERIFY=true` for self-signed certs\n- [ ] Docker networking allows container to reach Elasticsearch\n- [ ] Index name is correct (use `list_indices` tool to verify)\n- [ ] User has necessary Elasticsearch permissions for the requested operations\n\n## Getting Help\n\nFor additional support:\n\n1. Search [existing GitHub issues](https://github.com/elastic/mcp-server-elasticsearch/issues)\n2. Check the [Dependency Dashboard](https://github.com/elastic/mcp-server-elasticsearch/issues/6) for known dependency-related issues\n3. Enable debug logging by setting `RUST_LOG=debug` when running the server\n\n---\n\n<a id='page-monitoring'></a>\n\n## Monitoring and Health Checks\n\n### Related Pages\n\nRelated topics: [Troubleshooting Guide](#page-troubleshooting), [Docker Deployment](#page-deployment)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/bin/start_http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/bin/start_http.rs)\n- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n</details>\n\n# Monitoring and Health Checks\n\nThe 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.\n\n## Health Check Endpoints\n\nWhen 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.\n\n### Available Endpoints\n\n| Endpoint | Path | Method | Purpose |\n|----------|------|--------|---------|\n| Readiness | `/_health/ready` | GET | Indicates server can accept requests |\n| Liveness | `/_health/live` | GET | Indicates server process is alive |\n| Ping | `/ping` | GET | Basic connectivity verification |\n| Hello | `/` | GET | Server version and endpoint info |\n\n### Readiness Probe\n\nThe readiness endpoint signals when the server is fully initialized and ready to process MCP requests:\n\n```http\nGET /_health/ready HTTP/1.1\n```\n\n**Response:**\n```\nHTTP/1.1 200 OK\nReady\n```\n\nThe server becomes ready once the tool list is loaded and the Elasticsearch client is initialized. Source: [src/protocol/http.rs:1-50](src/protocol/http.rs)\n\n### Liveness Probe\n\nThe liveness endpoint confirms the server process is running:\n\n```http\nGET /_health/live HTTP/1.1\n```\n\n**Response:**\n```\nHTTP/1.1 200 OK\nAlive\n```\n\nThis endpoint returns immediately without checking Elasticsearch connectivity, making it suitable for detecting crashed processes. Source: [src/protocol/http.rs:1-50](src/protocol/http.rs)\n\n### Ping Endpoint\n\nThe ping endpoint provides a quick health verification:\n\n```http\nGET /ping HTTP/1.1\n```\n\n**Response:**\n```\nHTTP/1.1 200 OK\nReady\n```\n\nA successful `pong` response indicates the server is running and healthy. Source: [README.md](README.md)\n\n## Monitoring Tools\n\nThe 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.\n\n### Tool Reference\n\n| Tool | Purpose | Read-Only |\n|------|---------|-----------|\n| `list_indices` | List available Elasticsearch indices | Yes |\n| `get_shards` | Retrieve shard allocation information | Yes |\n| `get_mappings` | Fetch index field mappings | Yes |\n| `search` | Execute search queries | Yes |\n| `esql` | Run ES|QL queries | Yes |\n\n### Shard Monitoring\n\nThe `get_shards` tool provides detailed shard distribution information across the cluster:\n\n```json\n{\n  \"name\": \"get_shards\",\n  \"arguments\": {\n    \"index\": \"optional-index-name\"\n  }\n}\n```\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `index` | String | No | Specific index name; omit for all indices |\n\n**Response Fields:**\n\n| Field | Description |\n|-------|-------------|\n| `index` | Index name |\n| `shard` | Shard number |\n| `prirep` | Primary (P) or replica (R) |\n| `state` | Shard state (STARTED, INITIALIZING, etc.) |\n| `docs` | Document count |\n| `store` | Store size |\n| `node` | Node name housing the shard |\n\nThis tool was introduced in v0.2.0 for cluster monitoring purposes. Source: [src/servers/elasticsearch/base_tools.rs:1-50](src/servers/elasticsearch/base_tools.rs)\n\n### Index Listing\n\nThe `list_indices` tool enumerates all indices accessible to the authenticated user:\n\n```json\n{\n  \"name\": \"list_indices\",\n  \"arguments\": {\n    \"index_pattern\": \"*\"\n  }\n}\n```\n\n**Response Structure:**\n\n```json\n[\n  {\n    \"index\": \"index-name\",\n    \"status\": \"open\",\n    \"doc_count\": 12345\n  }\n]\n```\n\n### Mappings Retrieval\n\nThe `get_mappings` tool retrieves field mappings for index analysis:\n\n```json\n{\n  \"name\": \"get_mappings\",\n  \"arguments\": {\n    \"index\": \"my-index\"\n  }\n}\n```\n\n**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](https://github.com/elastic/mcp-server-elasticsearch/issues/185)\n\n## Architecture\n\n### Health Check Request Flow\n\n```mermaid\ngraph TD\n    A[External Monitor] -->|HTTP GET| B[Main Router]\n    B -->|Route| C[Health Router]\n    C -->|/ready| D[Readiness Check]\n    C -->|/live| E[Liveness Check]\n    C -->|/ping| F[Basic Ping]\n    \n    D -->|Initialize| G[Tool List Loaded]\n    G -->|ES Client Ready| H[200 OK]\n    \n    E --> I[Process Alive]\n    I --> J[200 OK]\n    \n    F --> K[Server Responding]\n    K --> L[pong]\n```\n\n### HTTP Server Structure\n\nThe HTTP server is built using the Axum framework with a layered router configuration:\n\n```mermaid\ngraph TD\n    A[TCP Listener] --> B[Graceful Shutdown Handler]\n    B --> C[Main Router]\n    \n    C -->|/| D[Hello Endpoint]\n    C -->|/ping| E[Ping Endpoint]\n    C -->|/mcp| F[MCP Handler]\n    C -->|/mcp/sse| G[SSE Handler]\n    C -->|/_health| H[Health Router]\n    \n    H -->|/ready| I[Readiness Probe]\n    H -->|/live| J[Liveness Probe]\n```\n\nSource: [src/protocol/http.rs:1-50](src/protocol/http.rs)\n\n## Troubleshooting\n\n### Common Issues\n\n#### Authentication Failures\n\n**Symptom:** 401 Unauthorized errors when the server attempts to connect to Elasticsearch.\n\n**Diagnostic Steps:**\n\n1. Verify environment variables inside the container:\n   ```bash\n   docker exec <container-id> env | grep ES_\n   ```\n\n2. Confirm credentials are correctly set:\n   - `ES_API_KEY` for API key authentication\n   - `ES_USERNAME` and `ES_PASSWORD` for basic auth\n\n3. Test connectivity directly from the container:\n   ```bash\n   # Basic auth\n   docker exec <container-id> curl -k -u <username>:<password> <ES_URL>\n   \n   # API key\n   docker exec <container-id> curl -k -H \"Authorization: ApiKey <api-key>\" <ES_URL>\n   ```\n\nSource: [README.md](README.md)\n\n#### Container Logs Analysis\n\nView logs to identify connection or authentication issues:\n\n```bash\ndocker logs <container-id>\n```\n\nLook for these error patterns:\n\n| Error Pattern | Likely Cause |\n|---------------|--------------|\n| `Connection refused` | Elasticsearch URL incorrect or ES not running |\n| `401 Unauthorized` | Invalid credentials |\n| `certificate verify failed` | SSL verification issue |\n\n#### Elasticsearch Connectivity Verification\n\nFrom within the container, verify network connectivity:\n\n```bash\ndocker exec <container-id> curl -k -u <username>:<password> <ES_URL>/_cluster/health\n```\n\nA successful response with cluster health JSON confirms the container can reach Elasticsearch.\n\n### Health Check Configuration\n\nThe default bind address is `127.0.0.1:8080`, configurable via:\n\n| Option | Environment Variable | CLI Flag |\n|--------|---------------------|----------|\n| Bind address | `HTTP_ADDRESS` | `--address` |\n\nExample configuration:\n```bash\n# Environment variable\nHTTP_ADDRESS=0.0.0.0:8080\n\n# CLI argument\n--address 0.0.0.0:8080\n```\n\nSource: [src/cli.rs](src/cli.rs)\n\n## Best Practices\n\n### Kubernetes Probes\n\nConfigure Kubernetes probes to use the health check endpoints:\n\n```yaml\nlivenessProbe:\n  httpGet:\n    path: /_health/live\n    port: 8080\n  initialDelaySeconds: 5\n  periodSeconds: 10\n\nreadinessProbe:\n  httpGet:\n    path: /_health/ready\n    port: 8080\n  initialDelaySeconds: 5\n  periodSeconds: 5\n```\n\n### Monitoring Integration\n\n- Use `/ping` for load balancer health checks\n- Use `/_health/ready` for orchestration readiness signals\n- Use `/_health/live` for process liveness detection\n- Leverage `get_shards` tool for detailed cluster state monitoring via MCP\n\n### Security Considerations\n\n- Health endpoints do not require authentication by default\n- Restrict access using network policies in production\n- The `/ping` endpoint returns minimal information suitable for public exposure\n\n## Configuration Reference\n\n### Health Router Configuration\n\nThe health router is mounted at `/_health` within the main application router:\n\n```rust\nlet health_router = Router::new()\n    .route(\"/ready\", get(async || (StatusCode::OK, \"Ready\\n\")))\n    .route(\"/live\", get(async || \"Alive\\n\"));\n```\n\nSource: [src/protocol/http.rs:1-50](src/protocol/http.rs)\n\n### Server Initialization\n\nHealth endpoints become available after successful server initialization:\n\n```rust\nlet handler = elasticsearch::ElasticsearchMcp::new_with_config(config.elasticsearch, container_mode)?;\n```\n\nThe server is ready when the `EsBaseTools` handler is constructed with a valid Elasticsearch client. Source: [src/lib.rs](src/lib.rs)\n\n## Deprecation Notice\n\nThe Elasticsearch MCP Server is deprecated as of v0.4.6. For production monitoring workloads, consider migrating to the [Elastic Agent Builder](https://ela.st/agent-builder-docs) MCP endpoint available in Elastic 9.2.0+ and Elasticsearch Serverless projects. Source: [README.md](README.md)\n\n---\n\n<a id='page-contributing'></a>\n\n## Contributing Guide\n\n### Related Pages\n\nRelated topics: [System Architecture](#page-architecture)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [Cargo.toml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/Cargo.toml)\n- [Makefile](https://github.com/elastic/mcp-server-elasticsearch/blob/main/Makefile)\n- [docs/CONTRIBUTING.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/docs/CONTRIBUTING.md)\n- [rustfmt.toml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/rustfmt.toml)\n- [scripts/cargo-run.sh](https://github.com/elastic/mcp-server-elasticsearch/blob/main/scripts/cargo-run.sh)\n</details>\n\n# Contributing Guide\n\nWelcome 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.\n\n## Overview\n\nThe 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.\n\nContributions 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.\n\n## Development Environment Setup\n\n### Prerequisites\n\n| Requirement | Version | Purpose |\n|-------------|---------|---------|\n| Rust | 1.75+ | Primary language runtime |\n| Cargo | Latest stable | Package manager and build tool |\n| Docker | 24.0+ | Container runtime for testing |\n| Elasticsearch | 8.x or 9.x | Target cluster for integration testing |\n\n### Initial Setup\n\n1. **Clone the repository**\n   ```bash\n   git clone https://github.com/elastic/mcp-server-elasticsearch.git\n   cd mcp-server-elasticsearch\n   ```\n\n2. **Install Rust dependencies**\n   ```bash\n   cargo fetch\n   ```\n\n3. **Verify the build compiles successfully**\n   ```bash\n   cargo build\n   ```\n\n### Running the Server Locally\n\nThe project provides a helper script for running the server during development:\n\n```bash\n./scripts/cargo-run.sh\n```\n\nThis script wraps the cargo run command with appropriate environment configuration for local development.\n\n## Project Structure\n\n```\nmcp-server-elasticsearch/\n├── src/\n│   ├── servers/\n│   │   └── elasticsearch/\n│   │       ├── base_tools.rs    # Core MCP tool implementations\n│   │       └── mod.rs            # Server configuration and initialization\n│   ├── utils/\n│   │   ├── interpolator.rs       # Environment variable interpolation\n│   │   ├── mod.rs                # Utility module exports\n│   │   └── rmcp_ext.rs           # MCP SDK extensions\n│   ├── cli.rs                    # Command-line interface\n│   └── lib.rs                    # Library entry point\n├── tests/                        # Integration tests\n├── Makefile                      # Build and development tasks\n├── Cargo.toml                    # Rust dependencies and metadata\n└── rustfmt.toml                  # Code formatting configuration\n```\n\n## Code Style and Standards\n\n### Formatting\n\nThe project uses `rustfmt` for consistent code formatting. Configuration is defined in `rustfmt.toml`:\n\n| Setting | Value | Description |\n|---------|-------|-------------|\n| `max_width` | 100 | Maximum line length |\n| `tab_spaces` | 4 | Indentation size |\n| `edition` | 2021 | Rust edition |\n\n**Format your code before committing:**\n```bash\ncargo fmt --check\n```\n\n### Linting\n\nRun clippy for linting checks:\n```bash\ncargo clippy --all-targets --all-features\n```\n\nAddress all warnings and errors reported by clippy before submitting your pull request.\n\n### Code Organization\n\nThe codebase follows these architectural patterns:\n\n- **Tool Implementation**: MCP tools are defined using the `#[tool]` macro and implemented in `src/servers/elasticsearch/base_tools.rs`\n- **Configuration**: Configuration parsing uses serde with JSON5 support for comments in config files\n- **Error Handling**: The project uses `anyhow::Error` for flexible error handling\n- **HTTP Authentication**: The `EsClientProvider` supports authorization header passthrough for HTTP transport mode\n\n## Testing\n\n### Unit Tests\n\nRun unit tests with:\n```bash\ncargo test\n```\n\n### Integration Testing\n\nIntegration tests require a running Elasticsearch cluster. Configure the test environment using environment variables:\n\n| Environment Variable | Description | Required |\n|---------------------|-------------|----------|\n| `ES_URL` | Elasticsearch cluster URL | Yes |\n| `ES_API_KEY` | API key for authentication | No* |\n| `ES_USERNAME` | Username for basic auth | No* |\n| `ES_PASSWORD` | Password for basic auth | No* |\n\n*Either API key or username/password combination required\n\n### Build Verification\n\nUse the Makefile to verify the complete build:\n\n```bash\nmake build\n```\n\n## MCP Tool Development\n\n### Defining New Tools\n\nTools are defined using the `#[tool]` attribute macro. The framework expects specific parameters:\n\n```rust\n#[tool(\n    description = \"Tool description for LLM context\",\n    annotations(title = \"Display title\", read_only_hint = true)\n)]\nasync fn my_tool(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(ToolParams): Parameters<ToolParams>,\n) -> Result<CallToolResult, rmcp::Error> {\n    // Implementation\n}\n```\n\n### Tool Parameters\n\nParameter types must implement `serde::Deserialize` and `schemars::JsonSchema`:\n\n```rust\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct MyToolParams {\n    /// Parameter description for schema generation\n    param_name: String,\n}\n```\n\n### Response Format\n\nReturn tool results using `CallToolResult::success()` with a vector of `Content` items:\n\n```rust\nOk(CallToolResult::success(vec![\n    Content::text(\"Description\"),\n    Content::json(data)?,\n]))\n```\n\n## Submitting Changes\n\n### Branch Strategy\n\n1. Create a feature branch from `main`:\n   ```bash\n   git checkout -b feature/my-feature\n   ```\n\n2. Make your changes following the coding standards\n\n3. Commit with clear, descriptive messages:\n   ```bash\n   git commit -m \"Add support for new ES|QL aggregation function\"\n   ```\n\n### Pull Request Checklist\n\n- [ ] Code formatted with `cargo fmt`\n- [ ] Clippy warnings resolved\n- [ ] Tests pass with `cargo test`\n- [ ] New tools include parameter documentation\n- [ ] Configuration changes documented in relevant files\n- [ ] Commit messages follow conventional format\n\n### Commit Message Format\n\n```\n<type>(<scope>): <description>\n\n[optional body]\n```\n\nTypes: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`\n\n## Build and Release Process\n\n### Build Targets\n\nThe project supports multiple build targets:\n\n| Target | Platform | Architecture |\n|--------|----------|--------------|\n| x86_64-unknown-linux-musl | Linux | x86_64 |\n| x86_64-apple-darwin | macOS | x86_64 |\n| aarch64-apple-darwin | macOS | ARM64 |\n| x86_64-pc-windows-msvc | Windows | x86_64 |\n\n### Using Makefile\n\nThe Makefile provides convenient build targets:\n\n```bash\nmake build       # Build release binary\nmake test        # Run test suite\nmake check       # Run formatting and clippy\nmake clean       # Clean build artifacts\n```\n\n## Known Limitations\n\nWhen contributing, be aware of the following known issues:\n\n1. **Nested Mappings Issue**: The `get_mappings` tool may fail with \"error decoding response body\" when nested properties omit explicit type specification. See [Issue #185](https://github.com/elastic/mcp-server-elasticsearch/issues/185).\n\n2. **Basic Auth Configuration**: Authentication via environment variables requires specific naming (`ES_USERNAME`, `ES_PASSWORD`). See [Issue #170](https://github.com/elastic/mcp-server-elasticsearch/issues/170).\n\n3. **Platform Binaries**: Currently, Linux ARM64 binaries are not published. See [Issue #191](https://github.com/elastic/mcp-server-elasticsearch/issues/191).\n\n## Getting Help\n\nIf you encounter issues while contributing:\n\n- Check existing [GitHub Issues](https://github.com/elastic/mcp-server-elasticsearch/issues) for similar problems\n- Review the [MCP Protocol Documentation](https://modelcontextprotocol.io/docs/concepts/transports) for transport-related questions\n- Join the Elastic community for support\n\n## License\n\nBy contributing to this project, you agree that your contributions will be licensed under the Apache License, Version 2.0. See the [NOTICE.txt](https://github.com/elastic/mcp-server-elasticsearch/blob/main/NOTICE.txt) file for details.\n\n---\n\n<!-- evidence_pipeline_checked: true -->\n<!-- evidence_injected: true -->\n\n---\n\n## Pitfall Log\n\nProject: elastic/mcp-server-elasticsearch\n\nSummary: Found 10 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Installation risk - Installation risk requires verification.\n\n## 1. Installation risk - Installation risk requires verification\n\n- Severity: medium\n- Evidence strength: runtime_trace\n- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Repro command: `docker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio`\n- Evidence: identity.distribution | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 2. Installation risk - Installation risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: community_evidence:github | cevd_5573c160ecdd4e34be6dbf6549fe2529 | https://github.com/elastic/mcp-server-elasticsearch/issues/6\n\n## 3. Configuration risk - Configuration risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: capability.host_targets | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 4. Capability evidence risk - Capability evidence risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: README/documentation is current enough for a first validation pass.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: capability.assumptions | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 5. Maintenance risk - Maintenance risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 6. Security or permission risk - Security or permission risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: downstream_validation.risk_items | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 7. Security or permission risk - Security or permission risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: risks.scoring_risks | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 8. Security or permission risk - Security or permission risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: community_evidence:github | cevd_f8732a2deab341d6b739b122459d1243 | https://github.com/elastic/mcp-server-elasticsearch/issues/185\n\n## 9. Maintenance risk - Maintenance risk requires verification\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: issue_or_pr_quality=unknown。\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 10. Maintenance risk - Maintenance risk requires verification\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: release_recency=unknown。\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n<!-- canonical_name: elastic/mcp-server-elasticsearch; human_manual_source: deepwiki_human_wiki -->\n",
      "markdown_key": "mcp-server-elasticsearch",
      "pages": "draft",
      "source_refs": [
        {
          "evidence_id": "github_repo:953992846",
          "kind": "repo",
          "supports_claim_ids": [
            "claim_identity",
            "claim_distribution",
            "claim_capability"
          ],
          "url": "https://github.com/elastic/mcp-server-elasticsearch"
        },
        {
          "evidence_id": "art_cfb65a7eda0a49dfac62bff85cbd5963",
          "kind": "docs",
          "supports_claim_ids": [
            "claim_identity",
            "claim_distribution",
            "claim_capability"
          ],
          "url": "https://github.com/elastic/mcp-server-elasticsearch#readme"
        }
      ],
      "summary": "DeepWiki/Human Wiki 完整输出，末尾追加 Discovery Agent 踩坑日志。",
      "title": "mcp-server-elasticsearch Manual",
      "toc": [
        "https://github.com/elastic/mcp-server-elasticsearch Project Manual",
        "Table of Contents",
        "Project Introduction",
        "Overview",
        "Project Metadata",
        "Architecture",
        "Core Components",
        "Available Tools",
        "Pitfall Log"
      ]
    }
  },
  "quality_gate": {
    "blocking_gaps": [],
    "category_confidence": "medium",
    "compile_status": "ready_for_review",
    "five_assets_present": true,
    "install_sandbox_verified": true,
    "missing_evidence": [],
    "next_action": "publish to Doramagic.ai project surfaces",
    "prompt_preview_boundary_ok": true,
    "publish_status": "publishable",
    "quick_start_verified": true,
    "repo_clone_verified": true,
    "repo_commit": "a2b050d07c1e0af19974f63efa20f4553cb43b2b",
    "repo_inspection_error": null,
    "repo_inspection_files": [
      "Dockerfile",
      "README.md",
      "docs/CONTRIBUTING.md"
    ],
    "repo_inspection_verified": true,
    "review_reasons": [],
    "tag_count_ok": true,
    "unsupported_claims": []
  },
  "schema_version": "0.1",
  "user_assets": {
    "ai_context_pack": {
      "asset_id": "ai_context_pack",
      "filename": "AI_CONTEXT_PACK.md",
      "markdown": "# mcp-server-elasticsearch - Doramagic AI Context Pack\n\n> 定位：安装前体验与判断资产。它帮助宿主 AI 有一个好的开始，但不代表已经安装、执行或验证目标项目。\n\n## 充分原则\n\n- **充分原则，不是压缩原则**：AI Context Pack 应该充分到让宿主 AI 在开工前理解项目价值、能力边界、使用入口、风险和证据来源；它可以分层组织，但不以最短摘要为目标。\n- **压缩策略**：只压缩噪声和重复内容，不压缩会影响判断和开工质量的上下文。\n\n## 给宿主 AI 的使用方式\n\n你正在读取 Doramagic 为 mcp-server-elasticsearch 编译的 AI Context Pack。请把它当作开工前上下文：帮助用户理解适合谁、能做什么、如何开始、哪些必须安装后验证、风险在哪里。不要声称你已经安装、运行或执行了目标项目。\n\n## Claim 消费规则\n\n- **事实来源**：Repo Evidence + Claim/Evidence Graph；Human Wiki 只提供显著性、术语和叙事结构。\n- **事实最低状态**：`supported`\n- `supported`：可以作为项目事实使用，但回答中必须引用 claim_id 和证据路径。\n- `weak`：只能作为低置信度线索，必须要求用户继续核实。\n- `inferred`：只能用于风险提示或待确认问题，不能包装成项目事实。\n- `unverified`：不得作为事实使用，应明确说证据不足。\n- `contradicted`：必须展示冲突来源，不得替用户强行选择一个版本。\n\n## 它最适合谁\n\n- **正在使用 Claude/Codex/Cursor/Gemini 等宿主 AI 的开发者**：README 或插件配置提到多个宿主 AI。 证据：`README.md` Claim：`clm_0016` supported 0.86\n\n## 它能做什么\n\n- **Elasticsearch Index Management**（需要安装后验证）：List and explore Elasticsearch indices with their status, document counts, and metadata 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n- **Index Mapping Retrieval**（需要安装后验证）：Retrieve field mappings for specified Elasticsearch indices to understand data schemas 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n- **Full-text Search**（需要安装后验证）：Execute search queries against Elasticsearch indices with support for aggregations and source field filtering 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs`, `README.md` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n- **ES|QL Query Execution**（需要安装后验证）：Run ES|QL (Elasticsearch Query Language) queries for data analysis and transformation 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n- **Shard Distribution Analysis**（需要安装后验证）：View shard allocation and distribution across nodes for debugging and performance analysis 证据：`src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n- **API Key Authentication**（需要安装后验证）：Connect to Elasticsearch using API key-based authentication 证据：`src/servers/elasticsearch/mod.rs`, `.env-example`, `README.md` Claim：`clm_0003` supported 0.86, `clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0008` supported 0.86 等\n- **Basic Authentication**（需要安装后验证）：Connect to Elasticsearch using username and password credentials 证据：`src/servers/elasticsearch/mod.rs`, `README.md` Claim：`clm_0003` supported 0.86, `clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0008` supported 0.86 等\n- **Stdio Transport Protocol**（可做安装前预览）：Direct communication between MCP client and server using standard input/output streams 证据：`src/lib.rs`, `Cargo.toml`, `README.md` Claim：`clm_0003` supported 0.86, `clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0008` supported 0.86 等\n- **Streamable HTTP Transport**（可做安装前预览）：HTTP-based MCP protocol for web integrations, stateful sessions, and concurrent clients 证据：`src/protocol/http.rs`, `Cargo.toml`, `README.md`, `src/protocol/http.rs` Claim：`clm_0003` supported 0.86, `clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0008` supported 0.86 等\n- **JSON5 Configuration Files**（可做安装前预览）：Load server configuration from JSON5 files with support for comments and environment variable interpolation 证据：`src/lib.rs`, `Cargo.toml`, `elastic-mcp.json5` Claim：`clm_0008` supported 0.86, `clm_0009` supported 0.86, `clm_0010` supported 0.86, `clm_0011` supported 0.86 等\n- **Environment Variable Interpolation**（可做安装前预览）：Substitute environment variables in configuration using ${VAR} or ${VAR:default} syntax 证据：`src/utils/interpolator.rs`, `src/utils/interpolator.rs`, `elastic-mcp.json5` Claim：`clm_0010` supported 0.86, `clm_0011` supported 0.86\n- **Docker Container Deployment**（可做安装前预览）：Run as Docker container with support for multi-platform images (amd64, arm64) and AWS ECR 证据：`Dockerfile`, `Dockerfile-8000`, `Makefile`, `Dockerfile` Claim：`clm_0012` supported 0.86\n- **SSL Certificate Verification Control**（需要安装后验证）：Optionally skip SSL/TLS certificate verification for development/testing environments 证据：`src/servers/elasticsearch/mod.rs`, `README.md` Claim：`clm_0003` supported 0.86, `clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0008` supported 0.86 等\n- **Container Hostname Rewriting**（需要安装后验证）：Rewrite localhost URLs to container host addresses for seamless local development 证据：`src/servers/elasticsearch/mod.rs`, `src/servers/elasticsearch/mod.rs` Claim：`clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0013` supported 0.86, `clm_0014` supported 0.86\n- **MCP Protocol Server**（需要安装后验证）：Implements Model Context Protocol (MCP) server providing tools and capabilities to AI agents 证据：`src/servers/elasticsearch/base_tools.rs`, `Cargo.toml`, `README.md` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n\n## 怎么开始\n\n- `uv tool install mcp-proxy` 证据：`README.md` Claim：`clm_0017` supported 0.86\n- `curl http://<host>:8080/ping` 证据：`README.md` Claim：`clm_0018` supported 0.86\n\n## 继续前判断卡\n\n- **当前建议**：需要管理员/安全审批\n- **为什么**：继续前可能涉及密钥、账号、外部服务或敏感上下文，建议先经过管理员或安全审批。\n\n### 30 秒判断\n\n- **现在怎么做**：需要管理员/安全审批\n- **最小安全下一步**：先跑 Prompt Preview；若涉及凭证或企业环境，先审批再试装\n- **先别相信**：工具权限边界不能在安装前相信。\n- **继续会触碰**：命令执行、本地环境或项目文件、环境变量 / API Key\n\n### 现在可以相信\n\n- **适合人群线索：正在使用 Claude/Codex/Cursor/Gemini 等宿主 AI 的开发者**（supported）：有 supported claim 或项目证据支撑，但仍不等于真实安装效果。 证据：`README.md` Claim：`clm_0016` supported 0.86\n- **能力存在：Elasticsearch Index Management**（supported）：可以相信项目包含这类能力线索；是否适合你的具体任务仍要试用或安装后验证。 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86\n- **能力存在：Index Mapping Retrieval**（supported）：可以相信项目包含这类能力线索；是否适合你的具体任务仍要试用或安装后验证。 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86\n- **能力存在：Full-text Search**（supported）：可以相信项目包含这类能力线索；是否适合你的具体任务仍要试用或安装后验证。 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs`, `README.md` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86\n- **能力存在：ES|QL Query Execution**（supported）：可以相信项目包含这类能力线索；是否适合你的具体任务仍要试用或安装后验证。 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86\n- **能力存在：Shard Distribution Analysis**（supported）：可以相信项目包含这类能力线索；是否适合你的具体任务仍要试用或安装后验证。 证据：`src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86\n\n### 现在还不能相信\n\n- **工具权限边界不能在安装前相信。**（unverified）：MCP/tool 类项目通常会触碰文件、网络、浏览器或外部 API，必须真实检查权限和日志。\n- **真实输出质量不能在安装前相信。**（unverified）：Prompt Preview 只能展示引导方式，不能证明真实项目中的结果质量。\n- **宿主 AI 版本兼容性不能在安装前相信。**（unverified）：Claude、Cursor、Codex、Gemini 等宿主加载规则和版本差异必须在真实环境验证。\n- **不会污染现有宿主 AI 行为，不能直接相信。**（inferred）：Skill、plugin、AGENTS/CLAUDE/GEMINI 指令可能改变宿主 AI 的默认行为。\n- **可安全回滚不能默认相信。**（unverified）：除非项目明确提供卸载和恢复说明，否则必须先在隔离环境验证。\n- **真实安装后是否与用户当前宿主 AI 版本兼容？**（unverified）：兼容性只能通过实际宿主环境验证。\n- **项目输出质量是否满足用户具体任务？**（unverified）：安装前预览只能展示流程和边界，不能替代真实评测。\n- **安装命令是否需要网络、权限或全局写入？**（unverified）：这影响企业环境和个人环境的安装风险。 证据：`README.md`\n\n### 继续会触碰什么\n\n- **命令执行**：包管理器、网络下载、本地插件目录、项目配置或用户主目录。 原因：运行第一条命令就可能产生环境改动；必须先判断是否值得跑。 证据：`README.md`\n- **本地环境或项目文件**：安装结果、插件缓存、项目配置或本地依赖目录。 原因：安装前无法证明写入范围和回滚方式，需要隔离验证。 证据：`.env-example`, `Cargo.toml`, `README.md`, `src/servers/elasticsearch/base_tools.rs` 等\n- **环境变量 / API Key**：项目入口文档明确出现 API key、token、secret 或账号凭证配置。 原因：如果真实安装需要凭证，应先使用测试凭证并经过权限/合规判断。 证据：`README.md`\n- **宿主 AI 上下文**：AI Context Pack、Prompt Preview、Skill 路由、风险规则和项目事实。 原因：导入上下文会影响宿主 AI 后续判断，必须避免把未验证项包装成事实。\n\n### 最小安全下一步\n\n- **先跑 Prompt Preview**：用安装前交互式试用判断工作方式是否匹配，不需要授权或改环境。（适用：任何项目都适用，尤其是输出质量未知时。）\n- **只在隔离目录或测试账号试装**：避免安装命令污染主力宿主 AI、真实项目或用户主目录。（适用：存在命令执行、插件配置或本地写入线索时。）\n- **不要使用真实生产凭证**：环境变量/API key 一旦进入宿主或工具链，可能产生账号和合规风险。（适用：出现 API、TOKEN、KEY、SECRET 等环境线索时。）\n- **安装后只验证一个最小任务**：先验证加载、兼容、输出质量和回滚，再决定是否深用。（适用：准备从试用进入真实工作流时。）\n\n### 退出方式\n\n- **保留安装前状态**：记录原始宿主配置和项目状态，后续才能判断是否可恢复。\n- **记录安装命令和写入路径**：没有明确卸载说明时，至少要知道哪些目录或配置需要手动清理。\n- **准备撤销测试 API key 或 token**：测试凭证泄露或误用时，可以快速止损。\n- **如果没有回滚路径，不进入主力环境**：不可回滚是继续前阻断项，不应靠信任或运气继续。\n\n## 哪些只能预览\n\n- 解释项目适合谁和能做什么\n- 基于项目文档演示典型对话流程\n- 帮助用户判断是否值得安装或继续研究\n\n## 哪些必须安装后验证\n\n- 真实安装 Skill、插件或 CLI\n- 执行脚本、修改本地文件或访问外部服务\n- 验证真实输出质量、性能和兼容性\n\n## 边界与风险判断卡\n\n- **把安装前预览误认为真实运行**：用户可能高估项目已经完成的配置、权限和兼容性验证。 处理方式：明确区分 prompt_preview_can_do 与 runtime_required。 Claim：`clm_0019` inferred 0.45\n- **命令执行会修改本地环境**：安装命令可能写入用户主目录、宿主插件目录或项目配置。 处理方式：先在隔离环境或测试账号中运行。 证据：`README.md` Claim：`clm_0020` supported 0.86\n- **风险**： 处理方式：\n- **风险**： 处理方式：\n- **风险**： 处理方式：\n- **待确认**：真实安装后是否与用户当前宿主 AI 版本兼容？。原因：兼容性只能通过实际宿主环境验证。\n- **待确认**：项目输出质量是否满足用户具体任务？。原因：安装前预览只能展示流程和边界，不能替代真实评测。\n- **待确认**：安装命令是否需要网络、权限或全局写入？。原因：这影响企业环境和个人环境的安装风险。\n\n## 开工前工作上下文\n\n### 加载顺序\n\n- 先读取 how_to_use.host_ai_instruction，建立安装前判断资产的边界。\n- 读取 claim_graph_summary，确认事实来自 Claim/Evidence Graph，而不是 Human Wiki 叙事。\n- 再读取 intended_users、capabilities 和 quick_start_candidates，判断用户是否匹配。\n- 需要执行具体任务时，优先查 role_skill_index，再查 evidence_index。\n- 遇到真实安装、文件修改、网络访问、性能或兼容性问题时，转入 risk_card 和 boundaries.runtime_required。\n\n### 任务路由\n\n- **Elasticsearch Index Management**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n- **Index Mapping Retrieval**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n- **Full-text Search**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs`, `README.md` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n- **ES|QL Query Execution**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`src/servers/elasticsearch/base_tools.rs`, `src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n- **Shard Distribution Analysis**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`src/servers/elasticsearch/base_tools.rs` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n- **API Key Authentication**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`src/servers/elasticsearch/mod.rs`, `.env-example`, `README.md` Claim：`clm_0003` supported 0.86, `clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0008` supported 0.86 等\n- **Basic Authentication**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`src/servers/elasticsearch/mod.rs`, `README.md` Claim：`clm_0003` supported 0.86, `clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0008` supported 0.86 等\n- **Stdio Transport Protocol**：先基于 role_skill_index / evidence_index 帮用户挑选可用角色、Skill 或工作流。 边界：可做安装前 Prompt 体验。 证据：`src/lib.rs`, `Cargo.toml`, `README.md` Claim：`clm_0003` supported 0.86, `clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0008` supported 0.86 等\n- **Streamable HTTP Transport**：先基于 role_skill_index / evidence_index 帮用户挑选可用角色、Skill 或工作流。 边界：可做安装前 Prompt 体验。 证据：`src/protocol/http.rs`, `Cargo.toml`, `README.md`, `src/protocol/http.rs` Claim：`clm_0003` supported 0.86, `clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0008` supported 0.86 等\n- **JSON5 Configuration Files**：先基于 role_skill_index / evidence_index 帮用户挑选可用角色、Skill 或工作流。 边界：可做安装前 Prompt 体验。 证据：`src/lib.rs`, `Cargo.toml`, `elastic-mcp.json5` Claim：`clm_0008` supported 0.86, `clm_0009` supported 0.86, `clm_0010` supported 0.86, `clm_0011` supported 0.86 等\n- **Environment Variable Interpolation**：先基于 role_skill_index / evidence_index 帮用户挑选可用角色、Skill 或工作流。 边界：可做安装前 Prompt 体验。 证据：`src/utils/interpolator.rs`, `src/utils/interpolator.rs`, `elastic-mcp.json5` Claim：`clm_0010` supported 0.86, `clm_0011` supported 0.86\n- **Docker Container Deployment**：先基于 role_skill_index / evidence_index 帮用户挑选可用角色、Skill 或工作流。 边界：可做安装前 Prompt 体验。 证据：`Dockerfile`, `Dockerfile-8000`, `Makefile`, `Dockerfile` Claim：`clm_0012` supported 0.86\n- **SSL Certificate Verification Control**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`src/servers/elasticsearch/mod.rs`, `README.md` Claim：`clm_0003` supported 0.86, `clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0008` supported 0.86 等\n- **Container Hostname Rewriting**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`src/servers/elasticsearch/mod.rs`, `src/servers/elasticsearch/mod.rs` Claim：`clm_0006` supported 0.86, `clm_0007` supported 0.86, `clm_0013` supported 0.86, `clm_0014` supported 0.86\n- **MCP Protocol Server**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`src/servers/elasticsearch/base_tools.rs`, `Cargo.toml`, `README.md` Claim：`clm_0001` supported 0.86, `clm_0002` supported 0.86, `clm_0003` supported 0.86, `clm_0004` supported 0.86 等\n\n### 上下文规模\n\n- 文件总数：33\n- 重要文件覆盖：30/33\n- 证据索引条目：30\n- 角色 / Skill 条目：2\n\n### 证据不足时的处理\n\n- **missing_evidence**：说明证据不足，要求用户提供目标文件、README 段落或安装后验证记录；不要补全事实。\n- **out_of_scope_request**：说明该任务超出当前 AI Context Pack 证据范围，并建议用户先查看 Human Manual 或真实安装后验证。\n- **runtime_request**：给出安装前检查清单和命令来源，但不要替用户执行命令或声称已执行。\n- **source_conflict**：同时展示冲突来源，标记为待核实，不要强行选择一个版本。\n\n## Prompt Recipes\n\n### 适配判断\n\n- 目标：判断这个项目是否适合用户当前任务。\n- 预期输出：适配结论、关键理由、证据引用、安装前可预览内容、必须安装后验证内容、下一步建议。\n\n```text\n请基于 mcp-server-elasticsearch 的 AI Context Pack，先问我 3 个必要问题，然后判断它是否适合我的任务。回答必须包含：适合谁、能做什么、不能做什么、是否值得安装、证据来自哪里。所有项目事实必须引用 evidence_refs、source_paths 或 claim_id。\n```\n\n### 安装前体验\n\n- 目标：让用户在安装前感受核心工作流，同时避免把预览包装成真实能力或营销承诺。\n- 预期输出：一段带边界标签的体验剧本、安装后验证清单和谨慎建议；不含真实运行承诺或强营销表述。\n\n```text\n请把 mcp-server-elasticsearch 当作安装前体验资产，而不是已安装工具或真实运行环境。\n\n请严格输出四段：\n1. 先问我 3 个必要问题。\n2. 给出一段“体验剧本”：用 [安装前可预览]、[必须安装后验证]、[证据不足] 三种标签展示它可能如何引导工作流。\n3. 给出安装后验证清单：列出哪些能力只有真实安装、真实宿主加载、真实项目运行后才能确认。\n4. 给出谨慎建议：只能说“值得继续研究/试装”“先补充信息后再判断”或“不建议继续”，不得替项目背书。\n\n硬性边界：\n- 不要声称已经安装、运行、执行测试、修改文件或产生真实结果。\n- 不要写“自动适配”“确保通过”“完美适配”“强烈建议安装”等承诺性表达。\n- 如果描述安装后的工作方式，必须使用“如果安装成功且宿主正确加载 Skill，它可能会……”这种条件句。\n- 体验剧本只能写成“示例台词/假设流程”：使用“可能会询问/可能会建议/可能会展示”，不要写“已写入、已生成、已通过、正在运行、正在生成”。\n- Prompt Preview 不负责给安装命令；如用户准备试装，只能提示先阅读 Quick Start 和 Risk Card，并在隔离环境验证。\n- 所有项目事实必须来自 supported claim、evidence_refs 或 source_paths；inferred/unverified 只能作风险或待确认项。\n\n```\n\n### 角色 / Skill 选择\n\n- 目标：从项目里的角色或 Skill 中挑选最匹配的资产。\n- 预期输出：候选角色或 Skill 列表，每项包含适用场景、证据路径、风险边界和是否需要安装后验证。\n\n```text\n请读取 role_skill_index，根据我的目标任务推荐 3-5 个最相关的角色或 Skill。每个推荐都要说明适用场景、可能输出、风险边界和 evidence_refs。\n```\n\n### 风险预检\n\n- 目标：安装或引入前识别环境、权限、规则冲突和质量风险。\n- 预期输出：环境、权限、依赖、许可、宿主冲突、质量风险和未知项的检查清单。\n\n```text\n请基于 risk_card、boundaries 和 quick_start_candidates，给我一份安装前风险预检清单。不要替我执行命令，只说明我应该检查什么、为什么检查、失败会有什么影响。\n```\n\n### 宿主 AI 开工指令\n\n- 目标：把项目上下文转成一次对话开始前的宿主 AI 指令。\n- 预期输出：一段边界明确、证据引用明确、适合复制给宿主 AI 的开工前指令。\n\n```text\n请基于 mcp-server-elasticsearch 的 AI Context Pack，生成一段我可以粘贴给宿主 AI 的开工前指令。这段指令必须遵守 not_runtime=true，不能声称项目已经安装、运行或产生真实结果。\n```\n\n\n## 角色 / Skill 索引\n\n- 共索引 2 个角色 / Skill / 项目文档条目。\n\n- **Contributing**（project_doc）：fork : https://github.com/elastic/mcp-server-elasticsearch/fork pr : https://github.com/elastic/mcp-server-elasticsearch/compare code-of-conduct : https://www.elastic.co/community/codeofconduct 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/CONTRIBUTING.md`\n- **Elasticsearch MCP Server**（project_doc）：!CAUTION This MCP server is deprecated and will only receive critical security updates going forward. It has been superseded by the Elastic Agent Builder https://ela.st/agent-builder-docs MCP endpoint https://ela.st/agent-builder-mcp , which is available in Elastic 9.2.0+ and Elasticsearch Serverless projects. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`README.md`\n\n## 证据索引\n\n- 共索引 30 条证据。\n\n- **Contributing**（documentation）：fork : https://github.com/elastic/mcp-server-elasticsearch/fork pr : https://github.com/elastic/mcp-server-elasticsearch/compare code-of-conduct : https://www.elastic.co/community/codeofconduct 证据：`docs/CONTRIBUTING.md`\n- **Elasticsearch MCP Server**（documentation）：!CAUTION This MCP server is deprecated and will only receive critical security updates going forward. It has been superseded by the Elastic Agent Builder https://ela.st/agent-builder-docs MCP endpoint https://ela.st/agent-builder-mcp , which is available in Elastic 9.2.0+ and Elasticsearch Serverless projects. 证据：`README.md`\n- **License**（source_file）：Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ 证据：`LICENSE`\n- **Renovate**（structured_config）：{ \"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\", \"extends\": \"local elastic/renovate-config\" , \"schedule\": \"after 1am on monday\" } 证据：`renovate.json`\n- **The MCP server looks for .env files to populate environment variables that aren't already set**（source_file）：The MCP server looks for .env files to populate environment variables that aren't already set Copy and edit this file it's listed in .gitignore 证据：`.env-example`\n- **Base stuff**（source_file）：package name = \"elasticsearch-core-mcp-server\" version = \"0.4.6\" edition = \"2024\" authors = \"Elastic.co\" license-file = \"LICENSE\" description = \"MCP server for core Elastisearch features\" homepage = \"https://github.com/elastic/mcp-server-elasticsearch\" repository = \"https://github.com/elastic/mcp-server-elasticsearch\" 证据：`Cargo.toml`\n- **Notice**（source_file）：Elasticsearch MCP Server Copyright 2025 Elasticsearch B.V. 证据：`NOTICE.txt`\n- **Catalog Info**（source_file）：apiVersion: backstage.io/v1alpha1 kind: Resource metadata: name: buildkite-pipeline-mcp-server-elasticsearch description: Buildkite Pipeline for mcp-server-elasticsearch links: - title: Pipeline url: https://buildkite.com/elastic/mcp-server-elasticsearch spec: type: buildkite-pipeline owner: group:devtools-team system: buildkite implementation: apiVersion: buildkite.elastic.dev/v1 kind: Pipeline metadata: name: mcp-server-elasticsearch description: Run checks for the mcp-server-elasticsearch package spec: repository: elastic/mcp-server-elasticsearch pipeline file: \".buildkite/pipeline.yml\" teams: devtools-team: access level: MANAGE BUILD AND READ everyone: access level: READ ONLY --- apiVer… 证据：`catalog-info.yaml`\n- **Rustfmt**（source_file）：max width = 120 证据：`rustfmt.toml`\n- **Cargo Run**（source_file）：cd \"$ dirname $0 \"/.. exec cargo run \"$@\" 证据：`scripts/cargo-run.sh`\n- **Cli**（source_file）：use crate::servers::elasticsearch; use clap::Parser; ⋮---- use std::collections::HashMap; use std::path::PathBuf; ⋮---- pub struct Cli { ⋮---- pub enum Command { ⋮---- pub struct HttpCommand { ⋮---- pub struct StdioCommand { ⋮---- pub struct Stdio { ⋮---- pub struct Http { ⋮---- pub enum McpServer { ⋮---- pub struct Configuration { 证据：`src/cli.rs`\n- **Lib**（source_file）：pub mod cli; mod protocol; mod servers; mod utils; ⋮---- use crate::servers::elasticsearch; use crate::utils::interpolator; use rmcp::transport::stdio; use rmcp::transport::streamable http server::session::never::NeverSessionManager; ⋮---- use std::path::PathBuf; use std::sync::Arc; use tokio::select; use tokio util::sync::CancellationToken; ⋮---- impl Cli { pub async fn run self - anyhow::Result { ⋮---- Command::Stdio cmd = run stdio cmd, self.container mode .await, Command::Http cmd = run http cmd, self.container mode .await, ⋮---- pub async fn run stdio cmd: StdioCommand, container mode: bool - anyhow::Result { ⋮---- let handler = setup services &cmd.config, container mode .await?; let s… 证据：`src/lib.rs`\n- **Start Http**（source_file）：use elasticsearch core mcp server::cli::HttpCommand; use elasticsearch core mcp server::run http; ⋮---- pub async fn main - anyhow::Result { println! \"Current directory: {:?}\", std::env::current dir ? ; ⋮---- run http HttpCommand { config: Some \"elastic-mcp.json5\".parse ? , ⋮---- Ok 证据：`src/bin/start_http.rs`\n- **Http**（source_file）：use crate::utils::rmcp ext::ServerProvider; use axum::Router; use axum::http::StatusCode; use axum::routing::get; use rmcp::transport::sse server::SseServerConfig; use rmcp::transport::streamable http server::session::local::LocalSessionManager; ⋮---- use std::net::SocketAddr; use std::sync::Arc; use std::time::Duration; use tokio util::sync::CancellationToken; use tracing::Instrument; ⋮---- pub struct HttpServerConfig { ⋮---- pub struct HttpProtocol {} ⋮---- impl HttpProtocol { pub async fn serve with config , M: SessionManager ⋮---- let server provider = server provider.into .0; ⋮---- let ct = config.ct.child token ; ⋮---- let server provider = server provider.clone ; ⋮---- StreamableHttp… 证据：`src/protocol/http.rs`\n- **Mod**（source_file）：pub mod http; pub mod stdio; 证据：`src/protocol/mod.rs`\n- **Base Tools**（source_file）：use elasticsearch::indices::IndicesGetMappingParts; ⋮---- use indexmap::IndexMap; ⋮---- use rmcp::service::RequestContext; ⋮---- use std::collections::HashMap; ⋮---- pub struct EsBaseTools { ⋮---- impl EsBaseTools { pub fn new es client: Elasticsearch - Self { ⋮---- struct ListIndicesParams { ⋮---- struct GetMappingsParams { ⋮---- struct SearchParams { ⋮---- struct EsqlQueryParams { ⋮---- struct GetShardsParams { ⋮---- async fn list indices ⋮---- let es client = self.es client.get req ctx ; ⋮---- .cat .indices CatIndicesParts::Index & &index pattern .h & \"index\", \"status\", \"docs.count\" .format \"json\" .send ⋮---- let response: Vec = read json response .await?; ⋮---- Ok CallToolResult::succes… 证据：`src/servers/elasticsearch/base_tools.rs`\n- **Mod**（source_file）：mod base tools; ⋮---- use crate::servers::IncludeExclude; use crate::utils::none if empty string; use elasticsearch::Elasticsearch; use elasticsearch::auth::Credentials; use elasticsearch::cert::CertificateValidation; use elasticsearch::http::Url; use elasticsearch::http::response::Response; use http::header::USER AGENT; use http::request::Parts; ⋮---- use indexmap::IndexMap; use rmcp::RoleServer; use rmcp::model::ToolAnnotations; use rmcp::service::RequestContext; use serde::de::DeserializeOwned; ⋮---- use serde aux::field attributes::deserialize bool from anything; use std::borrow::Cow; use std::collections::HashMap; ⋮---- pub struct ElasticsearchMcpConfig { ⋮---- pub struct EsClientProvi… 证据：`src/servers/elasticsearch/mod.rs`\n- **Mod**（source_file）：pub mod elasticsearch; ⋮---- pub enum IncludeExclude { ⋮---- impl IncludeExclude { pub fn is included &self, name: &str - bool { ⋮---- Include includes = includes.iter .map s s.as str .any s s == name , Exclude excludes = excludes.iter .map s s.as str .all s s != name , ⋮---- pub fn filter &self, tools: &mut Vec { tools.retain t self.is included &t.name 证据：`src/servers/mod.rs`\n- **Interpolator**（source_file）：use thiserror::Error; ⋮---- pub struct InterpolationError { ⋮---- pub fn interpolate from env s: String - Result { interpolate s, name std::env::var name .ok ⋮---- const OPEN LEN: usize = OPEN.len ; ⋮---- const CLOSE LEN: usize = CLOSE.len ; ⋮---- pub fn interpolate s: String, lookup: impl Fn &str - Option - Result { if !s.contains OPEN { return Ok s ; ⋮---- for line no, mut line in s.lines .enumerate { ⋮---- result.push '\\n' ; ⋮---- while let Some pos = line.find OPEN { ⋮---- result.push str &line ..pos ; ⋮---- if let Some pos = line.find CLOSE { ⋮---- let value = if let Some name, default = expr.split once ':' { lookup name .unwrap or default.to string ⋮---- lookup expr .ok or else err ch… 证据：`src/utils/interpolator.rs`\n- **Mod**（source_file）：pub mod interpolator; pub mod rmcp ext; ⋮---- pub fn none if empty string deserializer: D - Result , D::Error { ⋮---- Some s if s.is empty = Ok None , = Ok s , 证据：`src/utils/mod.rs`\n- **Pull Requests**（structured_config）：{ \"jobs\": { \"enabled\": true, \"pipelineSlug\": \"mcp-server-elasticsearch\", \"allow org users\": true, \"allowed repo permissions\": \"admin\", \"write\" , \"allowed list\": , \"set commit status\": true, \"commit status context\": \"buildkite/mcp-server-elasticsearch\", \"build on commit\": false, \"build on comment\": true, \"trigger comment regex\": \"^ ?: ?:buildkite\\\\W+ ? ?:build test \\\\W+ ?:this it \", \"always trigger comment regex\": \"^ ?: ?:buildkite\\\\W+ ? ?:build test \\\\W+ ?:this it \", \"skip ci labels\": \"skip-ci\" , \"skip target branches\": , \"always require ci on changed\": } } 证据：`.buildkite/pull-requests.json`\n- **!/bin/bash**（source_file）：!/bin/bash Produces a list of changed files between two commits works for merges and regular commits . Used in conjunction with the monorepo-diff-buildkite-plugin to determine which pipelines to upload/trigger based on the files changed. 证据：`.buildkite/diff`\n- **Docker**（source_file）：--- steps: - label: \"Build and publish Docker image\" command: \"make docker-push-elastic\" agents: provider: \"gcp\" 证据：`.buildkite/docker.yml`\n- **Pipeline**（source_file）：--- steps: - label: \"Triggering pipelines\" plugins: monorepo-diff diff: \".buildkite/diff ${BUILDKITE COMMIT}\" wait: true watch: - path: \"renovate.json\" config: label: \"Verify Renovate configuration\" command: \"renovate-config-validator\" agents: image: \"docker.elastic.co/ci-agent-images/pipelib:0.22.0@sha256:25503116fb91c18383b17aee528b9ca6e520ef58622c7f961c7d255bb8ba51f6\" - path: \"catalog-info.yaml\" config: command: \"/agent/check-catalog-info.sh\" agents: image: \"docker.elastic.co/ci-agent-images/pipelib:0.22.0@sha256:25503116fb91c18383b17aee528b9ca6e520ef58622c7f961c7d255bb8ba51f6\" 证据：`.buildkite/pipeline.yml`\n- **.dockerignore**（source_file）：docs target .idea .vscode 证据：`.dockerignore`\n- **Generated by Cargo**（source_file）：Generated by Cargo will have compiled files and executables debug/ target/ 证据：`.gitignore`\n- **Copyright Elasticsearch B.V. and contributors**（source_file）：Copyright Elasticsearch B.V. and contributors SPDX-License-Identifier: Apache-2.0 证据：`Dockerfile`\n- **Copyright Elasticsearch B.V. and contributors**（source_file）：Copyright Elasticsearch B.V. and contributors SPDX-License-Identifier: Apache-2.0 证据：`Dockerfile-8000`\n- **set version variable**（source_file）：set version variable VERSION = $ shell grep '^version' Cargo.toml head -n1 cut -d ' ' -f3 sed 's/\"//g' ES IMAGE = \"docker.elastic.co/mcp/elasticsearch:$ VERSION \" ES IMAGE LATEST = \"docker.elastic.co/mcp/elasticsearch:latest\" AWS IMAGE = \"709825985650.dkr.ecr.us-east-1.amazonaws.com/elastic/mcp/elasticsearch:$ VERSION \" 证据：`Makefile`\n- **Elastic Mcp**（source_file）：{ // Configure the target Elasticsearch server \"elasticsearch\": { \"url\": \"${ES URL}\", \"api key\": \"${ES API KEY:}\", \"username\": \"${ES USERNAME:}\", \"password\": \"${ES PASSWORD:}\", \"ssl skip verify\": \"${ES SSL SKIP VERIFY:false}\", 证据：`elastic-mcp.json5`\n\n## 宿主 AI 必须遵守的规则\n\n- **把本资产当作开工前上下文，而不是运行环境。**：AI Context Pack 只包含证据化项目理解，不包含目标项目的可执行状态。 证据：`docs/CONTRIBUTING.md`, `README.md`, `LICENSE`\n- **回答用户时区分可预览内容与必须安装后才能验证的内容。**：安装前体验的消费者价值来自降低误装和误判，而不是伪装成真实运行。 证据：`docs/CONTRIBUTING.md`, `README.md`, `LICENSE`\n\n## 用户开工前应该回答的问题\n\n- 你准备在哪个宿主 AI 或本地环境中使用它？\n- 你只是想先体验工作流，还是准备真实安装？\n- 你最在意的是安装成本、输出质量、还是和现有规则的冲突？\n\n## 验收标准\n\n- 所有能力声明都能回指到 evidence_refs 中的文件路径。\n- AI_CONTEXT_PACK.md 没有把预览包装成真实运行。\n- 用户能在 3 分钟内看懂适合谁、能做什么、如何开始和风险边界。\n\n---\n\n## Doramagic Context Augmentation\n\n下面内容用于强化 Repomix/AI Context Pack 主体。Human Manual 只提供阅读骨架；踩坑日志会被转成宿主 AI 必须遵守的工作约束。\n\n## Human Manual 骨架\n\n使用规则：这里只是项目阅读路线和显著性信号，不是事实权威。具体事实仍必须回到 repo evidence / Claim Graph。\n\n宿主 AI 硬性规则：\n- 不得把页标题、章节顺序、摘要或 importance 当作项目事实证据。\n- 解释 Human Manual 骨架时，必须明确说它只是阅读路线/显著性信号。\n- 能力、安装、兼容性、运行状态和风险判断必须引用 repo evidence、source path 或 Claim Graph。\n\n- **Project Introduction**：importance `high`\n  - source_paths: README.md, catalog-info.yaml, NOTICE.txt\n- **Available MCP Tools**：importance `high`\n  - source_paths: src/servers/elasticsearch/base_tools.rs, src/servers/elasticsearch/mod.rs\n- **System Architecture**：importance `high`\n  - source_paths: src/lib.rs, src/protocol/mod.rs, src/protocol/http.rs, src/protocol/stdio.rs, src/servers/mod.rs\n- **MCP Protocol Configuration**：importance `high`\n  - source_paths: src/cli.rs, src/protocol/http.rs, Dockerfile\n- **Docker Deployment**：importance `high`\n  - source_paths: Dockerfile, Dockerfile-8000, .env-example, Makefile\n- **Authentication and Security**：importance `high`\n  - source_paths: src/servers/elasticsearch/mod.rs, .env-example\n- **Configuration Reference**：importance `medium`\n  - source_paths: .env-example, src/cli.rs, src/servers/elasticsearch/mod.rs, src/utils/interpolator.rs, elastic-mcp.json5\n- **Troubleshooting Guide**：importance `high`\n  - source_paths: src/servers/elasticsearch/base_tools.rs\n\n## Repo Inspection Evidence / 源码检查证据\n\n- repo_clone_verified: true\n- repo_inspection_verified: true\n- repo_commit: `a2b050d07c1e0af19974f63efa20f4553cb43b2b`\n- inspected_files: `Dockerfile`, `README.md`, `docs/CONTRIBUTING.md`\n\n宿主 AI 硬性规则：\n- 没有 repo_clone_verified=true 时，不得声称已经读过源码。\n- 没有 repo_inspection_verified=true 时，不得把 README/docs/package 文件判断写成事实。\n- 没有 quick_start_verified=true 时，不得声称 Quick Start 已跑通。\n\n## Doramagic Pitfall Constraints / 踩坑约束\n\n这些规则来自 Doramagic 发现、验证或编译过程中的项目专属坑点。宿主 AI 必须把它们当作工作约束，而不是普通说明文字。\n\n### Constraint 1: 依赖 Docker 环境\n\n- Trigger: 安装/运行入口包含 Docker 命令：docker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio\n- Host AI rule: 标注 Docker 前置条件，并提供非 Docker 路径或失败提示。\n- Why it matters: 非工程用户可能没有 Docker，启动成本明显增加。\n- Evidence: 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\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 2: 来源证据：Dependency Dashboard\n\n- Trigger: GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Dependency Dashboard\n- Host AI rule: 来源问题仍为 open，Pack Agent 需要复核是否仍影响当前版本。\n- Why it matters: 可能阻塞安装或首次运行。\n- Evidence: community_evidence:github | cevd_5573c160ecdd4e34be6dbf6549fe2529 | https://github.com/elastic/mcp-server-elasticsearch/issues/6 | 来源讨论提到 docker 相关条件，需在安装/试用前复核。\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 3: 可能修改宿主 AI 配置\n\n- Trigger: 项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主，或安装命令涉及用户配置目录。\n- Host AI rule: 列出会写入的配置文件、目录和卸载/回滚步骤。\n- Why it matters: 安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。\n- Evidence: capability.host_targets | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | host_targets=mcp_host, claude, cursor\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 4: 能力判断依赖假设\n\n- Trigger: README/documentation is current enough for a first validation pass.\n- Host AI rule: 将假设转成下游验证清单。\n- Why it matters: 假设不成立时，用户拿不到承诺的能力。\n- Evidence: capability.assumptions | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | README/documentation is current enough for a first validation pass.\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 5: 维护活跃度未知\n\n- Trigger: 未记录 last_activity_observed。\n- Host AI rule: 补 GitHub 最近 commit、release、issue/PR 响应信号。\n- Why it matters: 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | last_activity_observed missing\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 6: 下游验证发现风险项\n\n- Trigger: no_demo\n- Host AI rule: 进入安全/权限治理复核队列。\n- Why it matters: 下游已经要求复核，不能在页面中弱化。\n- Evidence: downstream_validation.risk_items | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | no_demo; severity=medium\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 7: 存在评分风险\n\n- Trigger: no_demo\n- Host AI rule: 把风险写入边界卡，并确认是否需要人工复核。\n- Why it matters: 风险会影响是否适合普通用户安装。\n- Evidence: risks.scoring_risks | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | no_demo; severity=medium\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 8: 来源证据：get_mappings tool fails with \"error decoding response body\" when nested type is omitted in properties\n\n- Trigger: GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：get_mappings tool fails with \"error decoding response body\" when nested type is omitted in properties\n- Host AI rule: 来源显示可能已有修复、规避或版本变化，说明书中必须标注适用版本。\n- Why it matters: 可能影响授权、密钥配置或安全边界。\n- Evidence: community_evidence:github | cevd_f8732a2deab341d6b739b122459d1243 | https://github.com/elastic/mcp-server-elasticsearch/issues/185 | 来源讨论提到 api key 相关条件，需在安装/试用前复核。\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 9: issue/PR 响应质量未知\n\n- Trigger: issue_or_pr_quality=unknown。\n- Host AI rule: 抽样最近 issue/PR，判断是否长期无人处理。\n- Why it matters: 用户无法判断遇到问题后是否有人维护。\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | issue_or_pr_quality=unknown\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 10: 发布节奏不明确\n\n- Trigger: release_recency=unknown。\n- Host AI rule: 确认最近 release/tag 和 README 安装命令是否一致。\n- Why it matters: 安装命令和文档可能落后于代码，用户踩坑概率升高。\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch | release_recency=unknown\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n",
      "summary": "给宿主 AI 的上下文和工作边界。",
      "title": "AI Context Pack / 带给我的 AI"
    },
    "boundary_risk_card": {
      "asset_id": "boundary_risk_card",
      "filename": "BOUNDARY_RISK_CARD.md",
      "markdown": "# Boundary & Risk Card / 安装前决策卡\n\n项目：elastic/mcp-server-elasticsearch\n\n## Doramagic 试用结论\n\n当前结论：可以进入发布前推荐检查；首次使用仍应从最小权限、临时目录和可回滚配置开始。\n\n## 用户现在可以做\n\n- 可以先阅读 Human Manual，理解项目目的和主要工作流。\n- 可以复制 Prompt Preview 做安装前体验；这只验证交互感，不代表真实运行。\n- 可以把官方 Quick Start 命令放到隔离环境中验证，不要直接进主力环境。\n\n## 现在不要做\n\n- 不要把 Prompt Preview 当成项目实际运行结果。\n- 不要把 metadata-only validation 当成沙箱安装验证。\n- 不要把未验证能力写成“已支持、已跑通、可放心安装”。\n- 不要在首次试用时交出生产数据、私人文件、真实密钥或主力配置目录。\n\n## 安装前检查\n\n- 宿主 AI 是否匹配：mcp_host, claude, cursor\n- 官方安装入口状态：已发现官方入口\n- 是否在临时目录、临时宿主或容器中验证：必须是\n- 是否能回滚配置改动：必须能\n- 是否需要 API Key、网络访问、读写文件或修改宿主配置：未确认前按高风险处理\n- 是否记录了安装命令、实际输出和失败日志：必须记录\n\n## 当前阻塞项\n\n- 无阻塞项。\n\n## 项目专属踩坑\n\n- 依赖 Docker 环境（medium）：非工程用户可能没有 Docker，启动成本明显增加。 建议检查：标注 Docker 前置条件，并提供非 Docker 路径或失败提示。\n- 来源证据：Dependency Dashboard（medium）：可能阻塞安装或首次运行。 建议检查：来源问题仍为 open，Pack Agent 需要复核是否仍影响当前版本。\n- 可能修改宿主 AI 配置（medium）：安装可能改变本机 AI 工具行为，用户需要知道写入位置和回滚方法。 建议检查：列出会写入的配置文件、目录和卸载/回滚步骤。\n- 能力判断依赖假设（medium）：假设不成立时，用户拿不到承诺的能力。 建议检查：将假设转成下游验证清单。\n- 维护活跃度未知（medium）：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n\n## 风险与权限提示\n\n- no_demo: medium\n\n## 证据缺口\n\n- 暂未发现结构化证据缺口。\n",
      "summary": "安装、权限、验证和推荐前风险。",
      "title": "Boundary & Risk Card / 边界与风险卡"
    },
    "human_manual": {
      "asset_id": "human_manual",
      "filename": "HUMAN_MANUAL.md",
      "markdown": "# https://github.com/elastic/mcp-server-elasticsearch Project Manual\n\nGenerated at: 2026-05-31 01:04:06 UTC\n\n## Table of Contents\n\n- [Project Introduction](#page-project-introduction)\n- [Available MCP Tools](#page-available-tools)\n- [System Architecture](#page-architecture)\n- [MCP Protocol Configuration](#page-protocols)\n- [Docker Deployment](#page-deployment)\n- [Authentication and Security](#page-authentication)\n- [Configuration Reference](#page-configuration-reference)\n- [Troubleshooting Guide](#page-troubleshooting)\n- [Monitoring and Health Checks](#page-monitoring)\n- [Contributing Guide](#page-contributing)\n\n<a id='page-project-introduction'></a>\n\n## Project Introduction\n\n### Related Pages\n\nRelated topics: [System Architecture](#page-architecture), [Available MCP Tools](#page-available-tools), [Docker Deployment](#page-deployment)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n- [catalog-info.yaml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/catalog-info.yaml)\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)\n- [renovate.json](https://github.com/elastic/mcp-server-elasticsearch/blob/main/renovate.json)\n- [NOTICE.txt](https://github.com/elastic/mcp-server-elasticsearch/blob/main/NOTICE.txt)\n</details>\n\n# Project Introduction\n\n## Overview\n\nThe 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.\n\nSource: [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n\n### Deprecation Notice\n\n> [!CAUTION]\n> This MCP server is deprecated and will only receive critical security updates going forward. It has been superseded by the [Elastic Agent Builder](https://ela.st/agent-builder-docs) [MCP endpoint](https://ela.st/agent-builder-mcp), which is available in Elastic 9.2.0+ and Elasticsearch Serverless projects.\n\nSource: [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n\n## Project Metadata\n\nThe project is classified as a beta-stage library owned by the DevTools team at Elastic.\n\n| Attribute | Value |\n|-----------|-------|\n| **Project Name** | mcp-server-elasticsearch |\n| **Type** | Library (MCP Server) |\n| **Lifecycle** | Beta |\n| **Owner** | group:devtools-team |\n| **CI/CD** | Buildkite Pipeline |\n| **Copyright** | Copyright 2025 Elasticsearch B.V. |\n\nSource: [catalog-info.yaml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/catalog-info.yaml)\n\n## Architecture\n\n### High-Level Architecture\n\n```mermaid\ngraph TD\n    A[AI Agent / MCP Client] -->|MCP Protocol| B[MCP Server]\n    B --> C[Elasticsearch Cluster]\n    \n    subgraph \"MCP Server Components\"\n        D[CLI Layer<br/>stdio/http] --> E[Protocol Handler]\n        E --> F[Tool Router]\n        F --> G[Elasticsearch Client]\n    end\n    \n    subgraph \"Tools\"\n        H[list_indices]\n        I[get_mappings]\n        J[search]\n        K[esql]\n        L[get_shards]\n        M[Custom Tools]\n    end\n    \n    G --> H\n    G --> I\n    G --> J\n    G --> K\n    G --> L\n    G --> M\n```\n\n### Server Modes\n\nThe MCP server supports two primary transport modes:\n\n| Mode | Description | Use Case |\n|------|-------------|----------|\n| **Stdio** | Standard input/output communication | Local MCP clients, Claude Desktop, Cursor |\n| **HTTP/SSE** | HTTP with Server-Sent Events | Remote deployment, web-based clients, n8n integration |\n\nSource: [src/cli.rs:19-35](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n### Configuration Structure\n\n```mermaid\ngraph LR\n    A[Config File<br/>JSON5] --> B[Interpolator]\n    B --> C[Configuration]\n    \n    subgraph \"Elasticsearch Config\"\n        D[url]\n        E[api_key]\n        F[username/password]\n        G[ssl_skip_verify]\n    end\n    \n    subgraph \"MCP Servers Config\"\n        H[Stdio servers]\n        I[Streamable HTTP servers]\n        J[SSE servers]\n    end\n```\n\nSource: [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs) and [src/cli.rs:63-80](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n## Core Components\n\n### ElasticsearchMcpConfig\n\nThe main configuration struct for the Elasticsearch MCP server.\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `url` | `String` | Required | Cluster URL |\n| `api_key` | `Option<String>` | None | API key authentication |\n| `username` | `Option<String>` | None | Username for basic auth |\n| `password` | `Option<String>` | None | Password for basic auth |\n| `ssl_skip_verify` | `bool` | `false` | Skip SSL certificate verification |\n| `tools` | `Tools` | Empty | Custom tools configuration |\n| `prompts` | `Vec<String>` | Empty | Prompts to expose |\n\nSource: [src/servers/elasticsearch/mod.rs:64-85](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\n### EsClientProvider\n\nA wrapper around the Elasticsearch client that provides request-context-aware client instances.\n\n```rust\npub struct EsClientProvider(Elasticsearch);\n```\n\nThe provider supports authentication via:\n- **API Key**: `Credentials::EncodedApiKey(api_key)`\n- **Basic Auth**: `Credentials::Basic(username, password)`\n- **Per-request Auth**: Extracts `Authorization` header from incoming HTTP requests\n\nSource: [src/servers/elasticsearch/mod.rs:88-106](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\n## Available Tools\n\n### Base Tools\n\n| Tool | Description | Read Only |\n|------|-------------|-----------|\n| `list_indices` | List all available Elasticsearch indices | Yes |\n| `get_mappings` | Retrieve index mappings | Yes |\n| `search` | Perform Elasticsearch query DSL search | Yes |\n| `esql` | Execute ES|QL queries | Yes |\n| `get_shards` | Get shard information for indices | Yes |\n\nSource: [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n\n### Custom Tools\n\nThe server supports extensible custom tools through the `Tools` struct:\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `incl_excl` | `Option<IncludeExclude>` | Include/exclude filter for tools |\n| `custom` | `HashMap<String, CustomTool>` | Map of custom tool definitions |\n\nSupported custom tool types:\n\n| Type | Description |\n|------|-------------|\n| `Esql` | ES|QL query tool with configurable result format |\n| `SearchTemplate` | Search template tool (by ID or inline) |\n\nSource: [src/servers/elasticsearch/mod.rs:1-65](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\n### ES|QL Result Formats\n\n| Format | Description |\n|--------|-------------|\n| `json` (default) | Output as JSON array or single object |\n| `value` | If single object with single property, output only value |\n\nSource: [src/servers/elasticsearch/mod.rs:28-34](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\n## Data Models\n\n### Search Result\n\n```rust\npub struct SearchResult {\n    pub hits: Hits,\n    #[serde(default)]\n    pub aggregations: IndexMap<String, Value>,\n}\n\npub struct Hits {\n    pub total: Option<TotalHits>,\n    pub hits: Vec<Hit>,\n}\n\npub struct TotalHits {\n    pub value: u64,\n}\n\npub struct Hit {\n    #[serde(rename = \"_source\")]\n    pub source: Value,\n}\n```\n\nSource: [src/servers/elasticsearch/base_tools.rs:100-122](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n\n### ES|QL Response\n\n```rust\npub struct EsqlQueryResponse {\n    pub is_partial: Option<bool>,\n    pub columns: Vec<Column>,\n    pub values: Vec<Vec<Value>>,\n}\n\npub struct Column {\n    pub name: String,\n    #[serde(rename = \"type\")]\n    pub type_: String,\n}\n```\n\nSource: [src/servers/elasticsearch/base_tools.rs:155-169](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n\n## Transport Protocols\n\n### Stdio Transport\n\nUsed for local MCP client connections. Compatible with Claude Desktop, Cursor, and VS Code.\n\n```json\n{\n  \"mcpServers\": {\n    \"elasticsearch\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@elastic/mcp-server-elasticsearch\"]\n    }\n  }\n}\n```\n\nSource: [src/cli.rs:42-55](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n### HTTP Transport\n\nHTTP server with optional SSE support for remote deployments.\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/` | GET | Hello endpoint |\n| `/ping` | GET | Health check |\n| `/ready` | GET | Readiness probe |\n| `/live` | GET | Liveness probe |\n| `/mcp/sse` | GET | SSE endpoint |\n| `/mcp` | POST | MCP JSON-RPC handler |\n\nSource: [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n\n## Environment Variable Interpolation\n\nThe configuration file supports environment variable interpolation using `${VAR}` or `${VAR:default}` syntax.\n\n```rust\nfn interpolate(name: String, lookup: impl Fn(&str) -> Option<String>) \n    -> Result<String, InterpolationError>\n```\n\n| Syntax | Behavior |\n|--------|----------|\n| `${VAR}` | Required - fails if not defined |\n| `${VAR:default}` | Optional - uses default if not defined |\n\nSource: [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)\n\n## CLI Commands\n\n### Stdio Command\n\n```bash\nmcp-server-elasticsearch stdio --config <path>\n```\n\nSource: [src/cli.rs:36-41](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n### HTTP Command\n\n```bash\nmcp-server-elasticsearch http [OPTIONS]\n```\n\n| Option | Environment Variable | Default |\n|--------|---------------------|---------|\n| `--config <path>` | - | None |\n| `--address <ip:port>` | `HTTP_ADDRESS` | `127.0.0.1:8080` |\n| `--sse` | - | Disabled |\n\nSource: [src/cli.rs:19-33](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n## Dependency Management\n\nThe project uses Renovate for automated dependency updates.\n\n| Setting | Value |\n|---------|-------|\n| Schema | `https://docs.renovatebot.com/renovate-schema.json` |\n| Base Config | `local>elastic/renovate-config` |\n| Schedule | `after 1am on monday` |\n| Status | Rate-limited |\n\nSource: [renovate.json](https://github.com/elastic/mcp-server-elasticsearch/blob/main/renovate.json)\n\n## Known Issues\n\n### Community-Reported Issues\n\n| Issue | Description |\n|-------|-------------|\n| #185 | `get_mappings` tool fails with \"error decoding response body\" when nested type is omitted in properties |\n| #170 | Basic auth failed - 401 Unauthorized despite correct credentials |\n| #191 | Missing Linux ARM64 binary releases |\n| #17 | Request for streamable HTTP transport support |\n\nSource: [GitHub Issues](https://github.com/elastic/mcp-server-elasticsearch/issues)\n\n## Quick Reference\n\n### Minimum Requirements\n\n- Elasticsearch cluster (version 8.x or 9.x)\n- Authentication credentials (API key or username/password)\n- Docker (for container deployment)\n- MCP-compatible client\n\n### Default Configuration\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL:}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n  }\n}\n```\n\nSource: [src/lib.rs:36-45](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n### Version History\n\n| Version | Key Changes |\n|---------|-------------|\n| v0.4.6 | Deprecation notice added |\n| v0.4.5 | ENV name fix for username |\n| v0.4.4 | CA certificates added |\n| v0.4.3 | Default port set to 8080 |\n| v0.4.2 | Default port changed to 8000 |\n| v0.3.1 | Hashbang fix for npx execution |\n| v0.3.0 | OpenTelemetry support, aggregation results |\n| v0.2.0 | `get_shards` tool added |\n\nSource: [GitHub Releases](https://github.com/elastic/mcp-server-elasticsearch/releases)\n\n---\n\n<a id='page-available-tools'></a>\n\n## Available MCP Tools\n\n### Related Pages\n\nRelated topics: [System Architecture](#page-architecture), [Troubleshooting Guide](#page-troubleshooting)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n</details>\n\n# Available MCP Tools\n\nThe 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.\n\n## Overview\n\nThe 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.\n\n```mermaid\ngraph TD\n    A[MCP Client] -->|tool_request| B[EsBaseTools]\n    B --> C[Elasticsearch Cluster]\n    \n    subgraph Tools\n        D[list_indices]\n        E[get_mappings]\n        F[search]\n        G[esql]\n        H[get_shards]\n    end\n    \n    C -->|response| B\n    B -->|tool_result| A\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:30-36](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L30-L36)\n\n## Core Tools\n\nCore tools are built-in MCP tools that provide fundamental Elasticsearch operations. They are implemented in `EsBaseTools` and registered via the `#[tool_router]` macro.\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:1-40](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L1-L40)\n\n### list_indices\n\nLists all available Elasticsearch indices matching a specified pattern.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `index_pattern` | String | Yes | Index pattern to filter indices (e.g., `*`, `logs-*`) |\n\n**Implementation Details:**\n\nThe tool uses the Elasticsearch `_cat/indices` API with JSON response format, requesting the `index`, `status`, and `docs.count` fields.\n\n```rust\n#[tool(\n    description = \"List all available Elasticsearch indices\",\n    annotations(title = \"List ES indices\", read_only_hint = true)\n)]\nasync fn list_indices(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(ListIndicesParams { index_pattern }): Parameters<ListIndicesParams>,\n) -> Result<CallToolResult, rmcp::Error>\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:70-92](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L70-L92)\n\n### get_mappings\n\nRetrieves field mappings for a specific Elasticsearch index.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `index` | String | Yes | Name of the Elasticsearch index |\n\n**Implementation Details:**\n\nThe tool calls the `_mapping` endpoint for the specified index and returns the complete mapping definition.\n\n```rust\n#[tool(\n    description = \"Get field mappings for a specific Elasticsearch index\",\n    annotations(title = \"Get ES index mappings\", read_only_hint = true)\n)]\nasync fn get_mappings(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(GetMappingsParams { index }): Parameters<GetMappingsParams>,\n) -> Result<CallToolResult, rmcp::Error>\n```\n\n**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](https://github.com/elastic/mcp-server-elasticsearch/issues/185).\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:95-115](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L95-L115)\n\n### search\n\nPerforms an Elasticsearch search using the Query DSL.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `index` | String | Yes | Name of the Elasticsearch index to search |\n| `fields` | `Vec<String>` | No | Specific fields to return, augments `_source` |\n| `query_body` | `Map<String, Value>` | Yes | Complete Elasticsearch query DSL object |\n\n**Implementation Details:**\n\nThe 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.\n\nThe response includes both search hits and aggregations:\n\n```rust\n#[derive(Serialize, Deserialize)]\npub struct SearchResult {\n    pub hits: Hits,\n    #[serde(default)]\n    pub aggregations: IndexMap<String, Value>,\n}\n```\n\n```rust\n#[tool(\n    description = \"Perform an Elasticsearch search with the provided query DSL.\",\n    annotations(title = \"Elasticsearch search DSL query\", read_only_hint = true)\n)]\nasync fn search(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(SearchParams {\n        index,\n        fields,\n        query_body,\n    }): Parameters<SearchParams>,\n) -> Result<CallToolResult, rmcp::Error>\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:118-165](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L118-L165)\n\n### esql\n\nExecutes an ES|QL query against Elasticsearch.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `query` | String | Yes | Complete ES|QL query |\n\n**Response Formats:**\n\nThe tool supports different output formats configured via the `format` parameter:\n\n| Format | Description |\n|--------|-------------|\n| `json` (default) | Output as JSON array of objects or single object |\n| `value` | If single object with single property, output only its value |\n\n**Source:** [src/servers/elasticsearch/mod.rs:40-55](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L40-L55)\n\n### get_shards\n\nRetrieves shard allocation information for all or specific indices.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `index` | `Option<String>` | No | Optional index name to filter shards |\n\n**Implementation Details:**\n\nThe tool uses the Elasticsearch `_cat/shards` API with JSON format, requesting `index`, `shard`, `prirep`, `state`, `docs`, `store`, and `node` fields.\n\n```rust\n#[tool(\n    description = \"Get shard information for all or specific indices.\",\n    annotations(title = \"Get ES shard information\", read_only_hint = true)\n)]\nasync fn get_shards(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(GetShardsParams { index }): Parameters<GetShardsParams>,\n) -> Result<CallToolResult, rmcp::Error>\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:168-200](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L168-L200)\n\n## Custom Tools\n\nCustom 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.\n\n**Source:** [src/servers/elasticsearch/mod.rs:15-30](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L15-L30)\n\n### Tool Definition Structure\n\n```rust\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(tag = \"type\", rename_all = \"snake_case\")]\npub enum CustomTool {\n    Esql(EsqlTool),\n    SearchTemplate(SearchTemplateTool),\n}\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct ToolBase {\n    pub description: String,\n    pub parameters: IndexMap<String, schemars::schema::SchemaObject>,\n    pub annotations: Option<ToolAnnotations>,\n}\n```\n\n### EsqlTool\n\nPre-configured ES|QL queries that can be exposed as tools. Includes a base definition with description, parameters schema, and the query to execute.\n\n**Source:** [src/servers/elasticsearch/mod.rs:32-55](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L32-L55)\n\n### SearchTemplateTool\n\nPre-configured search templates that accept parameters at runtime. Supports two template specification modes:\n\n| Mode | Description |\n|------|-------------|\n| `template_id` | Reference an existing saved search template by ID |\n| `template` | Inline template definition as JSON |\n\n**Source:** [src/servers/elasticsearch/mod.rs:57-72](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L57-L72)\n\n## Tool Configuration\n\nTools are configured in the server configuration file under the `tools` section:\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY}\"\n  },\n  \"tools\": {\n    \"incl_excl\": {\n      \"include\": [\"custom_tool_1\"],\n      \"exclude\": [\"custom_tool_2\"]\n    },\n    \"custom\": {\n      \"my_esql_query\": {\n        \"type\": \"esql\",\n        \"description\": \"Count documents by status\",\n        \"parameters\": {},\n        \"query\": \"FROM my-index | STATS count = COUNT(*)\"\n      }\n    }\n  }\n}\n```\n\n**Source:** [src/lib.rs:45-65](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs#L45-L65)\n\n## Server Capabilities\n\nEach tool set reports its capabilities through the `get_info()` method:\n\n```rust\nfn get_info(&self) -> ServerInfo {\n    ServerInfo {\n        protocol_version: ProtocolVersion::V_2025_03_26,\n        capabilities: ServerCapabilities::builder().enable_tools().build(),\n        server_info: Implementation::from_build_env(),\n        instructions: Some(\"Provides access to Elasticsearch\".to_string()),\n    }\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:27-36](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs#L27-L36)\n\n## Transport Support\n\nTools can be accessed through multiple transport protocols:\n\n| Transport | Description | Use Case |\n|-----------|-------------|----------|\n| `stdio` | Direct process communication | Local clients, Claude Desktop |\n| `streamable-http` | HTTP-based with session support | Web integrations, remote access |\n| `sse` | Server-Sent Events (deprecated) | Legacy compatibility |\n\n**Source:** [src/cli.rs:20-35](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs#L20-L35)\n\n## Response Structure\n\nAll tools return results wrapped in `CallToolResult`:\n\n```rust\nOk(CallToolResult::success(vec![\n    Content::text(format!(\"Found {} indices:\", response.len())),\n    Content::json(response)?,\n]))\n```\n\nThe server returns:\n- Text summary with counts or status\n- JSON content with the full response data\n\n## Community Considerations\n\nWhen using these tools, be aware of the following community-reported issues:\n\n- **Aggregation results in search**: Some agents may not receive aggregation results properly. The [enhancement request #45](https://github.com/elastic/mcp-server-elasticsearch/issues/45) tracks improvements to aggregation handling.\n- **get_mappings with nested types**: Valid Elasticsearch mappings with implicit nested types may cause decoding errors. See [issue #185](https://github.com/elastic/mcp-server-elasticsearch/issues/185).\n- **HTTP transport limitations**: When accessing via HTTP/SSE, certain tool combinations may return errors. This is discussed in [issue #173](https://github.com/elastic/mcp-server-elasticsearch/issues/173).\n\n---\n\n<a id='page-architecture'></a>\n\n## System Architecture\n\n### Related Pages\n\nRelated topics: [MCP Protocol Configuration](#page-protocols), [Available MCP Tools](#page-available-tools)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)\n- [catalog-info.yaml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/catalog-info.yaml)\n</details>\n\n# System Architecture\n\n## Overview\n\nThe 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.\n\n**Project Type:** Library component (Backstage classification)  \n**Owner:** devtools-team  \n**Lifecycle:** Beta (deprecated as of v0.4.6)  \n**Source:** [catalog-info.yaml:1-56]()\n\n## High-Level Architecture\n\nThe server follows a layered architecture with distinct separation between transport handling, protocol implementation, and tool execution:\n\n```mermaid\ngraph TD\n    subgraph Transport Layer\n        STDIOC[Stdio Transport]\n        HTTPC[HTTP Transport]\n        SSEC[SSE Transport]\n    end\n    \n    subgraph Protocol Layer\n        MCP[Model Context Protocol]\n    end\n    \n    subgraph Server Layer\n        ESMC[ElasticsearchMcp]\n        BASET[EsBaseTools]\n    end\n    \n    subgraph Tools\n        SEARCH[search]\n        LISTIDX[list_indices]\n        GETMAP[get_mappings]\n        GETSHARDS[get_shards]\n        ESQL[esql]\n    end\n    \n    subgraph Elasticsearch\n        ES[Elasticsearch Cluster]\n    end\n    \n    STDIOC --> MCP\n    HTTPC --> MCP\n    SSEC --> MCP\n    MCP --> ESMC\n    ESMC --> BASET\n    BASET --> SEARCH\n    BASET --> LISTIDX\n    BASET --> GETMAP\n    BASET --> GETSHARDS\n    BASET --> ESQL\n    SEARCH --> ES\n    LISTIDX --> ES\n    GETMAP --> ES\n    GETSHARDS --> ES\n    ESQL --> ES\n```\n\n## Transport Layer\n\nThe server supports multiple transport mechanisms, configurable via command-line arguments:\n\n### Stdio Transport\n\nThe default transport mode for local MCP client integrations. Communicates via standard input/output streams using JSON-RPC messages.\n\n```rust\npub enum Command {\n    Stdio(StdioCommand),\n    Http(HttpCommand),\n}\n\npub struct StdioCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n}\n```\n\n**Source:** [src/cli.rs:19-29]()\n\n### HTTP Transport\n\nSupports remote deployments with optional Server-Sent Events (SSE) fallback:\n\n```rust\npub struct HttpCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n\n    /// Address to listen to [default: 127.0.0.1:8080]\n    #[clap(long, value_name = \"IP_ADDRESS:PORT\", env = \"HTTP_ADDRESS\")]\n    pub address: Option<std::net::SocketAddr>,\n\n    /// Also start an SSE server on '/sse'\n    #[clap(long)]\n    pub sse: bool,\n}\n```\n\n| Parameter | Type | Default | Environment Variable |\n|-----------|------|---------|---------------------|\n| config | PathBuf | None | - |\n| address | SocketAddr | 127.0.0.1:8080 | HTTP_ADDRESS |\n| sse | bool | false | - |\n\n**Source:** [src/cli.rs:31-47]()\n\n### Runtime Entry Points\n\nThe CLI determines which transport to initialize based on the subcommand:\n\n```rust\npub async fn run_stdio(cmd: StdioCommand, container_mode: bool) -> anyhow::Result<()> {\n    tracing::info!(\"Starting stdio server\");\n    let handler = setup_services(&cmd.config, container_mode).await?;\n    let service = handler.serve(stdio()).await.inspect_err(|e| {\n        tracing::error!(\"serving error: {:?}\", e);\n    })?;\n    // ...\n}\n\npub async fn run_http(cmd: HttpCommand, container_mode: bool) -> anyhow::Result<()> {\n    let handler = setup_services(&cmd.config, container_mode).await?;\n    let server_provider = move || handler.clone();\n    // ...\n}\n```\n\n**Source:** [src/lib.rs:1-100]()\n\n## Configuration System\n\n### Configuration Structure\n\nThe server uses JSON5 format for configuration files, with support for comments and environment variable interpolation:\n\n```rust\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct Configuration {\n    pub elasticsearch: elasticsearch::ElasticsearchMcpConfig,\n    #[serde(default)]\n    pub mcp_servers: HashMap<String, McpServer>,\n}\n```\n\n**Source:** [src/cli.rs:104-111]()\n\n### Elasticsearch Configuration\n\n```rust\npub struct ElasticsearchMcpConfig {\n    /// Cluster URL\n    pub url: String,\n\n    /// API key\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub api_key: Option<String>,\n\n    /// Username\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub username: Option<String>,\n\n    /// Password\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub password: Option<String>,\n\n    /// Should we skip SSL certificate verification?\n    #[serde(default, deserialize_with = \"deserialize_bool_from_anything\")]\n    pub ssl_skip_verify: bool,\n\n    /// Search templates to expose as tools or resources\n    #[serde(default)]\n    pub tools: Tools,\n\n    /// Prompts\n    #[serde(default)]\n    pub prompts: Vec<String>,\n}\n```\n\n| Parameter | Required | Default | Environment Variable |\n|-----------|----------|---------|---------------------|\n| url | Yes | - | ES_URL |\n| api_key | No | - | ES_API_KEY |\n| username | No | - | ES_USERNAME |\n| password | No | - | ES_PASSWORD |\n| ssl_skip_verify | No | false | ES_SSL_SKIP_VERIFY |\n\n**Source:** [src/servers/elasticsearch/mod.rs:1-100]()\n\n### Environment Variable Interpolation\n\nThe configuration parser supports `${VAR_NAME}` and `${VAR_NAME:default_value}` syntax:\n\n```rust\nfn expand(name: &str) -> Result<String, InterpolationError> {\n    let lookup = |s: &str| match s {\n        \"foo\" => Some(\"foo_value\".to_string()),\n        \"bar\" => Some(\"bar_value\".to_string()),\n        _ => None,\n    };\n    interpolate(name.to_string(), lookup)\n}\n```\n\n**Source:** [src/utils/interpolator.rs:1-50]()\n\n## Core Server Components\n\n### ElasticsearchMcp Server\n\nThe main server implementation wraps the Elasticsearch client and provides tool routing:\n\n```rust\npub struct ElasticsearchMcp {}\n\nimpl ElasticsearchMcp {\n    pub fn new_with_config(\n        config: ElasticsearchMcpConfig, \n        container_mode: bool\n    ) -> anyhow::Result<base_tools::EsBaseTools> {\n        let creds = if let Some(api_key) = config.api_key.clone() {\n            Some(Credentials::EncodedApiKey(api_key))\n        } else if let Some(username) = config.username.clone() {\n            let pwd = config.password.clone().ok_or(anyhow::Error::msg(\"missing password\"))?;\n            Some(Credentials::Basic(username, pwd))\n        } else {\n            None\n        };\n\n        let url = config.url.as_str();\n        if url.is_empty() {\n            return Err(anyhow::Error::msg(\"Elasticsearch URL is empty\"));\n        }\n\n        let mut url = Url::parse(url)?;\n        if container_mode {\n            rewrite_localhost(&mut url)?;\n        }\n\n        let pool = elasticsearch::http::transport::SingleNodeConnectionPool::new(url.clone());\n        let mut transport = elasticsearch::http::transport::TransportBuilder::new(pool);\n        if let Some(creds) = creds {\n            transport = transport.auth(creds);\n        }\n        // ...\n    }\n}\n```\n\n**Source:** [src/servers/elasticsearch/mod.rs:1-100]()\n\n### EsClientProvider\n\nA wrapper around the Elasticsearch client that supports per-request authentication:\n\n```rust\n#[derive(Clone)]\npub struct EsClientProvider(Elasticsearch);\n\nimpl EsClientProvider {\n    pub fn new(client: Elasticsearch) -> Self {\n        EsClientProvider(client)\n    }\n\n    /// If the incoming request is a http request and has an `Authorization` header, use it\n    /// to authenticate to the remote ES instance.\n    pub fn get(&self, context: RequestContext<RoleServer>) -> Elasticsearch {\n        // Authentication context handling\n    }\n}\n```\n\n**Source:** [src/servers/elasticsearch/mod.rs:100-150]()\n\n### EsBaseTools\n\nThe core tool provider implementing the MCP tool protocol:\n\n```rust\n#[derive(Clone)]\npub struct EsBaseTools {\n    es_client: EsClientProvider,\n    tool_router: ToolRouter<EsBaseTools>,\n}\n\nimpl EsBaseTools {\n    pub fn new(es_client: Elasticsearch) -> Self {\n        Self {\n            es_client: EsClientProvider::new(es_client),\n            tool_router: Self::tool_router(),\n        }\n    }\n}\n\n#[tool_handler]\nimpl ServerHandler for EsBaseTools {\n    fn get_info(&self) -> ServerInfo {\n        ServerInfo {\n            protocol_version: ProtocolVersion::V_2025_03_26,\n            capabilities: ServerCapabilities::builder().enable_tools().build(),\n            server_info: Implementation::from_build_env(),\n            instructions: Some(\"Provides access to Elasticsearch\".to_string()),\n        }\n    }\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:1-100]()\n\n## Tool System\n\n### Available Tools\n\n| Tool | Description | Read Only |\n|------|-------------|-----------|\n| list_indices | List all available Elasticsearch indices | Yes |\n| get_mappings | Retrieve index mappings | Yes |\n| get_shards | Get shard information for indices | Yes |\n| search | Perform Elasticsearch search with Query DSL | Yes |\n| esql | Execute ES\\|QL queries | Yes |\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:100-200]()\n\n### Tool Parameter Definitions\n\n```rust\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct ListIndicesParams {\n    /// Index pattern of Elasticsearch indices to list\n    pub index_pattern: String,\n}\n\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct GetMappingsParams {\n    /// Name of the Elasticsearch index to get mappings for\n    index: String,\n}\n\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct SearchParams {\n    /// Name of the Elasticsearch index to search\n    index: String,\n\n    /// Name of the fields that need to be returned (optional)\n    fields: Option<Vec<String>>,\n\n    /// Complete Elasticsearch query DSL object that can include query, size, from, sort, etc.\n    query_body: Map<String, Value>,\n}\n\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct EsqlQueryParams {\n    /// Complete Elasticsearch ES|QL query\n    query: String,\n}\n\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct GetShardsParams {\n    /// Optional index name to get shard information for\n    index: Option<String>,\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:100-200]()\n\n### Custom Tools\n\nThe server supports extensible custom tools via configuration:\n\n```rust\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(tag = \"type\", rename_all = \"snake_case\")]\npub enum CustomTool {\n    Esql(EsqlTool),\n    SearchTemplate(SearchTemplateTool),\n}\n\npub struct EsqlTool {\n    #[serde(flatten)]\n    base: ToolBase,\n    query: String,\n    #[serde(default)]\n    format: EsqlResultFormat,\n}\n\n#[derive(Debug, Serialize, Deserialize, Default)]\n#[serde(rename_all = \"snake_case\")]\npub enum EsqlResultFormat {\n    #[default]\n    Json,\n    Value,\n}\n```\n\n**Source:** [src/servers/elasticsearch/mod.rs:20-50]()\n\n## Data Models\n\n### Search Response\n\n```rust\n#[derive(Serialize, Deserialize)]\npub struct SearchResult {\n    pub hits: Hits,\n    #[serde(default)]\n    pub aggregations: IndexMap<String, Value>,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct Hits {\n    pub total: Option<TotalHits>,\n    pub hits: Vec<Hit>,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct TotalHits {\n    pub value: u64,\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:50-70]()\n\n### Index Mappings Response\n\n```rust\npub type MappingResponse = HashMap<String, Mappings>;\n\n#[derive(Serialize, Deserialize)]\npub struct Mappings {\n    pub mappings: Mapping,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct Mapping {\n    #[serde(rename = \"_meta\", skip_serializing_if = \"Option::is_none\")]\n    pub meta: Option<JsonObject>,\n    properties: HashMap<String, MappingProperty>,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct MappingProperty {\n    #[serde(rename = \"type\")]\n    pub type_: String,\n    #[serde(flatten)]\n    pub settings: HashMap<String, serde_json::Value>,\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:100-130]()\n\n### ES|QL Response\n\n```rust\n#[derive(Serialize, Deserialize)]\npub struct EsqlQueryResponse {\n    pub is_partial: Option<bool>,\n    pub columns: Vec<Column>,\n    pub values: Vec<Vec<Value>>,\n}\n\n#[derive(Serialize, Deserialize)]\npub struct Column {\n    pub name: String,\n    #[serde(rename = \"type\")]\n    pub type_: String,\n}\n```\n\n**Source:** [src/servers/elasticsearch/base_tools.rs:130-150]()\n\n## Server Initialization Flow\n\n```mermaid\nsequenceDiagram\n    participant CLI as Command Line\n    participant Config as Config Loader\n    participant Interpolator as Env Interpolator\n    participant Server as ElasticsearchMcp\n    participant Transport as MCP Transport\n    \n    CLI->>Config: Load config file\n    Config->>Interpolator: Expand ${VAR} placeholders\n    Interpolator->>Config: Expanded config\n    Config->>Server: Parse JSON5\n    Server->>Server: Create ES client with auth\n    CLI->>Transport: Start transport (stdio/http)\n    Transport->>Server: Serve MCP requests\n```\n\n**Source:** [src/lib.rs:1-100]()\n\n## Known Limitations\n\n### Community-Reported Issues\n\n1. **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.\n\n2. **HTTP Transport Complexity (Issue #17)**: Support for streamable HTTP is a requested enhancement. Currently, the server supports stdio and HTTP/SSE transports only.\n\n3. **Basic Auth Configuration (Issue #170)**: Users have reported confusion with authentication configuration when deploying via Docker, requiring careful setup of environment variables.\n\n## Architecture Summary\n\nThe Elasticsearch MCP Server implements a clean separation of concerns:\n\n1. **Transport Layer**: Handles protocol-agnostic communication (stdio/HTTP/SSE)\n2. **Protocol Layer**: Implements MCP specification for tool discovery and invocation\n3. **Service Layer**: Manages Elasticsearch connections and authentication\n4. **Tool Layer**: Provides domain-specific tools for Elasticsearch operations\n\nThis 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.\n\n---\n\n<a id='page-protocols'></a>\n\n## MCP Protocol Configuration\n\n### Related Pages\n\nRelated topics: [Docker Deployment](#page-deployment), [System Architecture](#page-architecture)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n</details>\n\n# MCP Protocol Configuration\n\n## Overview\n\nThe 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](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n\nThe 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.\n\n---\n\n## Protocol Types\n\nThe server supports three transport protocols, defined as an enum in the CLI module:\n\n| Protocol | Description | Use Case |\n|----------|-------------|----------|\n| `Stdio` | Direct stdin/stdout communication | Local MCP clients (Claude Desktop, Cursor, VS Code) |\n| `StreamableHttp` | HTTP-based streaming protocol | Web integrations, remote access, concurrent clients |\n| `Sse` | Server-Sent Events (deprecated) | Legacy HTTP support |\n\nSource: [src/cli.rs:28-33](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n### Configuration Structure\n\n```rust\n#[derive(Debug, Serialize, Deserialize)]\n#[serde(rename_all = \"kebab-case\")]\n#[serde(tag = \"type\")]\npub enum McpServer {\n    Sse(Http),\n    StreamableHttp(Http),\n    Stdio(Stdio),\n}\n```\n\n#### Stdio Configuration\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `command` | String | Yes | Command to run (e.g., \"npx\", \"docker\") |\n| `args` | Vec<String> | Yes | Command arguments |\n| `env` | HashMap<String, String> | No | Environment variables |\n\nSource: [src/cli.rs:6-14](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n#### HTTP Configuration\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `url` | String | Yes | URL of the server |\n| `headers` | HashMap<String, String> | No | HTTP headers to send with requests |\n\nSource: [src/cli.rs:17-25](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n---\n\n## CLI Commands\n\nThe server provides two main command variants for starting the server:\n\n```rust\n#[derive(Debug, Subcommand)]\npub enum Command {\n    Stdio(StdioCommand),\n    Http(HttpCommand),\n}\n```\n\nSource: [src/cli.rs:45-49](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n### Stdio Command\n\n```rust\n#[derive(Debug, Args)]\npub struct StdioCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n}\n```\n\nSource: [src/cli.rs:57-62](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n**Usage:**\n\n```bash\ndocker run -i --rm \\\n  -e ES_URL \\\n  -e ES_API_KEY \\\n  docker.elastic.co/mcp/elasticsearch \\\n  stdio\n```\n\n### HTTP Command\n\n```rust\n#[derive(Debug, Args)]\npub struct HttpCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n\n    /// Address to listen to [default: 127.0.0.1:8080]\n    #[clap(long, value_name = \"IP_ADDRESS:PORT\", env = \"HTTP_ADDRESS\")]\n    pub address: Option<std::net::SocketAddr>,\n\n    /// Also start an SSE server on '/sse'\n    #[clap(long)]\n    pub sse: bool,\n}\n```\n\nSource: [src/cli.rs:52-56](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n\n**Usage:**\n\n```bash\ndocker run -p 8080:8080 \\\n  -e ES_URL \\\n  -e ES_API_KEY \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --address 0.0.0.0:8080\n```\n\n---\n\n## HTTP Server Configuration\n\nThe HTTP protocol implementation provides fine-grained control over server behavior through the `HttpServerConfig` struct:\n\n```rust\npub struct HttpServerConfig<M: SessionManager = LocalSessionManager> {\n    /// TCP address to bind to\n    pub bind: SocketAddr,\n\n    /// Parent cancellation token. `serve_with_config` will return a child token\n    pub ct: CancellationToken,\n\n    /// Streamable http server option\n    pub keep_alive: Option<Duration>,\n\n    /// Streamable http server option\n    pub stateful_mode: bool,\n\n    /// Streamable http server option\n    pub session_manager: Arc<M>,\n}\n```\n\nSource: [src/protocol/http.rs:9-21](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n\n### Configuration Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `bind` | SocketAddr | 127.0.0.1:8080 | TCP address to bind to |\n| `ct` | CancellationToken | - | Parent cancellation token for graceful shutdown |\n| `keep_alive` | Option<Duration> | None | SSE keep-alive interval for connection maintenance |\n| `stateful_mode` | bool | false | Enable stateful session management |\n| `session_manager` | Arc<M> | NeverSessionManager | Session manager implementation |\n\nSource: [src/lib.rs:75-88](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n### Protocol Implementation\n\nThe `HttpProtocol` struct provides the server startup logic:\n\n```rust\npub struct HttpProtocol {}\n\nimpl HttpProtocol {\n    pub async fn serve_with_config<S: Service<RoleServer>, M: SessionManager>(\n        server_provider: impl Into<ServerProvider<S>>,\n        config: HttpServerConfig<M>,\n    ) -> std::io::Result<CancellationToken> { ... }\n}\n```\n\nSource: [src/protocol/http.rs:25-37](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n\n---\n\n## Server Setup Flow\n\nThe following diagram shows how the server initializes and configures the MCP protocol based on user input:\n\n```mermaid\ngraph TD\n    A[Start Server] --> B{Command Type?}\n    B -->|stdio| C[Initialize StdioCommand]\n    B -->|http| D[Initialize HttpCommand]\n    \n    C --> E[Read Config File]\n    D --> F[Parse CLI Args]\n    F --> G{Config File Provided?}\n    G -->|Yes| H[Load from File]\n    G -->|No| I[Use Environment Variables]\n    E --> J[setup_services]\n    H --> J\n    I --> J\n    \n    J --> K[Create ElasticsearchMcpConfig]\n    K --> L[Build ServerProvider]\n    L --> M{Protocol Type?}\n    M -->|Stdio| N[Start Stdio Server]\n    M -->|Http| O[HttpProtocol::serve_with_config]\n    \n    O --> P[Create HttpServerConfig]\n    P --> Q[Initialize StreamableHttpServer]\n    Q --> R[Bind to Address]\n    R --> S[Listen for Connections]\n```\n\n---\n\n## Configuration File Format\n\nThe server accepts JSON configuration files that can include both Elasticsearch connection settings and MCP server definitions:\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n  },\n  \"mcp_servers\": {\n    \"my-server\": {\n      \"type\": \"streamableHttp\",\n      \"url\": \"http://localhost:8080\",\n      \"headers\": {}\n    }\n  }\n}\n```\n\nSource: [src/lib.rs:95-106](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n### Environment Variable Expansion\n\nConfiguration files support environment variable interpolation using `${VAR}` or `${VAR:default}` syntax:\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `ES_URL` | Elasticsearch cluster URL | Required |\n| `ES_API_KEY` | API key for authentication | None |\n| `ES_USERNAME` | Username for basic auth | None |\n| `ES_PASSWORD` | Password for basic auth | None |\n| `ES_SSL_SKIP_VERIFY` | Skip SSL certificate verification | false |\n| `HTTP_ADDRESS` | HTTP server bind address | 127.0.0.1:8080 |\n\nSource: [src/servers/elasticsearch/mod.rs:28-46](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\n---\n\n## Available Tools\n\nRegardless of protocol configuration, the server exposes these tools to connected MCP clients:\n\n| Tool | Description | Read Only |\n|------|-------------|-----------|\n| `list_indices` | List all available Elasticsearch indices | Yes |\n| `get_mappings` | Get field mappings for a specific index | Yes |\n| `search` | Perform Elasticsearch search with Query DSL | Yes |\n| `esql` | Execute ESQL queries | No |\n| `get_shards` | Get shard information for indices | Yes |\n\nSource: [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n\n---\n\n## Deployment Considerations\n\n### Local Development\n\nFor local development with stdio protocol, use the default configuration with environment variables:\n\n```bash\nexport ES_URL=https://localhost:9200\nexport ES_API_KEY=your-api-key\ndocker run -i --rm \\\n  -e ES_URL -e ES_API_KEY \\\n  docker.elastic.co/mcp/elasticsearch \\\n  stdio\n```\n\n### Production HTTP Deployment\n\nFor production deployments requiring remote access:\n\n```bash\ndocker run -p 8080:8080 \\\n  -e ES_URL=https://your-cluster.es.amazonaws.com:9200 \\\n  -e ES_API_KEY=your-api-key \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --address 0.0.0.0:8080\n```\n\n### Address Binding Behavior\n\n| Mode | Default Address | Container Mode Default |\n|------|-----------------|------------------------|\n| HTTP | 127.0.0.1:8080 | 0.0.0.0:8080 |\n| Stdio | N/A (uses stdin/stdout) | N/A |\n\nSource: [src/lib.rs:68-76](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n---\n\n## Known Issues and Limitations\n\n### Authentication Issues\n\nIssue #170 documents cases where basic authentication fails with 401 Unauthorized despite correct credentials. Users should verify:\n\n1. `ES_USERNAME` and `ES_PASSWORD` are both set\n2. The Elasticsearch cluster supports basic authentication\n3. No conflicting authentication headers in MCP client configuration\n\n### HTTP Transport Status\n\nAs documented in Issue #17, the server previously only supported stdio mode. Streamable-HTTP support was added to address modern deployment requirements. Users requiring HTTP transport should ensure their MCP client also supports the streamable-HTTP protocol specification.\n\n---\n\n## References\n\n- [Model Context Protocol Specification](https://modelcontextprotocol.io/specification/latest/basic/transports)\n- [Streamable HTTP Transport](https://modelcontextprotocol.io/docs/concepts/transports#streamable-http)\n- [Elasticsearch MCP Server Releases](https://github.com/elastic/mcp-server-elasticsearch/releases)\n\n---\n\n<a id='page-deployment'></a>\n\n## Docker Deployment\n\n### Related Pages\n\nRelated topics: [MCP Protocol Configuration](#page-protocols), [Authentication and Security](#page-authentication), [Configuration Reference](#page-configuration-reference)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs) - Main library entry point with container mode and service setup\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs) - Command-line interface definitions\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs) - Elasticsearch server implementation\n- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md) - Main documentation with deployment instructions\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs) - Base tools implementation\n</details>\n\n# Docker Deployment\n\nThe 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.\n\n## Architecture Overview\n\nThe 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.\n\n```mermaid\ngraph TD\n    A[MCP Client] --> B{Docker Container}\n    B --> C[Elasticsearch MCP Server]\n    C --> D{Protocol Mode}\n    D -->|Stdio| E[Direct Stdio Communication]\n    D -->|HTTP| F[Streamable HTTP Endpoint]\n    F --> G[Port 8080 or 8000]\n    C --> H[Elasticsearch Cluster]\n    \n    I[Environment Variables] --> C\n    J[Config File] --> C\n```\n\n## Container Image\n\nThe 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.\n\n| Property | Value |\n|----------|-------|\n| Image Registry | `docker.elastic.co/mcp/elasticsearch` |\n| Default Port | 8080 |\n| Alternative Port | 8000 |\n| Base Image | Distroless/static (minimal attack surface) |\n| User | Non-root (security hardened) |\n\n## Environment Variables\n\nThe 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.\n\n### Authentication Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `ES_URL` | Yes | Elasticsearch cluster URL (e.g., `https://your-cluster.es.amazonaws.com:9200`) |\n| `ES_API_KEY` | Conditional | Elasticsearch API key for authentication (required if not using username/password) |\n| `ES_USERNAME` | Conditional | Username for basic authentication |\n| `ES_PASSWORD` | Conditional | Password for basic authentication |\n| `ES_SSL_SKIP_VERIFY` | No | Set to `true` to skip SSL/TLS certificate verification (not recommended for production) |\n\nSource: [src/lib.rs:setup_services()](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n### Network Variables\n\n| Variable | Description |\n|----------|-------------|\n| `HTTP_ADDRESS` | Socket address for HTTP server binding (format: `IP:PORT`) |\n| `CLI_ARGS` | Additional command-line arguments passed to the binary |\n\n## Running in Stdio Mode\n\nThe 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.\n\n### Basic Stdio Command\n\n```bash\ndocker run -i --rm \\\n  -e ES_URL=\"https://your-cluster.es.us-east-1.es.amazonaws.com:443\" \\\n  -e ES_API_KEY=\"your-api-key-here\" \\\n  docker.elastic.co/mcp/elasticsearch \\\n  stdio\n```\n\n### Claude Desktop Configuration\n\nTo integrate the MCP server with Claude Desktop, add the following configuration to your Claude Desktop settings file:\n\n```json\n{\n  \"mcpServers\": {\n    \"elasticsearch-mcp-server\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\", \"-i\", \"--rm\",\n        \"-e\", \"ES_URL\",\n        \"-e\", \"ES_API_KEY\",\n        \"docker.elastic.co/mcp/elasticsearch\",\n        \"stdio\"\n      ],\n      \"env\": {\n        \"ES_URL\": \"<elasticsearch-cluster-url>\",\n        \"ES_API_KEY\": \"<elasticsearch-api-key>\"\n      }\n    }\n  }\n}\n```\n\n## Running in HTTP Mode\n\nThe 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.\n\n### Basic HTTP Command\n\n```bash\ndocker run --rm \\\n  -e ES_URL=\"https://your-cluster.es.us-east-1.es.amazonaws.com:443\" \\\n  -e ES_API_KEY=\"your-api-key-here\" \\\n  -p 8080:8080 \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http\n```\n\n### HTTP Endpoints\n\n| Endpoint | Method | Description |\n|----------|--------|-------------|\n| `/mcp` | POST/GET | Streamable-HTTP MCP endpoint |\n| `/ping` | GET | Health check endpoint (returns `pong`) |\n\nSource: [src/lib.rs:run_http()](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n\n### HTTP-SSE Mode\n\nFor environments that require Server-Sent Events (SSE) for backwards compatibility, the HTTP server can be started with SSE support enabled:\n\n```bash\ndocker run --rm \\\n  -e ES_URL \\\n  -e ES_API_KEY \\\n  -p 8080:8080 \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --sse\n```\n\nNote that SSE is deprecated in favor of streamable-HTTP. The streamable-HTTP protocol provides better streaming support and should be preferred for new deployments.\n\n### HTTP Address Configuration\n\nBy 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:\n\n```bash\ndocker run --rm \\\n  -e ES_URL \\\n  -e ES_API_KEY \\\n  -p 0.0.0.0:8080:8080 \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --address 0.0.0.0:8080\n```\n\nThe server also respects the `HTTP_ADDRESS` environment variable for configuration.\n\n## Container Mode Host Resolution\n\nThe 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.\n\nThe following host aliases are checked in order:\n\n| Alias | Platform |\n|-------|----------|\n| `host.docker.internal` | Docker Desktop (Linux, macOS, Windows) |\n| `docker.for.host.internal` | Legacy Docker for macOS |\n| `host.containers.internal` | Podman and other container runtimes |\n\nSource: [src/servers/elasticsearch/mod.rs:container_mode()](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n\nIf `localhost` is detected and no alias resolves successfully, the server logs a warning but continues operation:\n\n```rust\ntracing::warn!(\"Container mode: could not find a replacement for 'localhost'\");\n```\n\n## Configuration File\n\nFor 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.\n\n### Example Configuration File\n\n```json5\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n  }\n}\n```\n\n### Running with Configuration File\n\n```bash\ndocker run --rm \\\n  -v /path/to/config.json:/config.json:ro \\\n  -p 8080:8080 \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --config /config.json\n```\n\nThe configuration file supports environment variable interpolation using the `${VAR}` and `${VAR:default}` syntax.\n\n## Security Considerations\n\n### Credential Handling\n\nThe Elasticsearch MCP Server follows security best practices for credential management:\n\n- **API keys and passwords**: Stored only in environment variables passed to the container. They are never persisted to disk or included in logs.\n- **Environment variables**: Set when running the container. Use secret management services like AWS Secrets Manager or AWS Systems Manager Parameter Store in production environments.\n- **Non-root user**: The container runs as a non-root user for security hardening.\n\n### Network Security\n\n| Security Feature | Implementation |\n|-----------------|----------------|\n| TLS/SSL | Enabled automatically when `ES_URL` uses `https://` |\n| Certificate Validation | Enabled by default; disabled with `ES_SSL_SKIP_VERIFY=true` |\n| Localhost Binding | HTTP server binds to `127.0.0.1:8080` by default |\n| Port Exposure | Only required ports should be exposed to the network |\n\n### Best Practices\n\n- Rotate API keys regularly (every 30-90 days for production)\n- Use API keys with minimal required permissions\n- Never commit credentials to version control\n- Use secret management services for credential storage\n- Restrict network access to the container using firewall rules\n\n## Troubleshooting\n\n### Connection Issues\n\nIf the container fails to connect to Elasticsearch, verify the following:\n\n1. **Check container logs**: View logs using `docker logs <container-id>` to identify authentication or connection errors.\n\n2. **Test Elasticsearch connectivity**: From within the container:\n   ```bash\n   docker exec <container-id> curl -k -u <username>:<password> <ES_URL>\n   ```\n   Or with an API key:\n   ```bash\n   docker exec <container-id> curl -k -H \"Authorization: ApiKey <api-key>\" <ES_URL>\n   ```\n\n3. **Verify network access**: Ensure the container can reach the Elasticsearch cluster. For cloud deployments, check security groups and network ACLs.\n\n### Authentication Failures\n\nCommon authentication issues and solutions:\n\n| Issue | Solution |\n|-------|----------|\n| 401 Unauthorized | Verify `ES_USERNAME` and `ES_PASSWORD` are correct; check for typos in environment variable names |\n| API key rejected | Ensure the API key has sufficient permissions for the operations being performed |\n| Certificate errors | If using a self-signed certificate, set `ES_SSL_SKIP_VERIFY=true` (development only) |\n\n### Port Binding Issues\n\nIf port 8080 is already in use, either stop the conflicting service or use an alternative port:\n\n```bash\ndocker run --rm \\\n  -e ES_URL \\\n  -e ES_API_KEY \\\n  -p 8081:8080 \\\n  docker.elastic.co/mcp/elasticsearch \\\n  http --address 0.0.0.0:8080\n```\n\n### Health Check Verification\n\nVerify the server is running correctly by checking the health endpoint:\n\n```bash\ncurl http://localhost:8080/ping\n```\n\nA successful response returns `pong`, indicating the server is operational.\n\n## Building the Docker Image\n\nFor development or custom deployments, you can build the Docker image locally using the provided Makefile:\n\n```bash\nmake docker-build\n```\n\nThe Makefile targets include:\n\n| Target | Description |\n|--------|-------------|\n| `docker-build` | Build the default Docker image |\n| `docker-build-8000` | Build the image with port 8000 as default |\n| `docker-push` | Push the built image to the registry |\n\n## Limitations and Known Issues\n\nThe following limitations are relevant to Docker deployment:\n\n- **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](https://github.com/elastic/mcp-server-elasticsearch/issues/185).\n\n- **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.\n\n- **ARM64 support**: The project currently publishes Linux AMD64 binaries. ARM64 support is requested by the community (issue [#191](https://github.com/elastic/mcp-server-elasticsearch/issues/191)) but not yet available.\n\n---\n\n<a id='page-authentication'></a>\n\n## Authentication and Security\n\n### Related Pages\n\nRelated topics: [Docker Deployment](#page-deployment), [Troubleshooting Guide](#page-troubleshooting)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n</details>\n\n# Authentication and Security\n\nThe 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.\n\n## Overview\n\nThe MCP server handles authentication at two distinct layers:\n\n| Layer | Purpose | Source |\n|-------|---------|--------|\n| **Server Configuration** | Establishes baseline credentials for connecting to Elasticsearch | Environment variables or config file |\n| **Per-Request Auth** | Allows MCP clients to inject authentication for specific requests | HTTP `Authorization` header |\n\nThis 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.\n\n## Configuration Options\n\nThe `ElasticsearchMcpConfig` struct in `src/servers/elasticsearch/mod.rs` defines the supported authentication parameters:\n\n```rust\npub struct ElasticsearchMcpConfig {\n    /// Cluster URL\n    pub url: String,\n\n    /// API key\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub api_key: Option<String>,\n\n    /// Username\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub username: Option<String>,\n\n    /// Password\n    #[serde(default, deserialize_with = \"none_if_empty_string\")]\n    pub password: Option<String>,\n\n    /// Should we skip SSL certificate verification?\n    #[serde(default, deserialize_with = \"deserialize_bool_from_anything\")]\n    pub ssl_skip_verify: bool,\n}\n```\n\nSource: [src/servers/elasticsearch/mod.rs:98-120]()\n\n### Supported Authentication Methods\n\n| Method | Configuration | Priority |\n|--------|---------------|----------|\n| **API Key** | `ES_API_KEY` environment variable | Highest |\n| **Basic Authentication** | `ES_USERNAME` + `ES_PASSWORD` environment variables | Fallback |\n| **No Authentication** | Neither configured | When no credentials needed |\n\nThe credential resolution logic follows this precedence:\n\n```rust\nlet creds = if let Some(api_key) = config.api_key.clone() {\n    Some(Credentials::EncodedApiKey(api_key))\n} else if let Some(username) = config.username.clone() {\n    let pwd = config.password.clone().ok_or(anyhow::Error::msg(\"missing password\"))?;\n    Some(Credentials::Basic(username, pwd))\n} else {\n    None\n};\n```\n\nSource: [src/servers/elasticsearch/mod.rs:160-168]()\n\n### Environment Variable Mapping\n\n| Environment Variable | Config Field | Description |\n|---------------------|--------------|-------------|\n| `ES_URL` | `url` | Elasticsearch cluster endpoint |\n| `ES_API_KEY` | `api_key` | Base64-encoded API key |\n| `ES_USERNAME` | `username` | Username for basic auth |\n| `ES_PASSWORD` | `password` | Password for basic auth |\n| `ES_SSL_SKIP_VERIFY` | `ssl_skip_verify` | Disable TLS verification (not recommended) |\n\nThe configuration template demonstrates environment variable interpolation:\n\n```json\n{\n    \"elasticsearch\": {\n        \"url\": \"${ES_URL}\",\n        \"api_key\": \"${ES_API_KEY:}\",\n        \"username\": \"${ES_USERNAME:}\",\n        \"password\": \"${ES_PASSWORD:}\",\n        \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n    }\n}\n```\n\nSource: [src/lib.rs:56-66]()\n\n## Per-Request Authentication\n\nThe `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.\n\n```rust\npub fn get(&self, context: RequestContext<RoleServer>) -> Cow<'_, Elasticsearch> {\n    let client = &self.0;\n\n    let Some(mut auth) = context\n        .extensions\n        .get::<Parts>()\n        .and_then(|p| p.headers.get(header::AUTHORIZATION))\n        .and_then(|h| h.to_str().ok())\n    else {\n        // No auth\n        return Cow::Borrowed(client);\n    };\n\n    // MCP inspector insists on sending a bearer token and prepends \"Bearer\" to the value provided\n    if auth.starts_with(\"Bearer ApiKey \") || auth.starts_with(\"Bearer Basic \") {\n        auth = auth.trim_start_matches(\"Bearer \");\n    }\n\n    let transport = client\n        .transport()\n        .clone_with_auth(Some(Credentials::AuthorizationHeader(auth.to_string())));\n\n    Cow::Owned(Elasticsearch::new(transport))\n}\n```\n\nSource: [src/servers/elasticsearch/mod.rs:126-151]()\n\n### Authorization Header Handling\n\nThe server intelligently processes the `Authorization` header by:\n\n1. Extracting the header value from the incoming HTTP request\n2. Stripping `Bearer ` prefixes that some MCP clients (like the MCP Inspector) automatically prepend\n3. Creating a new Elasticsearch client transport with the extracted credentials\n4. Returning an owned `Cow<Elasticsearch>` to ensure the per-request client is used\n\n### Supported Per-Request Formats\n\n| Format | Example Header | Notes |\n|--------|---------------|-------|\n| `ApiKey <key>` | `Authorization: ApiKey VGhpcyBpcyBhbiBhcGkga2V5...` | Direct API key |\n| `Basic <credentials>` | `Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=` | Base64-encoded username:password |\n| `Bearer ApiKey <key>` | `Authorization: Bearer ApiKey VGhpcyBpcyBhbiBhcGkga2V5...` | MCP Inspector format for API key |\n| `Bearer Basic <credentials>` | `Authorization: Bearer Basic dXNlcm5hbWU6cGFzc3dvcmQ=` | MCP Inspector format for basic auth |\n\n## Deployment Modes and Authentication\n\nThe MCP server supports multiple transport modes that interact differently with authentication:\n\n### Stdio Mode\n\nIn 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.\n\n```rust\n#[derive(Debug, Subcommand)]\npub enum Command {\n    Stdio(StdioCommand),\n    Http(HttpCommand),\n}\n\n#[derive(Debug, Args)]\npub struct StdioCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n}\n```\n\nSource: [src/cli.rs:42-52]()\n\n### HTTP/SSE Mode\n\nIn 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.\n\n```rust\n#[derive(Debug, Args)]\npub struct HttpCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n\n    /// Address to listen to [default: 127.0.0.1:8080]\n    #[clap(long, value_name = \"IP_ADDRESS:PORT\", env = \"HTTP_ADDRESS\")]\n    pub address: Option<std::net::SocketAddr>,\n\n    /// Also start an SSE server on '/sse'\n    #[clap(long)]\n    pub sse: bool,\n}\n```\n\nSource: [src/cli.rs:30-41]()\n\n## Authentication Flow Diagram\n\n```mermaid\nsequenceDiagram\n    participant Client as MCP Client\n    participant MCP as MCP Server\n    participant ES as Elasticsearch\n\n    Note over MCP: Configuration Load\n    MCP->>MCP: Read ES_URL, ES_API_KEY/ES_USERNAME/ES_PASSWORD\n    MCP->>MCP: Create base Elasticsearch client\n\n    Note over Client,MCP: Per-Request Auth (HTTP mode only)\n    Client->>MCP: HTTP Request + Authorization header\n    MCP->>MCP: Extract Authorization header\n    \n    alt Authorization header present\n        MCP->>MCP: Clone transport with new credentials\n        MCP->>ES: Request with per-request auth\n    else No Authorization header\n        MCP->>ES: Request with base client auth\n    end\n    \n    ES-->>MCP: Response\n    MCP-->>Client: MCP Response\n```\n\n## SSL/TLS Configuration\n\n### Certificate Verification\n\nBy default, the server validates SSL/TLS certificates when connecting to Elasticsearch. To disable verification (not recommended for production):\n\n```bash\nES_SSL_SKIP_VERIFY=true\n```\n\nThis sets `ssl_skip_verify: true` in the configuration, which is passed to the Elasticsearch HTTP transport.\n\n### Container Mode URL Rewriting\n\nWhen running inside a container, localhost connections may need URL rewriting to reach the host machine:\n\n```rust\nif container_mode {\n    rewrite_localhost(&mut url)?;\n}\n```\n\nThis ensures that `http://localhost:9200` in a container context resolves to the actual host machine's Elasticsearch instance.\n\n## Common Issues and Troubleshooting\n\n### Issue: Basic Auth Failed - 401 Unauthorized\n\nA frequently reported issue (#170) involves authentication failures even when credentials are correctly configured:\n\n**Symptoms:**\n- Server logs show `401 Unauthorized`\n- Environment variables `ES_USERNAME`, `ES_PASSWORD` are confirmed correct inside the container\n\n**Potential Causes:**\n\n| Cause | Solution |\n|-------|----------|\n| Conflicting env var names | Use `ES_USERNAME` and `ES_PASSWORD` (v0.4.5 updated env name) |\n| Empty password string | Ensure `ES_PASSWORD` is not empty; use quotes if special characters present |\n| API key takes precedence | If `ES_API_KEY` is set, it overrides username/password |\n\n**Diagnostic Steps:**\n\n1. Verify all environment variables are correctly set\n2. Test connectivity directly to Elasticsearch with the same credentials\n3. For HTTP mode, check if a proxy is stripping or modifying the Authorization header\n\n### MCP Inspector Compatibility\n\nThe MCP Inspector prepends `Bearer ` to authentication values. The server handles this by stripping the prefix:\n\n```rust\nif auth.starts_with(\"Bearer ApiKey \") || auth.starts_with(\"Bearer Basic \") {\n    auth = auth.trim_start_matches(\"Bearer \");\n}\n```\n\nThis ensures compatibility with tools that follow the OAuth2 bearer token convention.\n\n## Security Best Practices\n\n| Practice | Recommendation |\n|----------|----------------|\n| **Credential Storage** | Use secrets management systems (AWS Secrets Manager, HashiCorp Vault) rather than plain environment variables |\n| **SSL Verification** | Keep `ES_SSL_SKIP_VERIFY=false` in production; only disable for local development |\n| **API Keys** | Prefer API keys over username/password for machine-to-machine authentication |\n| **Network Exposure** | Bind HTTP server to localhost (`127.0.0.1`) when possible; restrict network access |\n| **Proxy Authentication** | When using a reverse proxy, ensure it properly forwards or handles the Authorization header |\n\n## Related Documentation\n\n- [Model Context Protocol Authentication](https://modelcontextprotocol.io/docs/concepts/transports)\n- [Elasticsearch API Keys](https://www.elastic.co/docs/deploy-manage/api-keys)\n- [Elasticsearch User Management](https://www.elastic.co/docs/deploy-manage/users-roles)\n- [Docker Deployment Guide](#) - For container-specific authentication configuration\n\n---\n\n<a id='page-configuration-reference'></a>\n\n## Configuration Reference\n\n### Related Pages\n\nRelated topics: [Docker Deployment](#page-deployment), [Authentication and Security](#page-authentication)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)\n- [.env-example](https://github.com/elastic/mcp-server-elasticsearch/blob/main/.env-example)\n</details>\n\n# Configuration Reference\n\nThe Elasticsearch MCP Server supports flexible configuration through configuration files and environment variables. This reference documents all available configuration options, their purposes, and usage patterns.\n\n## Overview\n\nThe server configuration defines how the MCP server connects to Elasticsearch and which tools and features to expose. Configuration can be provided through:\n\n1. **Configuration file** (JSON or JSON5 format) specified via CLI\n2. **Environment variables** for containerized deployments\n3. **Default values** built into the binary\n\nSource: [src/lib.rs:66-85](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs#L66-L85)\n\n## Configuration File Structure\n\nThe configuration file uses JSON5 format, which extends JSON with support for comments and trailing commas. This allows for human-readable configuration with documentation.\n\n```json5\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\",\n    \"tools\": {\n      \"custom\": {\n        // Custom tools configuration\n      }\n    },\n    \"prompts\": []\n  }\n}\n```\n\nSource: [src/lib.rs:66-79](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs#L66-L79)\n\n## Elasticsearch Configuration Options\n\nThe `ElasticsearchMcpConfig` struct defines all connection and behavior settings:\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `url` | String | *(required)* | Elasticsearch cluster URL (e.g., `https://localhost:9200`) |\n| `api_key` | Option<String> | `None` | API key for authentication |\n| `username` | Option<String> | `None` | Username for basic authentication |\n| `password` | Option<String> | `None` | Password for basic authentication |\n| `ssl_skip_verify` | bool | `false` | Skip SSL certificate verification (not recommended for production) |\n| `tools` | Tools | `{}` | Custom tools configuration (ESQL, search templates) |\n| `prompts` | Vec<String> | `[]` | List of prompt identifiers to expose |\n\nSource: [src/servers/elasticsearch/mod.rs:101-129](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L101-L129)\n\n## Environment Variable Interpolation\n\nThe configuration system supports environment variable interpolation using `${VAR}` or `${VAR:default}` syntax. This enables containerized deployments and integration with orchestration systems.\n\n### Syntax\n\n| Pattern | Behavior |\n|---------|----------|\n| `${VAR}` | Required variable - server fails if not set |\n| `${VAR:default}` | Optional variable with default value |\n\n### Example Usage\n\n```bash\n# With all environment variables\nES_URL=https://elasticsearch:9200 \\\nES_API_KEY=my-api-key \\\n./elastic-mcp stdio --config config.json5\n\n# Using defaults (empty strings for optional vars)\nES_URL=https://elasticsearch:9200 \\\n./elastic-mcp stdio\n```\n\nThe interpolator replaces `${VAR}` patterns with actual environment variable values before JSON parsing occurs.\n\nSource: [src/utils/interpolator.rs:1-50](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs#L1-L50)\n\n```mermaid\ngraph TD\n    A[Config File or Built-in Defaults] --> B[Environment Variable Interpolation]\n    B --> C[JSON5 Parsing]\n    C --> D[serde_json5 Deserialization]\n    D --> E[ElasticsearchMcpConfig]\n    E --> F[Server Initialization]\n    \n    G[Environment Variables] -.->|${VAR} replacement| B\n```\n\n## Authentication Configuration\n\nThe server supports multiple authentication methods. Only one should be configured per deployment.\n\n### API Key Authentication\n\n```json5\n{\n  \"elasticsearch\": {\n    \"url\": \"https://elasticsearch:9200\",\n    \"api_key\": \"${ES_API_KEY}\"\n  }\n}\n```\n\n### Username/Password Authentication\n\n```json5\n{\n  \"elasticsearch\": {\n    \"url\": \"https://elasticsearch:9200\",\n    \"username\": \"${ES_USERNAME}\",\n    \"password\": \"${ES_PASSWORD}\"\n  }\n}\n```\n\n### Authentication Priority\n\nWhen multiple authentication methods are specified:\n\n1. `api_key` takes precedence over `username`/`password`\n2. Both `username` and `password` must be present for basic auth\n\nSource: [src/servers/elasticsearch/mod.rs:70-81](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L70-L81)\n\n## CLI Configuration\n\n### Stdio Mode\n\nRun the server in stdio mode for local integration with MCP clients:\n\n```bash\nelastic-mcp stdio [OPTIONS]\n```\n\n| Option | Description |\n|--------|-------------|\n| `-c, --config <PATH>` | Path to configuration file |\n\nSource: [src/cli.rs:38-45](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs#L38-L45)\n\n### HTTP Mode\n\nRun the server as an HTTP server for remote access:\n\n```bash\nelastic-mcp http [OPTIONS]\n```\n\n| Option | Environment Variable | Default | Description |\n|--------|---------------------|---------|-------------|\n| `-c, --config <PATH>` | - | `None` | Path to configuration file |\n| `--address <ADDR>` | `HTTP_ADDRESS` | `127.0.0.1:8080` | Listen address |\n| `--sse` | - | `false` | Enable SSE endpoint at `/mcp/sse` |\n\nSource: [src/cli.rs:26-37](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs#L26-L37)\n\n### Address Binding Behavior\n\nThe server binds to different addresses based on execution mode:\n\n| Mode | Default Address | Description |\n|------|-----------------|--------------|\n| Stdio | N/A | No network binding required |\n| HTTP | `127.0.0.1:8080` | Localhost only for security |\n| HTTP (container) | `0.0.0.0:8080` | All interfaces for container networking |\n\nSource: [src/lib.rs:90-99](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs#L90-L99)\n\n## Container Mode\n\nWhen 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.\n\n### Supported Host Aliases\n\nContainer mode rewrites `localhost` to one of these addresses (in order of priority):\n\n| Platform | Host Alias |\n|----------|------------|\n| Docker Desktop | `host.docker.internal` |\n| Podman | `host.containers.internal` |\n| Kubernetes | `host.containers.internal` |\n\nSource: [src/servers/elasticsearch/mod.rs:158-175](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L158-L175)\n\n```mermaid\ngraph TD\n    A[Container Mode Enabled] --> B{URL host = localhost?}\n    B -->|Yes| C[Resolve alias addresses]\n    B -->|No| E[Use URL as-is]\n    C --> D[Rewrite to resolved address]\n    D --> E\n    E --> F[Create ES Client]\n    \n    F --> G[host.docker.internal]\n    F --> H[host.containers.internal]\n```\n\n## Custom Tools Configuration\n\nThe `Tools` struct allows exposing custom ES|QL queries and search templates as MCP tools:\n\n```json5\n{\n  \"elasticsearch\": {\n    \"url\": \"https://elasticsearch:9200\",\n    \"tools\": {\n      \"custom\": {\n        \"esql_query\": {\n          \"type\": \"esql\",\n          \"description\": \"Execute ES|QL query\",\n          \"parameters\": { /* JSON Schema */ },\n          \"query\": \"FROM my-index | LIMIT 10\"\n        },\n        \"search_template\": {\n          \"type\": \"search_template\",\n          \"description\": \"Execute search template\",\n          \"template\": {\n            \"id\": \"my-template\"\n          }\n        }\n      }\n    }\n  }\n}\n```\n\n### ES|QL Tool Configuration\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `type` | String | Must be `\"esql\"` |\n| `description` | String | Human-readable tool description |\n| `parameters` | SchemaObject | JSON Schema for parameters |\n| `query` | String | ES|QL query to execute |\n| `format` | String | Output format: `json` (default) or `value` |\n\nSource: [src/servers/elasticsearch/mod.rs:35-68](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L35-L68)\n\n## Complete Configuration Example\n\n```json5\n{\n  \"elasticsearch\": {\n    // Connection settings\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\",\n    \n    // Custom tools\n    \"tools\": {\n      \"custom\": {\n        \"log_analysis\": {\n          \"type\": \"esql\",\n          \"description\": \"Analyze recent error logs\",\n          \"query\": \"FROM logs-* | WHERE level == 'ERROR' | LIMIT 100\"\n        }\n      }\n    },\n    \n    // Prompts to expose\n    \"prompts\": []\n  }\n}\n```\n\n## Environment Variable Reference\n\n| Variable | Required | Description |\n|----------|----------|--------------|\n| `ES_URL` | Yes | Elasticsearch cluster URL |\n| `ES_API_KEY` | No* | API key for authentication |\n| `ES_USERNAME` | No* | Username for basic auth |\n| `ES_PASSWORD` | No* | Password for basic auth |\n| `ES_SSL_SKIP_VERIFY` | No | Set to `true` to skip SSL verification |\n| `CLI_ARGS` | No | Alternative to CLI arguments |\n| `HTTP_ADDRESS` | No | HTTP server listen address |\n\n*Either `ES_API_KEY` or both `ES_USERNAME` and `ES_PASSWORD` should be set.\n\nSource: [.env-example](https://github.com/elastic/mcp-server-elasticsearch/blob/main/.env-example)\n\n## Known Configuration Issues\n\n### Basic Auth 401 Unauthorized\n\nIf using basic authentication fails with 401 errors, verify that:\n1. Both `ES_USERNAME` and `ES_PASSWORD` are set\n2. The Elasticsearch user has sufficient permissions\n3. The credentials are correctly passed to the container\n\n### Container Mode URL Resolution\n\nContainer mode requires the host alias to be resolvable. If you see warnings about failing to rewrite `localhost`, ensure:\n- Docker Desktop is running (for `host.docker.internal`)\n- Podman socket is active (for `host.containers.internal`)\n\nSource: [src/servers/elasticsearch/mod.rs:169-170](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L169-L170)\n\n## Configuration Schema\n\nThe complete JSON Schema for validation:\n\n```json\n{\n  \"$schema\": \"http://json-schema.org/draft-07/schema#\",\n  \"type\": \"object\",\n  \"required\": [\"elasticsearch\"],\n  \"properties\": {\n    \"elasticsearch\": {\n      \"type\": \"object\",\n      \"required\": [\"url\"],\n      \"properties\": {\n        \"url\": { \"type\": \"string\", \"format\": \"uri\" },\n        \"api_key\": { \"type\": [\"string\", \"null\"] },\n        \"username\": { \"type\": [\"string\", \"null\"] },\n        \"password\": { \"type\": [\"string\", \"null\"] },\n        \"ssl_skip_verify\": { \"type\": \"boolean\" },\n        \"tools\": { \"$ref\": \"#/definitions/Tools\" },\n        \"prompts\": { \"type\": \"array\", \"items\": { \"type\": \"string\" } }\n      }\n    }\n  }\n}\n```\n\nSource: [src/servers/elasticsearch/mod.rs:101-129](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs#L101-L129)\n\n---\n\n<a id='page-troubleshooting'></a>\n\n## Troubleshooting Guide\n\n### Related Pages\n\nRelated topics: [Authentication and Security](#page-authentication), [Monitoring and Health Checks](#page-monitoring), [Available MCP Tools](#page-available-tools)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/servers/elasticsearch/mod.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/mod.rs)\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n- [src/cli.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/cli.rs)\n- [src/utils/interpolator.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/utils/interpolator.rs)\n</details>\n\n# Troubleshooting Guide\n\nThis guide covers common issues encountered when deploying and using the Elasticsearch MCP Server, with solutions based on the codebase and reported community issues.\n\n## Authentication Failures\n\n### 401 Unauthorized with Basic Auth\n\nUsers deploying via Docker have reported authentication failures even when credentials appear correct.\n\n**Common Causes:**\n\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| Environment variable name | `ES_lOGIN` is a typo; use `ES_USERNAME` | Use `ES_USERNAME` and `ES_PASSWORD` correctly |\n| Missing password | Username provided without password | Always provide `ES_PASSWORD` when `ES_USERNAME` is set |\n| Container env setup | Variables not properly passed to container | Verify `-e` flags in docker run command |\n\n**Source:** The server validates credentials in `src/servers/elasticsearch/mod.rs:47-54`:\n\n```rust\nlet creds = if let Some(api_key) = config.api_key.clone() {\n    Some(Credentials::EncodedApiKey(api_key))\n} else if let Some(username) = config.username.clone() {\n    let pwd = config.password.clone().ok_or(anyhow::Error::msg(\"missing password\"))?;\n    Some(Credentials::Basic(username, pwd))\n} else {\n    None\n};\n```\n\n**Verification Steps:**\n\n1. Enter the container and confirm environment variables:\n   ```bash\n   docker exec -it <container_name> env | grep ES_\n   ```\n\n2. Verify the correct variable names are used:\n   - `ES_URL` - Elasticsearch cluster URL\n   - `ES_USERNAME` - Username (NOT `ES_lOGIN`)\n   - `ES_PASSWORD` - Password\n   - `ES_API_KEY` - API key (alternative to username/password)\n\n3. Test authentication directly against Elasticsearch using the same credentials.\n\n### API Key Authentication\n\nWhen using API key authentication, ensure the key is properly formatted and has sufficient permissions.\n\n**Configuration:**\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"api_key\": \"${ES_API_KEY:}\"\n  }\n}\n```\n\nThe server will use `api_key` if provided, falling back to username/password authentication. Source: `src/servers/elasticsearch/mod.rs:47`\n\n## Configuration Issues\n\n### Empty Elasticsearch URL\n\nThe server fails to start with an empty `ES_URL`:\n\n```\nError: \"Elasticsearch URL is empty\"\n```\n\n**Source:** `src/servers/elasticsearch/mod.rs:53-55`:\n\n```rust\nlet url = config.url.as_str();\nif url.is_empty() {\n    return Err(anyhow::Error::msg(\"Elasticsearch URL is empty\"));\n}\n```\n\n**Solution:** Ensure `ES_URL` is set to a valid Elasticsearch endpoint (e.g., `https://localhost:9200`).\n\n### SSL Certificate Verification Failures\n\nFor development or testing with self-signed certificates:\n\n**Configuration option:**\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n  }\n}\n```\n\nSet `ES_SSL_SKIP_VERIFY=true` to skip SSL verification. Source: `src/servers/elasticsearch/mod.rs:33-34`\n\n### Environment Variable Interpolation\n\nThe server supports `${VAR_NAME:default_value}` syntax in configuration files.\n\n**Source:** `src/utils/interpolator.rs:17-38`:\n\n```rust\nif line.starts_with(\"${\") {\n    if let Some(end) = line.find(\"$}\") {\n        let expr = &line[2..end];\n        let value = if let Some((name, default)) = expr.split_once(':') {\n            lookup(name).unwrap_or(default.to_string())\n        } else {\n            lookup(expr).ok_or_else(|| err(...))?\n        };\n        result.push_str(&value);\n    }\n}\n```\n\n**Example:**\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"${ES_URL:http://localhost:9200}\",\n    \"api_key\": \"${ES_API_KEY:}\",\n    \"username\": \"${ES_USERNAME:}\",\n    \"password\": \"${ES_PASSWORD:}\",\n    \"ssl_skip_verify\": \"${ES_SSL_SKIP_VERIFY:false}\"\n  }\n}\n```\n\n### Config File Parsing Errors\n\nConfiguration files support JSON5 (JSON with comments and trailing commas).\n\n**Error format for parsing failures:**\n\n```json\n{\n  \"elasticsearch\": {\n    \"url\": \"http://localhost:9200\"\n    // Missing comma above causes parsing error\n  }\n}\n```\n\n**Source:** `src/lib.rs:58-63`:\n\n```rust\nlet config: Configuration = match serde_json5::from_str(&config) {\n    Ok(c) => c,\n    Err(serde_json5::Error::Message { msg, location }) if location.is_some() => {\n        let location = location.unwrap();\n        anyhow::bail!(\"Failed to parse config: {msg}, at line {line} column {column}\");\n    }\n    Err(err) => return Err(err)?,\n};\n```\n\n## Tool-Specific Issues\n\n### get_mappings Decoding Error\n\n**Issue:** `get_mappings` tool fails with \"error decoding response body\" when index mappings contain nested properties defined without explicit `\"type\": \"nested\"`.\n\nThis is a known limitation when Elasticsearch returns mappings that are technically valid but contain implicit nested type declarations.\n\n**Source:** The tool uses `read_json` to parse responses in `src/servers/elasticsearch/base_tools.rs:140-150`:\n\n```rust\nasync fn get_mappings(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(GetMappingsParams { index }): Parameters<GetMappingsParams>,\n) -> Result<CallToolResult, rmcp::Error> {\n    let es_client = self.es_client.get(req_ctx);\n    let response = es_client.indices().get_mapping(GetMappingParts::Index(&[&index])).send().await;\n    let mapping: GetMappingResponse = read_json(response).await?;\n}\n```\n\n**Workaround:** Ensure your Elasticsearch index mappings explicitly define the `type` property for nested fields:\n\n```json\n{\n  \"mappings\": {\n    \"properties\": {\n      \"nested_field\": {\n        \"type\": \"nested\"\n      }\n    }\n  }\n}\n```\n\n### search Tool Aggregation Results\n\nThe search tool returns aggregation results alongside hits:\n\n**Source:** `src/servers/elasticsearch/base_tools.rs:153-177`:\n\n```rust\nlet response: SearchResult = read_json(response).await?;\nlet mut results: Vec<Content> = Vec::new();\n\n// Send result stats only if it's not pure aggregation results\nif response.aggregations.is_empty() || !response.hits.hits.is_empty() {\n    let total = response.hits.total.map(|t| t.value).unwrap_or(0);\n    results.push(Content::text(format!(\"Found {} hits:\", total)));\n}\n\n// Include aggregations if present\nif !response.aggregations.is_empty() {\n    results.push(Content::text(\"Aggregations:\"));\n    results.push(Content::json(response.aggregations)?);\n}\n```\n\n### ES|QL Query Response Format\n\nES|QL queries transform columnar results into object format:\n\n**Source:** `src/servers/elasticsearch/base_tools.rs:186-203`:\n\n```rust\nlet response: EsqlQueryResponse = read_json(response).await?;\n\n// Transform response into an array of objects\nlet mut objects: Vec<Value> = Vec::new();\nfor row in response.values.into_iter() {\n    let mut obj = Map::new();\n    for (i, value) in row.into_iter().enumerate() {\n        obj.insert(response.columns[i].name.clone(), value);\n    }\n    objects.push(Value::Object(obj));\n}\n```\n\n## Deployment Issues\n\n### Docker Container Mode\n\nWhen running in Docker, the server rewrites `localhost` references to enable container-to-container communication.\n\n**Source:** `src/servers/elasticsearch/mod.rs:57`:\n\n```rust\nif container_mode {\n    rewrite_localhost(&mut url)?;\n}\n```\n\n**Default Ports:**\n\n| Mode | Default Address | Environment Variable |\n|------|-----------------|----------------------|\n| Docker (HTTP) | `0.0.0.0:8080` | `HTTP_ADDRESS` |\n| Local (HTTP) | `127.0.0.1:8080` | `HTTP_ADDRESS` |\n| Stdio | N/A | N/A |\n\n**Source:** `src/lib.rs:47-53`:\n\n```rust\nlet address: SocketAddr = if let Some(addr) = cmd.address {\n    addr\n} else if container_mode {\n    SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 8080)\n} else {\n    SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 8080)\n};\n```\n\n### HTTP Transport Endpoints\n\nWhen running in HTTP mode:\n\n| Endpoint | Purpose |\n|----------|---------|\n| `/mcp` | Streamable-HTTP MCP endpoint |\n| `/ping` | Health check endpoint |\n\n**Source:** `src/cli.rs:37-45`:\n\n```rust\npub struct HttpCommand {\n    /// Config file\n    #[clap(short, long)]\n    pub config: Option<PathBuf>,\n\n    /// Address to listen to [default: 127.0.0.1:8080]\n    #[clap(long, value_name = \"IP_ADDRESS:PORT\", env = \"HTTP_ADDRESS\")]\n    pub address: Option<std::net::SocketAddr>,\n\n    /// Also start an SSE server on '/sse'\n    #[clap(long)]\n    pub sse: bool,\n}\n```\n\n### Common Docker Deployment Errors\n\n**Container exits immediately:**\n\n1. Check logs: `docker logs <container_name>`\n2. Verify environment variables are set\n3. Ensure Elasticsearch URL is accessible from container\n\n**Port already in use:**\n\n```bash\n# Check what's using port 8080\nlsof -i :8080\n# Use different port\ndocker run -p 8081:8080 ...\n```\n\n## Error Handling Reference\n\n### Server Error Responses\n\nThe server uses the `rmcp::Error` type for MCP protocol errors:\n\n**Source:** `src/servers/elasticsearch/mod.rs:66-74`:\n\n```rust\npub fn handle_error(result: Result<Response, elasticsearch::Error>) -> Result<Response, rmcp::Error> {\n    match result {\n        Ok(resp) => resp.error_for_status_code(),\n        Err(e) => {\n            tracing::error!(\"Error: {:?}\", &e);\n            Err(e)\n        }\n    }\n    .map_err(internal_error)\n}\n```\n\n### Common Error Messages\n\n| Error | Cause | Resolution |\n|-------|-------|------------|\n| `error decoding response body` | Invalid JSON in ES response | Check ES version compatibility; verify index mappings |\n| `Request failed (remote)` | ES cluster unreachable | Verify ES_URL; check network/firewall |\n| `missing password` | Username set without password | Provide ES_PASSWORD or use API key auth |\n| `Elasticsearch URL is empty` | ES_URL not set | Set ES_URL environment variable |\n\n## Diagnostic Checklist\n\nWhen troubleshooting, verify:\n\n- [ ] `ES_URL` is set and points to a reachable Elasticsearch cluster\n- [ ] Authentication credentials (API key or username/password) are correct\n- [ ] If using Basic auth, both `ES_USERNAME` and `ES_PASSWORD` are set (not `ES_lOGIN`)\n- [ ] SSL certificate issues: set `ES_SSL_SKIP_VERIFY=true` for self-signed certs\n- [ ] Docker networking allows container to reach Elasticsearch\n- [ ] Index name is correct (use `list_indices` tool to verify)\n- [ ] User has necessary Elasticsearch permissions for the requested operations\n\n## Getting Help\n\nFor additional support:\n\n1. Search [existing GitHub issues](https://github.com/elastic/mcp-server-elasticsearch/issues)\n2. Check the [Dependency Dashboard](https://github.com/elastic/mcp-server-elasticsearch/issues/6) for known dependency-related issues\n3. Enable debug logging by setting `RUST_LOG=debug` when running the server\n\n---\n\n<a id='page-monitoring'></a>\n\n## Monitoring and Health Checks\n\n### Related Pages\n\nRelated topics: [Troubleshooting Guide](#page-troubleshooting), [Docker Deployment](#page-deployment)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [src/protocol/http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/protocol/http.rs)\n- [src/servers/elasticsearch/base_tools.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/servers/elasticsearch/base_tools.rs)\n- [src/bin/start_http.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/bin/start_http.rs)\n- [README.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/README.md)\n- [src/lib.rs](https://github.com/elastic/mcp-server-elasticsearch/blob/main/src/lib.rs)\n</details>\n\n# Monitoring and Health Checks\n\nThe 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.\n\n## Health Check Endpoints\n\nWhen 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.\n\n### Available Endpoints\n\n| Endpoint | Path | Method | Purpose |\n|----------|------|--------|---------|\n| Readiness | `/_health/ready` | GET | Indicates server can accept requests |\n| Liveness | `/_health/live` | GET | Indicates server process is alive |\n| Ping | `/ping` | GET | Basic connectivity verification |\n| Hello | `/` | GET | Server version and endpoint info |\n\n### Readiness Probe\n\nThe readiness endpoint signals when the server is fully initialized and ready to process MCP requests:\n\n```http\nGET /_health/ready HTTP/1.1\n```\n\n**Response:**\n```\nHTTP/1.1 200 OK\nReady\n```\n\nThe server becomes ready once the tool list is loaded and the Elasticsearch client is initialized. Source: [src/protocol/http.rs:1-50](src/protocol/http.rs)\n\n### Liveness Probe\n\nThe liveness endpoint confirms the server process is running:\n\n```http\nGET /_health/live HTTP/1.1\n```\n\n**Response:**\n```\nHTTP/1.1 200 OK\nAlive\n```\n\nThis endpoint returns immediately without checking Elasticsearch connectivity, making it suitable for detecting crashed processes. Source: [src/protocol/http.rs:1-50](src/protocol/http.rs)\n\n### Ping Endpoint\n\nThe ping endpoint provides a quick health verification:\n\n```http\nGET /ping HTTP/1.1\n```\n\n**Response:**\n```\nHTTP/1.1 200 OK\nReady\n```\n\nA successful `pong` response indicates the server is running and healthy. Source: [README.md](README.md)\n\n## Monitoring Tools\n\nThe 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.\n\n### Tool Reference\n\n| Tool | Purpose | Read-Only |\n|------|---------|-----------|\n| `list_indices` | List available Elasticsearch indices | Yes |\n| `get_shards` | Retrieve shard allocation information | Yes |\n| `get_mappings` | Fetch index field mappings | Yes |\n| `search` | Execute search queries | Yes |\n| `esql` | Run ES|QL queries | Yes |\n\n### Shard Monitoring\n\nThe `get_shards` tool provides detailed shard distribution information across the cluster:\n\n```json\n{\n  \"name\": \"get_shards\",\n  \"arguments\": {\n    \"index\": \"optional-index-name\"\n  }\n}\n```\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `index` | String | No | Specific index name; omit for all indices |\n\n**Response Fields:**\n\n| Field | Description |\n|-------|-------------|\n| `index` | Index name |\n| `shard` | Shard number |\n| `prirep` | Primary (P) or replica (R) |\n| `state` | Shard state (STARTED, INITIALIZING, etc.) |\n| `docs` | Document count |\n| `store` | Store size |\n| `node` | Node name housing the shard |\n\nThis tool was introduced in v0.2.0 for cluster monitoring purposes. Source: [src/servers/elasticsearch/base_tools.rs:1-50](src/servers/elasticsearch/base_tools.rs)\n\n### Index Listing\n\nThe `list_indices` tool enumerates all indices accessible to the authenticated user:\n\n```json\n{\n  \"name\": \"list_indices\",\n  \"arguments\": {\n    \"index_pattern\": \"*\"\n  }\n}\n```\n\n**Response Structure:**\n\n```json\n[\n  {\n    \"index\": \"index-name\",\n    \"status\": \"open\",\n    \"doc_count\": 12345\n  }\n]\n```\n\n### Mappings Retrieval\n\nThe `get_mappings` tool retrieves field mappings for index analysis:\n\n```json\n{\n  \"name\": \"get_mappings\",\n  \"arguments\": {\n    \"index\": \"my-index\"\n  }\n}\n```\n\n**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](https://github.com/elastic/mcp-server-elasticsearch/issues/185)\n\n## Architecture\n\n### Health Check Request Flow\n\n```mermaid\ngraph TD\n    A[External Monitor] -->|HTTP GET| B[Main Router]\n    B -->|Route| C[Health Router]\n    C -->|/ready| D[Readiness Check]\n    C -->|/live| E[Liveness Check]\n    C -->|/ping| F[Basic Ping]\n    \n    D -->|Initialize| G[Tool List Loaded]\n    G -->|ES Client Ready| H[200 OK]\n    \n    E --> I[Process Alive]\n    I --> J[200 OK]\n    \n    F --> K[Server Responding]\n    K --> L[pong]\n```\n\n### HTTP Server Structure\n\nThe HTTP server is built using the Axum framework with a layered router configuration:\n\n```mermaid\ngraph TD\n    A[TCP Listener] --> B[Graceful Shutdown Handler]\n    B --> C[Main Router]\n    \n    C -->|/| D[Hello Endpoint]\n    C -->|/ping| E[Ping Endpoint]\n    C -->|/mcp| F[MCP Handler]\n    C -->|/mcp/sse| G[SSE Handler]\n    C -->|/_health| H[Health Router]\n    \n    H -->|/ready| I[Readiness Probe]\n    H -->|/live| J[Liveness Probe]\n```\n\nSource: [src/protocol/http.rs:1-50](src/protocol/http.rs)\n\n## Troubleshooting\n\n### Common Issues\n\n#### Authentication Failures\n\n**Symptom:** 401 Unauthorized errors when the server attempts to connect to Elasticsearch.\n\n**Diagnostic Steps:**\n\n1. Verify environment variables inside the container:\n   ```bash\n   docker exec <container-id> env | grep ES_\n   ```\n\n2. Confirm credentials are correctly set:\n   - `ES_API_KEY` for API key authentication\n   - `ES_USERNAME` and `ES_PASSWORD` for basic auth\n\n3. Test connectivity directly from the container:\n   ```bash\n   # Basic auth\n   docker exec <container-id> curl -k -u <username>:<password> <ES_URL>\n   \n   # API key\n   docker exec <container-id> curl -k -H \"Authorization: ApiKey <api-key>\" <ES_URL>\n   ```\n\nSource: [README.md](README.md)\n\n#### Container Logs Analysis\n\nView logs to identify connection or authentication issues:\n\n```bash\ndocker logs <container-id>\n```\n\nLook for these error patterns:\n\n| Error Pattern | Likely Cause |\n|---------------|--------------|\n| `Connection refused` | Elasticsearch URL incorrect or ES not running |\n| `401 Unauthorized` | Invalid credentials |\n| `certificate verify failed` | SSL verification issue |\n\n#### Elasticsearch Connectivity Verification\n\nFrom within the container, verify network connectivity:\n\n```bash\ndocker exec <container-id> curl -k -u <username>:<password> <ES_URL>/_cluster/health\n```\n\nA successful response with cluster health JSON confirms the container can reach Elasticsearch.\n\n### Health Check Configuration\n\nThe default bind address is `127.0.0.1:8080`, configurable via:\n\n| Option | Environment Variable | CLI Flag |\n|--------|---------------------|----------|\n| Bind address | `HTTP_ADDRESS` | `--address` |\n\nExample configuration:\n```bash\n# Environment variable\nHTTP_ADDRESS=0.0.0.0:8080\n\n# CLI argument\n--address 0.0.0.0:8080\n```\n\nSource: [src/cli.rs](src/cli.rs)\n\n## Best Practices\n\n### Kubernetes Probes\n\nConfigure Kubernetes probes to use the health check endpoints:\n\n```yaml\nlivenessProbe:\n  httpGet:\n    path: /_health/live\n    port: 8080\n  initialDelaySeconds: 5\n  periodSeconds: 10\n\nreadinessProbe:\n  httpGet:\n    path: /_health/ready\n    port: 8080\n  initialDelaySeconds: 5\n  periodSeconds: 5\n```\n\n### Monitoring Integration\n\n- Use `/ping` for load balancer health checks\n- Use `/_health/ready` for orchestration readiness signals\n- Use `/_health/live` for process liveness detection\n- Leverage `get_shards` tool for detailed cluster state monitoring via MCP\n\n### Security Considerations\n\n- Health endpoints do not require authentication by default\n- Restrict access using network policies in production\n- The `/ping` endpoint returns minimal information suitable for public exposure\n\n## Configuration Reference\n\n### Health Router Configuration\n\nThe health router is mounted at `/_health` within the main application router:\n\n```rust\nlet health_router = Router::new()\n    .route(\"/ready\", get(async || (StatusCode::OK, \"Ready\\n\")))\n    .route(\"/live\", get(async || \"Alive\\n\"));\n```\n\nSource: [src/protocol/http.rs:1-50](src/protocol/http.rs)\n\n### Server Initialization\n\nHealth endpoints become available after successful server initialization:\n\n```rust\nlet handler = elasticsearch::ElasticsearchMcp::new_with_config(config.elasticsearch, container_mode)?;\n```\n\nThe server is ready when the `EsBaseTools` handler is constructed with a valid Elasticsearch client. Source: [src/lib.rs](src/lib.rs)\n\n## Deprecation Notice\n\nThe Elasticsearch MCP Server is deprecated as of v0.4.6. For production monitoring workloads, consider migrating to the [Elastic Agent Builder](https://ela.st/agent-builder-docs) MCP endpoint available in Elastic 9.2.0+ and Elasticsearch Serverless projects. Source: [README.md](README.md)\n\n---\n\n<a id='page-contributing'></a>\n\n## Contributing Guide\n\n### Related Pages\n\nRelated topics: [System Architecture](#page-architecture)\n\n<details>\n<summary>Related Source Files</summary>\n\nThe following source files were used to generate this page:\n\n- [Cargo.toml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/Cargo.toml)\n- [Makefile](https://github.com/elastic/mcp-server-elasticsearch/blob/main/Makefile)\n- [docs/CONTRIBUTING.md](https://github.com/elastic/mcp-server-elasticsearch/blob/main/docs/CONTRIBUTING.md)\n- [rustfmt.toml](https://github.com/elastic/mcp-server-elasticsearch/blob/main/rustfmt.toml)\n- [scripts/cargo-run.sh](https://github.com/elastic/mcp-server-elasticsearch/blob/main/scripts/cargo-run.sh)\n</details>\n\n# Contributing Guide\n\nWelcome 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.\n\n## Overview\n\nThe 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.\n\nContributions 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.\n\n## Development Environment Setup\n\n### Prerequisites\n\n| Requirement | Version | Purpose |\n|-------------|---------|---------|\n| Rust | 1.75+ | Primary language runtime |\n| Cargo | Latest stable | Package manager and build tool |\n| Docker | 24.0+ | Container runtime for testing |\n| Elasticsearch | 8.x or 9.x | Target cluster for integration testing |\n\n### Initial Setup\n\n1. **Clone the repository**\n   ```bash\n   git clone https://github.com/elastic/mcp-server-elasticsearch.git\n   cd mcp-server-elasticsearch\n   ```\n\n2. **Install Rust dependencies**\n   ```bash\n   cargo fetch\n   ```\n\n3. **Verify the build compiles successfully**\n   ```bash\n   cargo build\n   ```\n\n### Running the Server Locally\n\nThe project provides a helper script for running the server during development:\n\n```bash\n./scripts/cargo-run.sh\n```\n\nThis script wraps the cargo run command with appropriate environment configuration for local development.\n\n## Project Structure\n\n```\nmcp-server-elasticsearch/\n├── src/\n│   ├── servers/\n│   │   └── elasticsearch/\n│   │       ├── base_tools.rs    # Core MCP tool implementations\n│   │       └── mod.rs            # Server configuration and initialization\n│   ├── utils/\n│   │   ├── interpolator.rs       # Environment variable interpolation\n│   │   ├── mod.rs                # Utility module exports\n│   │   └── rmcp_ext.rs           # MCP SDK extensions\n│   ├── cli.rs                    # Command-line interface\n│   └── lib.rs                    # Library entry point\n├── tests/                        # Integration tests\n├── Makefile                      # Build and development tasks\n├── Cargo.toml                    # Rust dependencies and metadata\n└── rustfmt.toml                  # Code formatting configuration\n```\n\n## Code Style and Standards\n\n### Formatting\n\nThe project uses `rustfmt` for consistent code formatting. Configuration is defined in `rustfmt.toml`:\n\n| Setting | Value | Description |\n|---------|-------|-------------|\n| `max_width` | 100 | Maximum line length |\n| `tab_spaces` | 4 | Indentation size |\n| `edition` | 2021 | Rust edition |\n\n**Format your code before committing:**\n```bash\ncargo fmt --check\n```\n\n### Linting\n\nRun clippy for linting checks:\n```bash\ncargo clippy --all-targets --all-features\n```\n\nAddress all warnings and errors reported by clippy before submitting your pull request.\n\n### Code Organization\n\nThe codebase follows these architectural patterns:\n\n- **Tool Implementation**: MCP tools are defined using the `#[tool]` macro and implemented in `src/servers/elasticsearch/base_tools.rs`\n- **Configuration**: Configuration parsing uses serde with JSON5 support for comments in config files\n- **Error Handling**: The project uses `anyhow::Error` for flexible error handling\n- **HTTP Authentication**: The `EsClientProvider` supports authorization header passthrough for HTTP transport mode\n\n## Testing\n\n### Unit Tests\n\nRun unit tests with:\n```bash\ncargo test\n```\n\n### Integration Testing\n\nIntegration tests require a running Elasticsearch cluster. Configure the test environment using environment variables:\n\n| Environment Variable | Description | Required |\n|---------------------|-------------|----------|\n| `ES_URL` | Elasticsearch cluster URL | Yes |\n| `ES_API_KEY` | API key for authentication | No* |\n| `ES_USERNAME` | Username for basic auth | No* |\n| `ES_PASSWORD` | Password for basic auth | No* |\n\n*Either API key or username/password combination required\n\n### Build Verification\n\nUse the Makefile to verify the complete build:\n\n```bash\nmake build\n```\n\n## MCP Tool Development\n\n### Defining New Tools\n\nTools are defined using the `#[tool]` attribute macro. The framework expects specific parameters:\n\n```rust\n#[tool(\n    description = \"Tool description for LLM context\",\n    annotations(title = \"Display title\", read_only_hint = true)\n)]\nasync fn my_tool(\n    &self,\n    req_ctx: RequestContext<RoleServer>,\n    Parameters(ToolParams): Parameters<ToolParams>,\n) -> Result<CallToolResult, rmcp::Error> {\n    // Implementation\n}\n```\n\n### Tool Parameters\n\nParameter types must implement `serde::Deserialize` and `schemars::JsonSchema`:\n\n```rust\n#[derive(Debug, serde::Deserialize, schemars::JsonSchema)]\nstruct MyToolParams {\n    /// Parameter description for schema generation\n    param_name: String,\n}\n```\n\n### Response Format\n\nReturn tool results using `CallToolResult::success()` with a vector of `Content` items:\n\n```rust\nOk(CallToolResult::success(vec![\n    Content::text(\"Description\"),\n    Content::json(data)?,\n]))\n```\n\n## Submitting Changes\n\n### Branch Strategy\n\n1. Create a feature branch from `main`:\n   ```bash\n   git checkout -b feature/my-feature\n   ```\n\n2. Make your changes following the coding standards\n\n3. Commit with clear, descriptive messages:\n   ```bash\n   git commit -m \"Add support for new ES|QL aggregation function\"\n   ```\n\n### Pull Request Checklist\n\n- [ ] Code formatted with `cargo fmt`\n- [ ] Clippy warnings resolved\n- [ ] Tests pass with `cargo test`\n- [ ] New tools include parameter documentation\n- [ ] Configuration changes documented in relevant files\n- [ ] Commit messages follow conventional format\n\n### Commit Message Format\n\n```\n<type>(<scope>): <description>\n\n[optional body]\n```\n\nTypes: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`\n\n## Build and Release Process\n\n### Build Targets\n\nThe project supports multiple build targets:\n\n| Target | Platform | Architecture |\n|--------|----------|--------------|\n| x86_64-unknown-linux-musl | Linux | x86_64 |\n| x86_64-apple-darwin | macOS | x86_64 |\n| aarch64-apple-darwin | macOS | ARM64 |\n| x86_64-pc-windows-msvc | Windows | x86_64 |\n\n### Using Makefile\n\nThe Makefile provides convenient build targets:\n\n```bash\nmake build       # Build release binary\nmake test        # Run test suite\nmake check       # Run formatting and clippy\nmake clean       # Clean build artifacts\n```\n\n## Known Limitations\n\nWhen contributing, be aware of the following known issues:\n\n1. **Nested Mappings Issue**: The `get_mappings` tool may fail with \"error decoding response body\" when nested properties omit explicit type specification. See [Issue #185](https://github.com/elastic/mcp-server-elasticsearch/issues/185).\n\n2. **Basic Auth Configuration**: Authentication via environment variables requires specific naming (`ES_USERNAME`, `ES_PASSWORD`). See [Issue #170](https://github.com/elastic/mcp-server-elasticsearch/issues/170).\n\n3. **Platform Binaries**: Currently, Linux ARM64 binaries are not published. See [Issue #191](https://github.com/elastic/mcp-server-elasticsearch/issues/191).\n\n## Getting Help\n\nIf you encounter issues while contributing:\n\n- Check existing [GitHub Issues](https://github.com/elastic/mcp-server-elasticsearch/issues) for similar problems\n- Review the [MCP Protocol Documentation](https://modelcontextprotocol.io/docs/concepts/transports) for transport-related questions\n- Join the Elastic community for support\n\n## License\n\nBy contributing to this project, you agree that your contributions will be licensed under the Apache License, Version 2.0. See the [NOTICE.txt](https://github.com/elastic/mcp-server-elasticsearch/blob/main/NOTICE.txt) file for details.\n\n---\n\n<!-- evidence_pipeline_checked: true -->\n<!-- evidence_injected: true -->\n\n---\n\n## Pitfall Log\n\nProject: elastic/mcp-server-elasticsearch\n\nSummary: Found 10 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Installation risk - Installation risk requires verification.\n\n## 1. Installation risk - Installation risk requires verification\n\n- Severity: medium\n- Evidence strength: runtime_trace\n- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Repro command: `docker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio`\n- Evidence: identity.distribution | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 2. Installation risk - Installation risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: community_evidence:github | cevd_5573c160ecdd4e34be6dbf6549fe2529 | https://github.com/elastic/mcp-server-elasticsearch/issues/6\n\n## 3. Configuration risk - Configuration risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: capability.host_targets | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 4. Capability evidence risk - Capability evidence risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: README/documentation is current enough for a first validation pass.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: capability.assumptions | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 5. Maintenance risk - Maintenance risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 6. Security or permission risk - Security or permission risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: downstream_validation.risk_items | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 7. Security or permission risk - Security or permission risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: risks.scoring_risks | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 8. Security or permission risk - Security or permission risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: community_evidence:github | cevd_f8732a2deab341d6b739b122459d1243 | https://github.com/elastic/mcp-server-elasticsearch/issues/185\n\n## 9. Maintenance risk - Maintenance risk requires verification\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: issue_or_pr_quality=unknown。\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 10. Maintenance risk - Maintenance risk requires verification\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: release_recency=unknown。\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n<!-- canonical_name: elastic/mcp-server-elasticsearch; human_manual_source: deepwiki_human_wiki -->\n",
      "summary": "DeepWiki/Human Wiki 完整输出，末尾追加 Discovery Agent 踩坑日志。",
      "title": "Human Manual / 人类版说明书"
    },
    "pitfall_log": {
      "asset_id": "pitfall_log",
      "filename": "PITFALL_LOG.md",
      "markdown": "# Pitfall Log\n\nProject: elastic/mcp-server-elasticsearch\n\nSummary: Found 10 structured pitfall item(s), including 0 high/blocking item(s). Top priority: Installation risk - Installation risk requires verification.\n\n## 1. Installation risk - Installation risk requires verification\n\n- Severity: medium\n- Evidence strength: runtime_trace\n- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Repro command: `docker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio`\n- Evidence: identity.distribution | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 2. Installation risk - Installation risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a installation risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: community_evidence:github | cevd_5573c160ecdd4e34be6dbf6549fe2529 | https://github.com/elastic/mcp-server-elasticsearch/issues/6\n\n## 3. Configuration risk - Configuration risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a configuration risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: capability.host_targets | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 4. Capability evidence risk - Capability evidence risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: README/documentation is current enough for a first validation pass.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: capability.assumptions | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 5. Maintenance risk - Maintenance risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a maintenance risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 6. Security or permission risk - Security or permission risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: downstream_validation.risk_items | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 7. Security or permission risk - Security or permission risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: no_demo\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: risks.scoring_risks | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 8. Security or permission risk - Security or permission risk requires verification\n\n- Severity: medium\n- Evidence strength: source_linked\n- Finding: Project evidence flags a security or permission risk. Review the linked source before relying on this workflow.\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: community_evidence:github | cevd_f8732a2deab341d6b739b122459d1243 | https://github.com/elastic/mcp-server-elasticsearch/issues/185\n\n## 9. Maintenance risk - Maintenance risk requires verification\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: issue_or_pr_quality=unknown。\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n\n## 10. Maintenance risk - Maintenance risk requires verification\n\n- Severity: low\n- Evidence strength: source_linked\n- Finding: release_recency=unknown。\n- User impact: May increase setup, validation, or first-run risk for the user.\n- Suggested check: Reproduce the official install and quickstart path in an isolated environment.\n- Evidence: evidence.maintainer_signals | github_repo:953992846 | https://github.com/elastic/mcp-server-elasticsearch\n",
      "summary": "用户实践前最可能遇到的身份、安装、配置、运行和安全坑。",
      "title": "Pitfall Log / 踩坑日志"
    },
    "prompt_preview": {
      "asset_id": "prompt_preview",
      "filename": "PROMPT_PREVIEW.md",
      "markdown": "# mcp-server-elasticsearch - Prompt Preview\n\n> Copy the prompt below into your AI host before installing anything.\n> Its purpose is to let you safely feel the project's workflow, not to claim the project has already run.\n\n## Copy this prompt\n\n```text\nYou are using an independent Doramagic capability pack for elastic/mcp-server-elasticsearch.\n\nProject:\n- Name: mcp-server-elasticsearch\n- Repository: https://github.com/elastic/mcp-server-elasticsearch\n- Summary: Elasticsearch MCP Server\n- Host target: mcp_host, claude, cursor\n\nGoal:\nHelp me evaluate this project for the following task without installing it yet: Elasticsearch MCP Server\n\nBefore taking action:\n1. Restate my task, success standard, and boundary.\n2. Identify whether the next step requires tools, browser access, network access, filesystem access, credentials, package installation, or host configuration.\n3. Use only the Doramagic Project Pack, the upstream repository, and the source-linked evidence listed below.\n4. If a real command, install step, API call, file write, or host integration is required, mark it as \"requires post-install verification\" and ask for approval first.\n5. If evidence is missing, say \"evidence is missing\" instead of filling the gap.\n\nPreviewable capabilities:\n- Environment Variable Interpolation: Substitute environment variables in configuration using ${VAR} or ${VAR:default} syntax (Inputs: String with ${VAR} or ${VAR:default} placeholders; Outputs: Interpolated string)\n\nCapabilities that require post-install verification:\n- Elasticsearch Index Management: List and explore Elasticsearch indices with their status, document counts, and metadata (Inputs: index_pattern: string (default '*'); Outputs: Array of index objects with name, status, doc count)\n- Index Mapping Retrieval: Retrieve field mappings for specified Elasticsearch indices to understand data schemas (Inputs: index: string; Outputs: Mapping response with field definitions and types)\n- Full-text Search: Execute search queries against Elasticsearch indices with support for aggregations and source field filtering (Inputs: index: string, query_body: object, fields: array (optional _source fields); Outputs: Hits with sources, aggregations, total count)\n- ES|QL Query Execution: Run ES|QL (Elasticsearch Query Language) queries for data analysis and transformation (Inputs: query: string, params: object (optional); Outputs: Columns metadata and result rows)\n- Shard Distribution Analysis: View shard allocation and distribution across nodes for debugging and performance analysis (Inputs: index: string (optional); Outputs: Shard details including index, shard num, primary/replica, state, docs count, node)\n\nCore service flow:\n1. page-project-introduction: Project Introduction. Produce one small intermediate artifact and wait for confirmation.\n2. page-available-tools: Available MCP Tools. Produce one small intermediate artifact and wait for confirmation.\n3. page-architecture: System Architecture. Produce one small intermediate artifact and wait for confirmation.\n4. page-protocols: MCP Protocol Configuration. Produce one small intermediate artifact and wait for confirmation.\n5. page-deployment: Docker Deployment. Produce one small intermediate artifact and wait for confirmation.\n\nSource-backed evidence to keep in mind:\n- https://github.com/elastic/mcp-server-elasticsearch\n- https://github.com/elastic/mcp-server-elasticsearch#readme\n- src/utils/interpolator.rs\n- elastic-mcp.json5\n- README.md\n- catalog-info.yaml\n- NOTICE.txt\n- src/servers/elasticsearch/base_tools.rs\n- src/servers/elasticsearch/mod.rs\n- src/lib.rs\n\nFirst response rules:\n1. Start Step 1 only.\n2. Explain the one service action you will perform first.\n3. Ask exactly three questions about my target workflow, success standard, and sandbox boundary.\n4. Stop and wait for my answers.\n\nStep 1 follow-up protocol:\n- After I answer the first three questions, stay in Step 1.\n- Produce six parts only: clarified task, success standard, boundary conditions, two or three options, tradeoffs for each option, and one recommendation.\n- End by asking whether I confirm the recommendation.\n- Do not move to Step 2 until I explicitly confirm.\n\nConversation rules:\n- Advance one step at a time and wait for confirmation after each small artifact.\n- Write outputs as recommendations or planned checks, not as completed execution.\n- Do not claim tests passed, files changed, commands ran, APIs were called, or the project was installed.\n- If the user asks for execution, first provide the sandbox setup, expected output, rollback, and approval checkpoint.\n```\n",
      "summary": "不安装项目也能感受能力节奏的安全试用 Prompt。",
      "title": "Prompt Preview / 安装前试用 Prompt"
    },
    "quick_start": {
      "asset_id": "quick_start",
      "filename": "QUICK_START.md",
      "markdown": "# Quick Start / 官方入口\n\n项目：elastic/mcp-server-elasticsearch\n\n## 官方安装入口\n\n### Docker · 官方安装入口\n\n```bash\ndocker run -i --rm -e ES_URL -e ES_API_KEY docker.elastic.co/mcp/elasticsearch stdio\n```\n\n来源：https://github.com/elastic/mcp-server-elasticsearch#readme\n\n## 来源\n\n- repo: https://github.com/elastic/mcp-server-elasticsearch\n- docs: https://github.com/elastic/mcp-server-elasticsearch#readme\n",
      "summary": "从项目官方 README 或安装文档提取的开工入口。",
      "title": "Quick Start / 官方入口"
    }
  },
  "validation_id": "dval_a637409e3fd74426bc5c840f395c1308"
}
