Custom Elasticsearch

Un servidor MCP simple para Elasticsearch, diseñado para entornos en la nube donde tu clave pública ya está autorizada.

Documentación

Servidor MCP de Elasticsearch personalizado

Un servidor MCP (Protocolo de Contexto de Modelo) sencillo para Elasticsearch, diseñado para entornos en la nube donde tu clave pública ya está autorizada en el servidor.

¿Por qué esta versión personalizada?

Sin necesidad de clave de API — A diferencia del servidor MCP oficial de Elasticsearch que requiere tanto ES_URL como ES_API_KEY, esta versión solo necesita la URL, ya que tu clave pública ya es de confianza en el servidor en la nube.

Herramientas mejoradas — Mejor usabilidad con parámetros opcionales y valores predeterminados mejorados en comparación con la versión oficial.

Qué hace esto

Este servidor MCP conecta Cursor a tu clúster de Elasticsearch con 4 herramientas potentes:

  • list_indices — Lista todos los índices (filtro de patrón opcional)
  • search — Soporte completo de Elasticsearch Query DSL
  • get_mappings — Obtiene los mapeos de campos para cualquier índice
  • get_shards — Ve la información de los fragmentos del clúster

Inicio rápido

Compilar desde el código fuente

git clone https://github.com/M0-AR/Custom-Elasticsearch-MCP-Server.git
cd Custom-Elasticsearch-MCP-Server
docker build -t elasticsearch-mcp:latest .

2. Agregar a la configuración de MCP en Cursor

Agrega esto a tu archivo .cursor/mcp.json:

Configuración:

{
    "mcpServers": {
        "elasticsearch-custom": {
            "command": "docker",
            "args": [
                "run",
                "-i",
                "--rm",
                "--add-host=host.docker.internal:host-gateway",
                "-e",
                "ES_URL=http://host.docker.internal:9400",
                "elasticsearch-mcp:latest"
            ]
        }
    }
}

3. Reiniciar Cursor

Cierra y vuelve a abrir Cursor. Deberías ver el servidor elasticsearch-custom con 4 herramientas habilitadas.

Configuración

Variables de entorno:

  • ES_URL — Tu URL de Elasticsearch (predeterminado: http://localhost:9400)
  • MAX_CONNECTIONS — Máximo de conexiones concurrentes (predeterminado: 100)
  • MAX_KEEPALIVE_CONNECTIONS — Máximo de conexiones keepalive (predeterminado: 20)
  • CONNECTION_TIMEOUT — Tiempo de espera de conexión en segundos (predeterminado: 30)
  • REQUEST_TIMEOUT — Tiempo de espera de solicitud en segundos (predeterminado: 30)

Para diferentes puertos de Elasticsearch:

"ES_URL=http://host.docker.internal:9200"

Para entornos de alto tráfico:

"MAX_CONNECTIONS=200",
"MAX_KEEPALIVE_CONNECTIONS=50",
"CONNECTION_TIMEOUT=60",
"REQUEST_TIMEOUT=60"

Ejemplo de uso

Una vez conectado en Cursor, puedes:

  • Listar todos los índices: "Muéstrame todos los índices de Elasticsearch"
  • Buscar datos: "Buscar datos de ventas en el índice hq.sales"
  • Obtener mapeos: "¿Qué campos hay en el índice hq.menuitems?"
  • Verificar el clúster: "Muéstrame el estado del clúster de Elasticsearch"

Comparación con el servidor oficial

CaracterísticaServidor oficialEste servidor personalizado
AutenticaciónRequiere ES_URL + ES_API_KEYSolo necesita ES_URL (clave pública autorizada)
list_indicesRequiere el parámetro indexPatternParámetro opcional con valor predeterminado "*"
Herramientas disponibles4 herramientas (mismas funciones)4 herramientas (usabilidad mejorada)
SeguridadBasada en clave de APIAutorización mediante clave pública
ConcurrenciaBloqueo síncronoAsíncrono con agrupación de conexiones
RendimientoUna solicitud a la vezMás de 100 solicitudes concurrentes

Manejo de solicitudes concurrentes

Este servidor MCP está diseñado para manejar múltiples solicitudes paralelas de varias aplicaciones simultáneamente, utilizando las mejores prácticas de la industria:

Características clave:

Arquitectura Async/Await — E/S sin bloqueo para procesamiento de solicitudes en paralelo ✅ Agrupación de conexiones — Reutiliza conexiones HTTP (hasta 100 concurrentes) ✅ Soporte HTTP/2 — Multiplexa múltiples solicitudes sobre una sola conexión ✅ Límites configurables — Ajusta los límites de conexión según tu carga de trabajo ✅ Seguro para subprocesos — FastMCP maneja la ejecución concurrente de herramientas de manera segura

Características de rendimiento:

  • Predeterminado: 100 conexiones concurrentes, 20 conexiones keepalive
  • Escalable: Configura hasta más de 1000 conexiones concurrentes
  • Eficiente: La reutilización de conexiones reduce la latencia en ~50%
  • Confiable: El manejo adecuado de tiempos de espera evita el agotamiento de conexiones

Configuración para alto tráfico:

{
    "mcpServers": {
        "elasticsearch-custom": {
            "command": "docker",
            "args": [
                "run", "-i", "--rm",
                "--add-host=host.docker.internal:host-gateway",
                "-e", "ES_URL=http://host.docker.internal:9400",
                "-e", "MAX_CONNECTIONS=200",
                "-e", "MAX_KEEPALIVE_CONNECTIONS=50",
                "-e", "CONNECTION_TIMEOUT=60",
                "-e", "REQUEST_TIMEOUT=60",
                "elasticsearch-mcp:latest"
            ]
        }
    }
}

Prueba de solicitudes concurrentes:

# Test 10 parallel requests
for i in {1..10}; do
    echo '{"jsonrpc": "2.0", "id": '$i', "method": "tools/call", "params": {"name": "list_indices", "arguments": {}}}' | \
    python3 simple_elasticsearch_mcp.py &
done
wait

Archivos

  • simple_elasticsearch_mcp.py — Servidor MCP principal
  • Dockerfile — Instrucciones de compilación del contenedor
  • requirements.txt — Dependencias de Python

Pruebas manuales

Prueba el servidor directamente:

python3 simple_elasticsearch_mcp.py

Prueba con comandos JSON-RPC:

1. Listar todas las herramientas:

echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {}}' | python3 simple_elasticsearch_mcp.py

