This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
elasticsearch-mcp is a Python MCP (Model Context Protocol) server that enables AI assistants to interact with Elasticsearch clusters. It uses the official elasticsearch Python client and provides tools for searching, aggregations, index management, and cluster operations.
pip install -e ".[dev]" # Install with dev dependencies
pytest # All tests
pytest tests/test_config.py # Single file
pytest --cov=elasticsearch_mcp --cov-report=html # With coverage
ruff check . # Lint
ruff format . # Format
mypy src/ # Type checkThe server (server.py:main) supports three transport modes via CLI args:
- stdio (default):
elasticsearch-mcp— for Claude Desktop local connections - SSE (legacy):
elasticsearch-mcp --http— HTTP/SSE for centralized deployment - Streamable HTTP:
elasticsearch-mcp --streamable-http— for Claude.ai Integrations with OAuth
Tools are registered via @mcp.tool() decorators on the module-level mcp FastMCP instance in server.py. Connection tools (connect, disconnect, cluster_health, etc.) are defined directly in server.py. Domain tools are implemented in tools/ modules and called from server.py tool wrappers.
src/elasticsearch_mcp/
├── server.py # FastMCP instance, connection/cluster tools, CLI entry, transport modes
├── connection.py # ConnectionManager: async connect/disconnect, health check
├── config.py # Settings (pydantic-settings): all env vars including auth, watchdog, audit
├── auth/ # OAuth for Claude.ai Integrations (Streamable HTTP mode only)
│ ├── provider.py # ESOAuthProvider: bridges Claude.ai DCR to external IdPs
│ ├── callback.py # /oauth/callback route handler
│ ├── storage.py # In-memory auth state (clients, codes, tokens, pending auths)
│ └── idp/ # Identity provider adapters
│ ├── base.py # BaseIdPAdapter ABC (get_authorization_url, exchange_code, validate_token)
│ ├── duo.py # Cisco Duo adapter
│ ├── auth0.py # Auth0 adapter
│ └── oidc.py # Generic OIDC adapter
├── tools/ # MCP tool implementations
│ ├── cluster.py # cluster_health, cluster_info, list_nodes, cluster_stats
│ ├── indices.py # list_indices, describe_index, get_index_stats, get_mappings, get_aliases
│ └── search.py # search, search_simple, count, get_document, aggregate, terms_aggregation, date_histogram
├── resources/ # MCP resources (placeholder)
└── utils/ # Utility modules (placeholder)
When --streamable-http with auth enabled:
- Claude.ai registers via DCR →
ESOAuthProvider.register_client() /authorize→ redirects to external IdP (Duo/Auth0/OIDC)- User authenticates → IdP callbacks to
/oauth/callback - Callback generates auth code → redirects to Claude's callback
- Claude exchanges code at
/token→ returns access/refresh tokens
A second FastMCP instance is created for Streamable HTTP mode, and tools/resources are copied from the module-level mcp instance.
server.py:mcp— module-level FastMCP instanceconfig.py:settings— module-level Settings instanceconnection.py:connection_manager— module-level ConnectionManager instance
Required: ES_HOST
Key optional groups:
- Auth:
ES_API_KEYorES_USERNAME/ES_PASSWORDorES_CLOUD_ID - Safety:
ES_READ_ONLY,ES_MAX_RESULTS,ES_BLOCKED_INDICES,ES_TIMEOUT - HTTP:
ES_HTTP_HOST,ES_HTTP_PORT,ES_HTTP_CORS_ORIGINS - OAuth:
ES_AUTH_ENABLED,ES_AUTH_ISSUER_URL,ES_IDP_PROVIDER,ES_IDP_DISCOVERY_URL,ES_IDP_CLIENT_ID,ES_IDP_CLIENT_SECRET,ES_DUO_API_HOST - Watchdog:
ES_WATCHDOG_ENABLED,ES_WATCHDOG_INTERVAL,ES_WATCHDOG_TIMEOUT - Audit:
ES_AUDIT_ENABLED,ES_AUDIT_PATH
All config is in config.py (Settings pydantic-settings class) with env_prefix="ES_".
Tests do not require a live Elasticsearch cluster. The tests/ directory contains mock-based unit tests. Key pattern:
- Config tests validate environment variable binding and defaults
- Tool tests mock the Elasticsearch client responses
- Follow PEP 8; use ruff for linting/formatting
- Maximum line length: 100 characters
- Type hints required for all function signatures
- Google-style docstrings for public APIs
- Ruff rules:
select = ["E", "F", "I", "N", "W", "UP"] - mypy:
disallow_untyped_defs = true
Connection Pattern: Use elasticsearch.AsyncElasticsearch for async operations. Single persistent connection via ConnectionManager with auto-reconnect.
Safety Controls: Index pattern validation via blocked_indices list (default: .security*,.kibana*,.apm*,.monitoring*), read-only mode, max results limit.
Schema Discovery: Use _cat/indices, _mapping, and _settings APIs for metadata.
Auth Layer: The OAuth module is database-agnostic — identical pattern across u2-mcp, pymssql-mcp, and elasticsearch-mcp (only class names and config types differ).
- u2-mcp - Universe/UniData MCP (auth module source)
- pymssql-mcp - SQL Server MCP