A comprehensive Model Context Protocol (MCP) server for Elasticsearch, written in Go. Provides 220 tools covering the entire Elasticsearch REST API surface, with YAML-configurable profiles to control which tools are exposed to AI clients.
Built for Elasticsearch 9.x. Tested against ES 9.3.0.
- 220 tools across 17 API domains -- full coverage of the Elasticsearch REST API
- YAML profile system -- 4 built-in profiles (full, readonly, minimal, admin), easily create your own
- Single binary -- ~10MB, no runtime dependencies
- Stdio transport -- works with Claude Desktop, Claude Code, and any MCP-compatible client
- Secure -- supports Basic auth, API key auth, and TLS with custom CA certificates
- Structured errors -- extracts Elasticsearch error details (type, reason, root cause) into clean responses
go build -o elasticsearch-mcp ./cmd/serverSet your Elasticsearch connection via environment variables:
export ES_BASE_URL=http://localhost:9200
# Optional auth:
# export ES_USERNAME=elastic
# export ES_PASSWORD=changeme
# Or:
# export ES_API_KEY=your-base64-api-keyThe server communicates over stdio (stdin/stdout) per the MCP protocol.
Add to your Claude Desktop claude_desktop_config.json:
{
"mcpServers": {
"elasticsearch": {
"command": "/path/to/elasticsearch-mcp",
"env": {
"ES_BASE_URL": "http://localhost:9200",
"ES_MCP_PROFILE": "full",
"ES_MCP_CONFIG_DIR": "/path/to/config"
}
}
}
}Add to your .mcp.json:
{
"mcpServers": {
"elasticsearch": {
"command": "/path/to/elasticsearch-mcp",
"env": {
"ES_BASE_URL": "http://localhost:9200",
"ES_MCP_PROFILE": "readonly"
}
}
}
}| API Domain | Tools | Examples |
|---|---|---|
| Documents | 13 | index, get, delete, update, bulk, reindex, mget, update/delete by query |
| Search | 16 | search, msearch, count, templates, scroll, PIT, field_caps, knn, explain |
| Indices | 37 | create, delete, mappings, settings, aliases, templates, shrink, split, clone, rollover, stats |
| Cluster & Nodes | 17 | health, state, stats, settings, allocation explain, reroute, nodes info/stats/hot_threads |
| Cat | 24 | indices, shards, nodes, health, aliases, allocation, thread_pool, ML jobs |
| Ingest | 5 | get/put/delete pipeline, simulate, grok patterns |
| Snapshot | 10 | repos, create/restore/delete snapshots, status, verify, cleanup |
| ILM | 10 | policies, explain, status, start/stop, retry, move to step |
| Data Streams | 5 | get, create, delete, stats, migrate |
| Security | 39 | users, roles, role mappings, privileges, API keys, tokens, SAML, OIDC, service tokens, cache |
| SQL | 3 | query, translate, clear cursor |
| EQL | 4 | search, async get/status/delete |
| Tasks | 3 | list, get, cancel |
| Scripts | 5 | get/put/delete, painless execute, languages |
| Transforms | 10 | get/put/delete, start/stop, preview, stats, reset, schedule, upgrade |
| Enrich | 5 | get/put/delete policy, execute, stats |
| Watcher | 11 | get/put/delete watch, execute, ack, activate/deactivate, stats, start/stop, query |
Total: 220 tools
Profiles control which tools are exposed to the MCP client. Set via ES_MCP_PROFILE environment variable.
| Profile | Enabled | Description |
|---|---|---|
full |
220 | All tools enabled (default) |
readonly |
114 | Read-only operations -- no create, update, or delete |
admin |
194 | Everything except destructive delete operations |
minimal |
17 | Essential everyday tools only |
Create a YAML file in config/profiles/:
# config/profiles/search-only.yaml
name: "search-only"
description: "Only search and read operations"
disable_unlisted: true
enable:
- es_search
- es_search_count
- es_search_template
- es_cat_indices
- es_cluster_healthProfile fields:
enable_all: true-- start with all tools enableddisable_unlisted: true-- start with all tools disabled, only enable listed onesenable: [...]-- list of tool names to enabledisable: [...]-- list of tool names to disable (useful withenable_all)
| Variable | Default | Description |
|---|---|---|
ES_BASE_URL |
http://localhost:9200 |
Elasticsearch endpoint URL |
ES_USERNAME |
Basic auth username | |
ES_PASSWORD |
Basic auth password | |
ES_API_KEY |
API key (base64-encoded, alternative to basic auth) | |
ES_CA_CERT |
Path to custom CA certificate for TLS | |
ES_INSECURE |
false |
Skip TLS verification |
ES_DEBUG |
false |
Enable debug logging |
ES_MCP_PROFILE |
full |
Active profile name |
ES_MCP_CONFIG_DIR |
(auto-detected) | Path to config directory containing tools.yaml |
.
├── cmd/server/
│ └── main.go # Entry point, MCP server setup
├── api/
│ ├── registry.go # Central registration of all API packages
│ ├── cat/ # _cat API tools
│ ├── cluster/ # Cluster + Nodes API tools
│ ├── datastreams/ # Data Stream API tools
│ ├── documents/ # Document API tools
│ ├── enrich/ # Enrich API tools
│ ├── eql/ # EQL API tools
│ ├── ilm/ # ILM API tools
│ ├── indices/ # Index Management API tools
│ ├── ingest/ # Ingest Pipeline API tools
│ ├── scripts/ # Scripts API tools
│ ├── search/ # Search API tools
│ ├── security/ # Security API tools
│ ├── snapshot/ # Snapshot API tools
│ ├── sql/ # SQL API tools
│ ├── tasks/ # Tasks API tools
│ ├── transforms/ # Transforms API tools
│ └── watcher/ # Watcher API tools
├── internal/
│ ├── client/ # HTTP client for Elasticsearch
│ ├── config/ # Config loading (env vars + YAML)
│ └── registry/ # Thread-safe tool registry
├── config/
│ ├── tools.yaml # Master tool definitions
│ └── profiles/
│ ├── full.yaml
│ ├── readonly.yaml
│ ├── minimal.yaml
│ └── admin.yaml
├── go.mod
└── go.sum
Each API domain is a self-contained Go package under api/. Every package follows the same pattern:
type Package struct{ client *client.Client }
func (p *Package) Tools() []mcp.Tool { /* tool definitions */ }
func (p *Package) Handlers() map[string]func { /* tool handlers */ }
func Register(reg *registry.Registry, c *client.Client) { /* registration */ }The central api/registry.go imports all 17 packages and calls their Register() functions. The internal/registry provides thread-safe tool management with enable/disable filtering based on the active profile.
- Go 1.23+
- Elasticsearch 8.x or 9.x
MIT