2. Listar todos los índices:

echo '{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "list_indices", "arguments": {}}}' | python3 simple_elasticsearch_mcp.py

3. Buscar datos:

echo '{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "search", "arguments": {"index": "hq.sales", "queryBody": {"query": {"match_all": {}}, "size": 3}}}}' | python3 simple_elasticsearch_mcp.py

4. Obtener mapeos de índices:

echo '{"jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": {"name": "get_mappings", "arguments": {"index": "hq.menuitems"}}}' | python3 simple_elasticsearch_mcp.py

5. Verificar fragmentos del clúster:

echo '{"jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": {"name": "get_shards", "arguments": {}}}' | python3 simple_elasticsearch_mcp.py

Establecer una URL personalizada de Elasticsearch:

ES_URL="http://your-es-host:9200" python3 simple_elasticsearch_mcp.py

Solución de problemas

❌ Errores de "Conexión rechazada" o "tiempo de espera agotado"

Causa raíz: El problema más común es la red de contenedores Docker cuando Elasticsearch es accesible a través de un túnel SSH.

Solución: Asegúrate de que se cumplan estos requisitos:

1. El túnel SSH debe estar activo

Si tu Elasticsearch está detrás de un túnel SSH (común en implementaciones en la nube):

# Start SSH tunnel to forward port 9400
ssh -L 9400:localhost:9400 -N -f -l username your-server-ip

# Verify tunnel is working
curl -X GET "localhost:9400/_cluster/health?pretty"

2. Configuración correcta de Docker

Tu mcp.json debe usar exactamente esta configuración:

"elasticsearch-custom": {
    "command": "docker",
    "args": [
        "run",
        "-i",
        "--rm",
        "--add-host=host.docker.internal:host-gateway",
        "-e",
        "ES_URL=http://host.docker.internal:9400",
        "elasticsearch-mcp:latest"
    ]
}

Puntos clave:

  • ✅ Usa --add-host=host.docker.internal:host-gateway (no direcciones IP)
  • ✅ Usa ES_URL=http://host.docker.internal:9400 (no localhost)
  • ✅ El túnel SSH debe estar en ejecución antes de iniciar Cursor

3. Prueba la conectividad de Docker

# Test if Docker can reach your Elasticsearch
docker run --rm --add-host=host.docker.internal:host-gateway alpine/curl \
  curl -s http://host.docker.internal:9400/_cluster/health

4. Prueba completa de MCP con Docker

Prueba el flujo de trabajo completo de MCP con este comando integral:

# Full MCP server test with proper initialization
{
    echo '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "test-client", "version": "1.0.0"}}}';
    echo '{"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}';
    echo '{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "list_indices", "arguments": {}}}';
} | docker run -i --rm --add-host=host.docker.internal:host-gateway -e ES_URL="http://host.docker.internal:9400" elasticsearch-mcp:latest

Salida esperada:

  • Respuesta de inicialización con información del servidor
  • Lista de todos los índices de Elasticsearch en formato JSON
  • Sin mensajes de error

5. Alternativa: Modo de red de host

Si host-gateway no funciona, prueba el modo de red de host:

"args": [
    "run", "-i", "--rm", "--network=host",
    "-e", "ES_URL=http://localhost:9400",
    "elasticsearch-mcp:latest"
]

❌ "Se recibió una solicitud antes de que se completara la inicialización"

Causa raíz: El protocolo MCP requiere una secuencia de inicialización adecuada.

Solución: Siempre inicializa antes de llamar a las herramientas:

# Correct sequence:
echo '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "test", "version": "1.0"}}}'
echo '{"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}'
echo '{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "list_indices", "arguments": {}}}'

¡Eso es todo!

Compila → Agrega a la configuración → Reinicia Cursor → ¡Listo! 🚀