Helm MCP
Servidor MCP para trabajar con gráficos de Helm
Documentación
Servidor MCP Helm
Un servidor MCP (Model Context Protocol) que proporciona herramientas para interactuar con repositorios y charts de Helm. Este servidor permite a los asistentes de IA consultar repositorios de Helm, recuperar información de charts y acceder a los valores de los charts sin requerir una instalación local de Helm.
El propósito de usar MCP para Helm es evitar inventar el formato de values.yaml y los contenidos de los charts al trabajar
con LLMs.
En su lugar, el servidor proporciona una forma estandarizada de acceder a esta información, facilitando a los asistentes de IA la
interacción con charts y repositorios de Helm.
Este servidor MCP proporciona y proporcionará herramientas para trabajar únicamente con repositorios de Helm. Si necesitas trabajar con otros recursos de Kubernetes, considera usar un servidor MCP separado que proporcione herramientas para recursos de Kubernetes.
Características
El servidor MCP Helm proporciona las siguientes herramientas:
- list_repository_charts - Lista todos los charts disponibles en un repositorio de Helm (o nombre del chart para registros OCI)
- list_chart_versions - Lista todas las versiones/etiquetas disponibles para un chart
- get_latest_version_of_chart - Recupera la última versión estable (no preliminar) de un chart específico
- get_chart_values - Recupera el archivo de valores de un chart (última versión o versión específica)
- get_chart_contents - Recupera el contenido de un chart (incluyendo plantillas, valores y metadatos), opcionalmente
filtrado por patrones glob de rutas de archivo (por ejemplo,
templates/**) - get_chart_dependencies - Recupera las dependencias de un chart según lo definido en su archivo
Chart.yaml - get_chart_images - Extrae imágenes de contenedores utilizadas en un chart de Helm renderizando plantillas y analizando manifiestos de Kubernetes
Tipos de Repositorio
Todas las herramientas admiten tanto repositorios HTTP tradicionales de Helm como registros OCI:
| Tipo de Repositorio | URL de Ejemplo |
|---|---|
| Repositorio HTTP | https://charts.example.com |
| Registro OCI | oci://ghcr.io/org/charts/mychart |
| OCI (Docker Hub) | oci://docker.io/library/mysql |
Soporte de Registros OCI
Los registros OCI (Open Container Initiative) almacenan charts de Helm como artefactos OCI. A diferencia de los repositorios HTTP donde múltiples charts comparten un índice, los registros OCI típicamente contienen un chart por repositorio con múltiples etiquetas de versión.
Ejemplo de uso con OCI:
repository_url: oci://ghcr.io/nginxinc/charts/nginx-ingress
chart_name: (empty - chart name is in the URL)
Probar sin instalación
Hay una instancia disponible públicamente del servidor MCP Helm que puedes usar para probar las características sin instalarlo: https://mcp-helm.zekker.dev/mcp
Instalación
Ejecutar con docker
Puedes ejecutar el servidor MCP Helm usando Docker. Esta es la forma más fácil de comenzar sin necesidad de instalar Go o compilar desde el código fuente.
docker run -d --name mcp-helm -p 8012:8012 ghcr.io/zekker6/mcp-helm:v1.3.0 -mode=sse
Ten en cuenta que la bandera --mode=sse se usa para habilitar el modo Server-Sent Events, que utilizan los clientes MCP para conectarse.
Alternativamente, puedes usar -mode=http para habilitar el modo HTTP Streamable.
Mediante binario precompilado
Descarga el binario desde la página de lanzamientos.
Ejemplo para Linux x86_64 (ten en cuenta que también están disponibles otras arquitecturas y plataformas):
latest=$(curl -s https://api.github.com/repos/zekker6/mcp-helm/releases/latest | grep 'tag_name' | cut -d\" -f4)
wget https://github.com/zekker6/mcp-helm/releases/download/$latest/mcp-helm_Linux_x86_64.tar.gz
tar axvf mcp-helm_Linux_x86_64.tar.gz
Mediante Mise
Mise (mise-en-place) es una herramienta de configuración del entorno de desarrollo.
mise i ubi:zekker6/mcp-helm@latest
Instalar con Go
Nota: Se requiere Go 1.26.0.
go install github.com/zekker6/mcp-helm/cmd/mcp-helm@latest
Compilar desde el Código Fuente
Nota: Se requiere Go 1.26.0.
-
Clona el repositorio:
git clone https://github.com/zekker6/mcp-helm.git cd mcp-helm -
Compila el binario:
go build -o mcp-helm ./cmd/mcp-helm -
Ejecuta el servidor:
./mcp-helm
Configuración
Configura tu cliente MCP para conectarse a este servidor. El servidor implementa el protocolo MCP estándar para el descubrimiento de herramientas y su ejecución.
En los modos http y sse, los cuerpos POST están limitados a 8 MiB. Las solicitudes más grandes reciben HTTP 413, incluyendo
cargas fragmentadas sin Content-Length. El servidor HTTP permite 5 segundos para los encabezados de solicitud, 30 segundos para
encabezados y cuerpo juntos, y 60 segundos para conexiones inactivas. Las respuestas SSE no tienen plazo de escritura y pueden permanecer
abiertas más allá de estos presupuestos de lectura de solicitudes. Estos límites no limitan el trabajo realizado por una llamada de herramienta aceptada.
Caché de índice de repositorio
El índice de un repositorio HTTP de Helm se descarga en el primer uso y se reutiliza durante -repo-index-max-age (por defecto 1h).
Una vez que se supera esa antigüedad, la siguiente solicitud descarga el índice nuevamente, por lo que las versiones de charts recién publicadas aparecen
sin necesidad de reiniciar. Establece -repo-index-max-age=0 para descargar el índice en cada solicitud. Los registros OCI siempre se
consultan en vivo.
De forma predeterminada, cada cliente retiene como máximo 16 índices de repositorio con un presupuesto de bytes de origen derivado de su asignación de memoria al inicio, desalojando los índices menos recientemente utilizados cuando se alcanza cualquiera de los límites. El servidor MCP comparte un cliente de Helm y su caché entre solicitudes. Los objetos Go analizados añaden sobrecarga de memoria; esto no es un límite de montón del proceso. El desalojo no cambia las instantáneas ya retenidas por solicitudes activas. Los archivos de índice usan un directorio temporal privado que se elimina después del análisis, incluso en caso de fallo de descarga o análisis. Los archivos de charts HTTP se cargan directamente desde la memoria. Los archivos existentes en los directorios de caché compartidos de Helm no se leen ni se eliminan. Las instantáneas en caché no retienen contextos de solicitud ni clientes de descarga.
Límites de caché y descarga
Los valores predeterminados son constantes nombradas en lib/helm_client/limits.go y lib/helm_client/memory.go. Anúlalos con variables de entorno leídas al
crear el cliente de Helm. Los valores deben ser enteros decimales positivos, con límites de bytes expresados en bytes, no en MiB
u otras unidades con sufijo. Una variable no establecida usa su valor predeterminado; los valores vacíos, cero, negativos, malformados o desbordados
fallan al inicio. Los clientes existentes no recargan los cambios en el entorno. La bandera -repo-index-max-age aún controla el TTL.
| Variable de entorno | Predeterminado | Controla |
|---|---|---|
MCP_HELM_REPO_CACHE_MAX_ENTRIES | 16 | Recuento de índices de repositorio retenidos |
MCP_HELM_REPO_CACHE_MAX_BYTES | Automático, descrito a continuación | Bytes totales de origen de índice retenidos |
MCP_HELM_INDEX_MAX_BYTES | 33554432 (32 MiB) | Bytes por descarga de índice HTTP |
MCP_HELM_CHART_MAX_BYTES | 104857600 (100 MiB) | Bytes por archivo de chart HTTP comprimido |
MCP_HELM_OCI_MAX_BYTES | 134217728 (128 MiB) | Bytes totales del cuerpo de respuesta por extracción OCI |
Cuando MCP_HELM_REPO_CACHE_MAX_BYTES no está establecido, el cliente usa 1/16 de la asignación de memoria más pequeña detectada,
limitada a 256 MiB. Considera los límites de cgroup v1/v2 de Linux, incluidos los límites principales visibles, el límite de memoria actual del
tiempo de ejecución de Go inicializado por GOMEMLIMIT, y la RAM total del host. No usa memoria libre fluctuante ni solicitudes
de memoria de Kubernetes. Este cálculo nunca cambia el límite de memoria de Go.
| Asignación de memoria | Presupuesto automático de bytes de origen de caché |
|---|---|
| 512 MiB | 32 MiB |
| 1 GiB | 64 MiB |
| 2 GiB | 128 MiB |
| 4 GiB o más | 256 MiB |
Si no se puede detectar ningún límite, el cliente recurre a 64 MiB. Un error de detección, como un controlador de contenedor ilegible, limita el resultado a 64 MiB mientras preserva cualquier presupuesto detectado más pequeño. Los registros de inicio informan el modo de dimensionamiento, el presupuesto seleccionado, la asignación y fuente detectadas cuando están disponibles, y cualquier error de detección. No se ejecuta ningún redimensionamiento en segundo plano; los cambios de asignación surten efecto cuando se inicia un nuevo cliente. Una anulación explícita de bytes evita la detección y el límite automático. En asignaciones pequeñas, un índice válido más grande que el presupuesto de caché puede descargarse pero no se retendrá. Estos presupuestos de bytes de origen no son límites de montón medidos y no evitan OOM por trabajo concurrente.
El presupuesto OCI incluye manifiestos, configuración, capas de charts, respuestas de autenticación, redirecciones y reintentos.
Las extracciones concurrentes tienen presupuestos independientes. Las respuestas sin Content-Length se verifican mientras se leen; las descargas
sobredimensionadas fallan en lugar de truncarse y analizarse. Estos límites no limitan las solicitudes concurrentes ni la memoria de renderizado de charts.
El límite de contenido de charts descomprimidos de Helm aún se aplica. Las descargas OCI respetan tanto la cancelación del llamador como la
cancelación de solicitudes del registro, incluso mientras se leen los cuerpos de respuesta.
Por ejemplo, permite un conjunto de trabajo más grande e índices individuales más grandes:
env MCP_HELM_REPO_CACHE_MAX_ENTRIES=32 \
MCP_HELM_REPO_CACHE_MAX_BYTES=134217728 \
MCP_HELM_INDEX_MAX_BYTES=67108864 \
./mcp-helm -mode=http
Validación de un servidor compartido
Ejecuta task test:repos para obtener índices actuales de Prometheus Community, Grafana, Bitnami, Jetstack, Argo e
ingress-nginx. Verifica el conjunto de trabajo contra los límites configurados, reproduce esos índices exactos localmente con
ocho llamadores concurrentes, verifica la reutilización de caché en caliente y descarga un chart representativo de cada repositorio
público. La fase de carga repetida no accede a servidores públicos. La prueba registra tamaños de origen, latencia, fallos
y uso de montón de Go en repositorio, que incluye los accesorios de prueba capturados y no es RSS del proceso. Los fallos de puntos finales públicos o
formatos de charts fallan la prueba en lugar de omitirse. task test mantiene esta verificación de red deshabilitada;
task test:all compila el binario y ejecuta las pruebas unitarias, de extremo a extremo y de repositorio público juntas.
CI ejecuta task test:all después del linting, por lo que la verificación de repositorio público también controla los cambios.
Para índices que referencian charts OCI, también prueba la referencia OCI directa por separado. El cargador de repositorio HTTP
actualmente no sigue URLs de archivo oci://, incluido el chart nginx de Bitnami; usa la URL de repositorio OCI directa
para esos charts. Este fallo de compatibilidad permanece visible en la prueba pública.
Las pruebas regulares también ejercitan ocho clientes MCP HTTP independientes contra repositorios locales, incluido el desalojo forzado de caché y descargas repetidas de charts. Una ejecución exitosa es una verificación de regresión de compatibilidad y concurrencia, no una garantía de capacidad de producción. Los límites de caché limitan la retención, no el número de usuarios activos. Las búsquedas de índice en frío aún comparten un bloqueo global, y los archivos de charts se descargan en cada solicitud. Dimensiona el límite de índice para el repositorio más grande y el límite de bytes de caché para el conjunto de trabajo completo utilizado con frecuencia, con espacio para crecimiento.
Autenticación
El servidor admite autenticación tanto para registros OCI como para repositorios HTTP de Helm.
Al incrustar el cliente Go, las descargas de repositorios HTTP clonan http.DefaultTransport si es un *http.Transport.
Si está envuelto o reemplazado con otro http.RoundTripper, las descargas usan un transporte privado con soporte
de proxy de entorno en su lugar. El envoltorio no se usa; las opciones TLS del repositorio del cliente aún se aplican.
Banderas de Línea de Comandos
| Bandera | Descripción |
|---|---|
-username | Nombre de usuario para autenticación básica (repos HTTP, y registros OCI no cubiertos por -registry-credentials) |
-password-file | Ruta al archivo que contiene la contraseña |
-registry-credentials | Ruta al archivo de credenciales estilo Docker (por ejemplo, ~/.docker/config.json); autoritativo para los registros OCI que lista |
-registry-plain-http | Usar HTTP simple para registros OCI (inseguro, solo para desarrollo) |
-tls-cert | Ruta al archivo de certificado de cliente TLS para repositorios HTTP |
-tls-key | Ruta al archivo de clave de cliente TLS para repositorios HTTP |
-tls-ca | Ruta al archivo de certificado CA para verificar certificados del servidor |
-tls-insecure-skip-verify | Omitir verificación de certificado TLS (inseguro) |
-pass-credentials-all | Enviar credenciales de repositorio HTTP a todas las URLs de charts y orígenes de redirección (inseguro) |
Las credenciales de repositorios HTTP se envían al propio esquema, host y puerto del repositorio por defecto. Los archivos de chart en otros orígenes aún se pueden descargar, pero no reciben credenciales del repositorio, incluso después de redirecciones o una degradación de HTTPS a HTTP. -pass-credentials-all opta por enviar esas credenciales a cada URL de chart y origen de redirección. Úsalo solo cuando confíes en las URLs de chart del repositorio y en cada destino de redirección. |
Autenticación Básica
Para repositorios que requieren autenticación de usuario/contraseña:
# Create a password file (recommended for security)
echo "your-password" > /path/to/password.txt
chmod 600 /path/to/password.txt
# Run with basic auth
./mcp-helm -username myuser -password-file /path/to/password.txt
Autenticación de Registro OCI
Para registros OCI privados, la autenticación se puede configurar mediante:
- Credenciales de Docker - El servidor usa automáticamente las credenciales de
~/.docker/config.json - Archivo de credenciales explícito - Usa la bandera
-registry-credentials
# Using Docker login (credentials stored in ~/.docker/config.json)
docker login ghcr.io
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
# Using explicit credentials file
./mcp-helm -registry-credentials /path/to/docker/config.json
# Using basic auth for OCI registry
./mcp-helm -username myuser -password-file /path/to/password.txt
Combinando autenticación básica con un archivo de credenciales de registro
Una sola instancia puede servir repositorios HTTP privados y registros OCI privados al mismo tiempo. Cuando tanto -username/-password-file como -registry-credentials están configurados, las solicitudes OCI se enrutan por host de registro:
- Si el archivo de credenciales resuelve una credencial para el host de registro del chart, se usa esa credencial por host (
auths,credHelpersycredsStorese consultan todas, usando la misma resolución de credenciales de Docker que el CLI de Helm, por lo que la clave canónicahttps://index.docker.io/v1/de Docker Hub se empareja correctamente). - De lo contrario, se usa la autenticación básica estática
-username/-password-file.
Esto permite que -registry-credentials siga siendo autoritativo para los registros OCI que cubre, mientras que la autenticación básica aún se aplica a los repositorios HTTP (y a cualquier registro OCI que el archivo de credenciales no resuelva).
# HTTP repos use basic auth; OCI hosts in config.json use their per-host creds
./mcp-helm \
-username myuser -password-file /path/to/password.txt \
-registry-credentials /path/to/docker/config.json
Las credenciales detrás de un almacén de credenciales externo (credsStore) o un helper por registro (credHelpers) se resuelven invocando ese binario helper en tiempo de ejecución. Si el helper no está disponible en el entorno de ejecución, los registros afectados vuelven a la autenticación básica; se registra una advertencia al inicio para que esto sea visible. El enrutamiento considera solo el archivo pasado a -registry-credentials (sin respaldo implícito de ~/.docker/config.json), así que lista cada registro OCI privado que necesites en ese archivo.
Configuración TLS/mTLS
Para repositorios con requisitos TLS personalizados:
# Custom CA certificate (for self-signed or internal CAs)
./mcp-helm -tls-ca /path/to/ca.crt
# Client certificate authentication (mTLS)
./mcp-helm -tls-cert /path/to/client.crt -tls-key /path/to/client.key
# Combined: mTLS with custom CA
./mcp-helm -tls-cert client.crt -tls-key client.key -tls-ca ca.crt
# Skip TLS verification (development only, not recommended for production)
./mcp-helm -tls-insecure-skip-verify
Configuración de Docker
Ejemplo con Docker, pasando autenticación:
# With basic auth
docker run -d --name mcp-helm -p 8012:8012 \
-v /path/to/password.txt:/secrets/password.txt:ro \
ghcr.io/zekker6/mcp-helm:v1.3.0 \
-mode=sse -username myuser -password-file /secrets/password.txt
# With Docker credentials
docker run -d --name mcp-helm -p 8012:8012 \
-v ~/.docker/config.json:/root/.docker/config.json:ro \
ghcr.io/zekker6/mcp-helm:v1.3.0 \
-mode=sse
Observabilidad
El servidor puede exportar trazas, métricas y registros de OpenTelemetry a través de OTLP. Está deshabilitado por defecto: con OTEL_ENABLED sin configurar, no se exporta nada, no se construye ningún exportador, no se registra ningún proveedor globalmente y no se instala instrumentación, por lo que el binario se comporta exactamente como hoy.
OTEL_ENABLED es el único interruptor. OTEL_SDK_DISABLED no se consulta, ni tampoco OTEL_EXPORTER_OTLP_PROTOCOL: el protocolo de cable proviene del esquema del endpoint, descrito a continuación.
Variables de Entorno
| Variable | Default | Descripción |
|---|---|---|
OTEL_ENABLED | false | Interruptor principal. La telemetría se configura solo cuando esto contiene un valor verdadero (true, 1, t) |
OTEL_EXPORTER_OTLP_ENDPOINT | - | Endpoint base para las tres señales. Requerido cuando está habilitado, a menos que cada endpoint por señal esté configurado |
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | endpoint base | Anulación solo de trazas, usada textualmente (incluye la ruta completa para HTTP) |
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT | endpoint base | Anulación solo de métricas, usada textualmente |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | endpoint base | Anulación solo de registros, usada textualmente |
OTEL_SERVICE_NAME | mcp-helm | Nombre del servicio reportado al colector |
OTEL_RESOURCE_ATTRIBUTES | - | Atributos de recurso adicionales, p. ej. deployment.environment.name=production |
OTEL_EXPORTER_OTLP_HEADERS | - | Cabeceras enviadas con cada exportación, p. ej. para autenticación. Leídas por los exportadores del SDK |
OTEL_EXPORTER_OTLP_TIMEOUT | 10000 | Tiempo de espera de exportación en milisegundos. Leído por los exportadores del SDK |
OTEL_EXPORTER_OTLP_COMPRESSION | - | Configúralo a gzip para comprimir exportaciones. Leído por los exportadores del SDK |
OTEL_METRIC_EXPORT_INTERVAL | 60000 | Intervalo de exportación de métricas en milisegundos |
OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION | base2_exponential_bucket_histogram | Agregación de histogramas para ambos transportes OTLP. Configúralo a explicit_bucket_histogram para buckets clásicos |
OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE | cumulative | Los contadores e histogramas se acumulan desde su inicio o reinicio. El SDK también acepta delta y lowmemory |
OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT | 4096 | Valor de atributo de span más largo; los más largos se truncan. El default del SDK es ilimitado, pero varios valores provienen de clientes. OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT tiene prioridad, y -1 levanta el límite |
OTEL_EXPORTER_OTLP_CERTIFICATE | raíces del sistema | Paquete de CA PEM usado para verificar un colector https:// o grpcs://. Leído por los exportadores del SDK |
OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE | - | Certificado de cliente PEM para mTLS al colector. Leído por los exportadores del SDK |
OTEL_EXPORTER_OTLP_CLIENT_KEY | - | Clave de cliente PEM para mTLS al colector. Leído por los exportadores del SDK |
Cuando la telemetría está habilitada y falta un endpoint o está malformado, el servidor sale con un código no cero y un error que nombra la variable problemática; un error tipográfico nunca degrada silenciosamente a "sin telemetría". Con OTEL_ENABLED desactivado, las variables de endpoint no se analizan en absoluto, por lo que un valor obsoleto en el entorno no puede romper el inicio.
Atributos de Recurso
El servidor configura service.name (de OTEL_SERVICE_NAME, si no mcp-helm) y service.version por sí mismo, y lee cualquier otra cosa de OTEL_RESOURCE_ATTRIBUTES. Las convenciones semánticas requieren más que eso, y el resto tiene que venir del despliegue:
| Atributo | De dónde debería venir |
|---|---|
deployment.environment.name | OTEL_RESOURCE_ATTRIBUTES. Nota el sufijo .name - el deployment.environment simple está obsoleto |
service.instance.id | OTEL_RESOURCE_ATTRIBUTES de la API descendente. Requerido una vez que más de una réplica se ejecuta, o las series de cada instancia colisionan |
service.namespace | OTEL_RESOURCE_ATTRIBUTES, cuando otros servicios comparten el backend |
k8s.pod.uid y otros k8s.* | El procesador k8sattributes del Colector, que es la forma soportada de agregarlos |
En Kubernetes, los dos primeros provienen de la API descendente:
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: OTEL_RESOURCE_ATTRIBUTES
value: deployment.environment.name=production,service.instance.id=$(POD_NAME)
Esquemas de Endpoint
El protocolo de cable y TLS provienen del esquema de URL del endpoint:
| Endpoint | Protocolo | TLS | Las exportaciones van a |
|---|---|---|---|
grpc://collector:4317 | OTLP/gRPC | no | collector:4317 |
grpcs://otel.example.com:4317 | OTLP/gRPC | sí | otel.example.com:4317 |
http://collector:4318 | OTLP/HTTP | no | http://collector:4318/v1/traces, /v1/metrics, /v1/logs |
https://otel.example.com | OTLP/HTTP | sí | https://otel.example.com/v1/traces, /v1/metrics, /v1/logs |
Cualquier otro esquema es un error de inicio que nombra los cuatro esquemas aceptados.
- El endpoint base es una URL base: para HTTP, la ruta de señal (
/v1/traces,/v1/metrics,/v1/logs) se agrega, después de recortar una barra diagonal final. Se maneja un endpoint de colector inyectado con una barra diagonal final. - Un endpoint por señal se usa textualmente, como requiere la especificación OTLP, por lo que para HTTP tiene que llevar la ruta completa incluyendo
/v1/tracesy similares. - Los endpoints gRPC conservan solo
host:port; gRPC no tiene ruta de señal, por lo que cualquier ruta se descarta. - El protocolo se resuelve por señal, por lo que las configuraciones mixtas funcionan: trazas sobre gRPC mientras métricas y registros van por HTTP es una configuración soportada. Para registros,
grpcs://requiere TLS incluso sin una CA personalizada; usaOTEL_EXPORTER_OTLP_CERTIFICATEoOTEL_EXPORTER_OTLP_LOGS_CERTIFICATEpara una CA privada.
Ejemplos de Configuración
Un endpoint para las tres señales:
OTEL_ENABLED=true \
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 \
./mcp-helm -mode=http
Las trazas, métricas y registros se envían a http://otel-collector:4318/v1/traces, /v1/metrics y /v1/logs. Cambiar ese endpoint a grpc://otel-collector:4317 mueve las tres señales a OTLP/gRPC sin ningún otro cambio.
Endpoints por señal, mezclando protocolos y TLS:
OTEL_ENABLED=true \
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=grpc://otel-collector:4317 \
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://metrics.example.com/v1/metrics \
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://logs.example.com/v1/logs \
OTEL_SERVICE_NAME=mcp-helm \
OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production \
./mcp-helm -mode=http
Con Docker:
docker run -d --name mcp-helm -p 8012:8012 \
-e OTEL_ENABLED=true \
-e OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 \
ghcr.io/zekker6/mcp-helm:latest -mode=http
Las variables OTEL_* son ignoradas por imágenes construidas antes de que llegara el soporte de OpenTelemetry, así que fija una etiqueta que lo tenga o usa latest.
Qué Se Emite
Trazas
Una llamada de herramienta sobre HTTP produce una traza desde la solicitud entrante hasta el trabajo de Helm que desencadena:
POST /mcp (HTTP server span)
tools/call get_chart_images (MCP server span)
tool.get_chart_images (MCP tool span)
helm.get_chart_images (Helm operation span)
helm.load_chart
helm.oci.pull
helm.parse.images
Los nombres de telemetría personalizados usan el espacio de nombres específico de la aplicación mcp_helm.*, sin un dominio personal. Los atributos específicos de Helm a continuación omiten su prefijo mcp_helm.helm. para legibilidad; los nombres emitidos lo incluyen.
Guía de nomenclatura de OpenTelemetry
recomienda evitar colisiones con espacios de nombres estándar, no un prefijo DNS inverso obligatorio. Los atributos de registro (url.full, server.address, server.port, error.type, gen_ai.*, mcp.*, jsonrpc.*, rpc.*) se muestran completos.
Las consultas existentes que usan el espacio de nombres personalizado anterior deben actualizarse; los nombres estándar de OTel no cambian.
| Span | Kind | Attributes |
|---|---|---|
<METHOD> <route> | servidor | otelhttp Convenciones semánticas del servidor HTTP, más el mensaje JSON-RPC que un POST transportó (abajo). Solo en modos sse y http |
<mcp method> [<tool>] | servidor | mcp.method.name, jsonrpc.request.id, gen_ai.tool.name, gen_ai.operation.name, mcp.session.id, mcp.protocol.version, network.transport, network.protocol.name, rpc.response.status_code, error.type |
tool.<name> | interno | - |
helm.list_charts | interno | repository.url, repository.type, chart.count |
helm.list_chart_versions | interno | + chart.name, version.count |
helm.get_latest_version | interno | + chart.name, chart.version (resuelto) |
helm.get_latest_values | interno | + chart.name, chart.version (resuelto). Solo biblioteca; ninguna herramienta MCP lo alcanza |
helm.get_chart_values | interno | + chart.name, chart.version |
helm.get_chart_contents | interno | + chart.name, chart.version, recursive |
helm.get_chart_dependencies | interno | + chart.name, chart.version, dependency.count |
helm.get_chart_images | interno | + chart.name, chart.version, recursive, image.count |
helm.load_chart | interno | repository.type, chart.name, chart.version |
helm.oci.pull | cliente | oci.ref, server.address, server.port |
helm.oci.tags | cliente | oci.ref, server.address, server.port |
helm.repo.index | cliente | repository.url, server.address, server.port |
helm.chart.download | cliente | url.full, server.address, server.port |
helm.parse.images | interno | recursive |
helm.parse.contents | interno | recursive |
Un span con fallo se marca con un estado ERROR, registra la excepción y lleva error.type. Los atributos de URL se
sanean: la información de usuario user:password@ se elimina antes de que una URL de repositorio, OCI o chart se convierta en un atributo de span.
El span helm.chart.download informa url.full porque la URL del chart es el recurso exacto que se obtiene.
helm.repo.index no lo hace: el getter de Helm resuelve la ruta del índice por sí mismo, por lo que la URL que este servidor mantiene no es la
solicitada.
El span del servidor MCP sigue las convenciones semánticas de MCP:
se llama {mcp.method.name} {target}, como tools/call get_chart_values, tools/list o ping. Solo una
herramienta registrada se convierte en el objetivo, ya que el cliente elige el nombre; una no registrada aún llega a
gen_ai.tool.name. Un método que mcp-go no implementa se registra como mcp.method.name=_OTHER en un span llamado MCP, de la
misma manera que la instrumentación HTTP trata un método desconocido, por lo que un cliente no puede crear un nombre de span por solicitud. El servidor traza
a través de su propio adaptador para la interfaz de trazado de mcp-go en lugar de github.com/mark3labs/mcp-go/otel, y omite
las claves mcp.method y mcp.tool.name que mcp-go establece: el registro no define ninguna. Los spans de método desconocido actualmente
omiten jsonrpc.request.id porque mcp-go no expone el ID al trazador ni a los hooks de error en esa ruta.
La corrección diferida requiere soporte de la API ascendente.
mcp.protocol.version registra la versión efectiva de la solicitud solo cuando mcp-go la reconoce. Los valores de metadatos no admitidos
y los encabezados de protocolo sin procesar no se copian en spans o métricas. network.transport es tcp en modos sse y
http, junto con network.protocol.name=http, y pipe en modo stdio.
Una solicitud respondida con un error JSON-RPC lleva el código en rpc.response.status_code. El atributo de convenciones
-32700, -32600, -32601, -32602 (que incluye una herramienta desconocida) y -32002 al llamador, por lo que esos dejan
error.type sin establecer y el estado del span UNSET. Cualquier otro código establece error.type al código y el estado a ERROR,
descrito por el mensaje de error JSON-RPC. Un manejador de herramienta que informó el fallo a su llamador en lugar de devolver
un error establece error.type a tool_error, también con un estado ERROR.
Cada span POST de grabación también registra qué mensaje JSON-RPC llevaba su cuerpo, como mcp_helm.jsonrpc.message.kind
(request, notification o response). Una notificación agrega mcp.method.name, _OTHER para un método que el registro
no lista, y una respuesta agrega jsonrpc.request.id. mcp-go abre un span MCP solo para las solicitudes que despacha,
por lo que para notificaciones y para las respuestas de un cliente a pings del servidor, que son la mayoría de los POSTs que una sesión inactiva envía, el
span HTTP es el único registro. El método y el id de una solicitud permanecen en su span MCP, por lo que una consulta sobre ellos cuenta cada solicitud
una vez. La captura de anotaciones está limitada a 64 KiB; los cuerpos más grandes no se analizan ni anotan. Los spans sin grabación omiten
la captura por completo. Estos límites afectan solo a la telemetría: el transporte aún recibe el cuerpo original y los errores de lectura.
Los encabezados W3C entrantes traceparent / tracestate se respetan en modos sse y http, por lo que una llamada de herramienta se une al
rastro del llamador en lugar de iniciar uno nuevo. El contexto de rastro que un cliente pone en el params._meta de una solicitud (SEP-414)
es padre del span del servidor MCP en todos los modos, stdio incluido, ya que las convenciones hacen que el span del cliente MCP sea su padre.
Cuando esto reemplaza un contexto de transporte existente, el span MCP enlaza a ese contexto, preservando la conexión con el
span HTTP incluso entre rastros diferentes. Los metadatos ausentes o inválidos mantienen el padre existente sin un enlace adicional.
Sin ninguno de los dos, cada solicitud MCP en modo stdio es un span raíz.
Métricas
| Métrica | Tipo | Unidad | Atributos |
|---|---|---|---|
mcp.server.operation.duration | histograma | s | mcp.method.name, gen_ai.tool.name, gen_ai.operation.name, mcp.protocol.version, network.transport, network.protocol.name, rpc.response.status_code, error.type |
mcp_helm.helm.operation.duration | histograma | s | …helm.operation, …helm.repository.type, error.type |
http.server.* | de otelhttp | - | http.server.request.duration, http.server.request.body.size, http.server.response.body.size. Solo modos sse/http |
go.* | de la instrumentación de runtime OTel | - | Métricas de memoria, GC y goroutines de Go |
mcp.server.operation.duration es el histograma que las convenciones semánticas de MCP definen para el lado receptor. Cubre
cada solicitud para la que mcp-go abre un span, desde la recepción hasta que la respuesta está lista, incluidas las que responde con un
error. Las notificaciones no se miden, ni tampoco un mensaje que mcp-go rechaza antes de ese punto (JSON malformado, una
versión jsonrpc incorrecta), ya que ninguno obtiene un span.
Todos los histogramas, incluidos los de MCP, Helm, HTTP y runtime, usan por defecto agregación exponencial de base 2 sobre OTLP/HTTP y OTLP/gRPC. Los buckets se adaptan a los valores registrados, con un máximo de 160 buckets por rango positivo o negativo y una escala máxima de 20. Las métricas usan temporalidad acumulativa por defecto: las exportaciones repetidas retienen observaciones anteriores en lugar de informar solo el último intervalo. Los reinicios del proceso restablecen los valores acumulativos.
Las variables de entorno estándar anteriores pueden anular cualquiera de los dos valores predeterminados de forma independiente. Cuando se selecciona una
agregación explícita, los histogramas de duración de MCP y Helm usan los límites recomendados de 10 ms a 300 s. Asegúrese de que su
Collector y backend acepten histogramas exponenciales; las consultas que requieren series clásicas _bucket pueden necesitar actualización.
error.type está ausente en éxito, que es lo que especifican las convenciones: no filtre por un valor ok, filtre por
el atributo no establecido. En mcp.server.operation.duration coincide con el span: el código de error JSON-RPC a menos que el
atributo de convenciones atribuya ese código al llamador, o tool_error para un manejador de herramienta que informó el fallo a su
llamador (mcp-go lo entrega como una respuesta exitosa que lleva un resultado de error). Un manejador de herramienta que entra en pánico se responde
con -32603. En mcp_helm.helm.operation.duration contiene el tipo de error de Go. Las tasas de los valores de conteo de los histogramas
proporcionan tasas de llamadas, por lo que no hay un contador separado.
Las operaciones de Helm se anidan, y cada nivel registra su propio punto: get_latest_values envuelve get_latest_version y
get_chart_values, y cualquier llamada de herramienta que omita chart_version registra get_latest_version antes de la operación que
se le pidió. Filtre por mcp_helm.helm.operation en lugar de sumar los conteos de histogramas entre operaciones, o una llamada lógica
se cuenta más de una vez.
Los atributos de métricas son deliberadamente de baja cardinalidad: las URLs de repositorios, nombres de charts y versiones de charts aparecen solo en spans,
nunca en una métrica. gen_ai.tool.name se registra solo para herramientas registradas y mcp.method.name cae a
_OTHER, por lo que ninguno lleva una cadena arbitraria de un cliente. Las versiones de protocolo están restringidas a las versiones compatibles de mcp-go.
En las métricas http.server.*, server.address y server.port informan -httpListenAddr
en lugar del encabezado Host de la solicitud, por lo que una sonda no autenticada que varíe ese encabezado no puede abrir una serie por
valor.
Registros
Con la telemetría habilitada, los registros se duplican al exportador de registros OTLP además de a stderr. Ambos destinos respetan
-logLevel, por lo que aumentarlo mantiene los registros filtrados fuera del cable y también fuera de stderr. Cada llamada de herramienta también registra
un registro INFO con el nombre de la herramienta, la duración y, en caso de fallo, error.type. Ese registro describe el manejador en lugar
de la respuesta JSON-RPC: un error devuelto se nombra por su tipo de Go, un fallo informado al llamador es tool_error,
y un pánico es _OTHER.
Cada registro emitido desde un sitio de llamada trazado se correlaciona con su span, por lo que los registros, rastros y métricas se alinean en el
backend. Los dos destinos llevan esa correlación de manera diferente: la línea de stderr obtiene campos trace_id y span_id, mientras que
el registro exportado obtiene los campos de id de rastro del propio modelo de datos de registro, que el SDK completa desde el contexto emisor.
Los ids se eliminan de los atributos del registro exportado para que no estén en el cable dos veces.
Limitaciones
Dos cosas están deliberadamente no instrumentadas:
- Sin spans HTTP de salida por solicitud. El trabajo de salida está cubierto por los spans de cliente manuales
helm.repo.index,helm.chart.download,helm.oci.pullyhelm.oci.tags. Las solicitudes OCI aún usan contextos creados internamente por el SDK de Helm; instrumentar esas solicitudes produciría spans desconectados del trace de la herramienta. - Las solicitudes de stream de larga duración están excluidas de los traces y métricas HTTP. La solicitud
GET /sseen modossey la solicitudGET /mcpen modohttppermanecen abiertas durante toda la sesión del cliente. Rastrearlas produciría spans de horas y pondría las duraciones de sesión en el histograma de latencia de solicitudes, por lo que ambas están filtradas. Las solicitudes JSON-RPC transportadas sobre esas sesiones se rastrean normalmente.
Apagado
Al recibir SIGTERM o SIGINT, el servidor deja de aceptar nuevo trabajo, drena las solicitudes en curso dentro de 10 segundos y luego
vacía la telemetría almacenada en búfer dentro de 5, por lo que un cliente que nunca se desconecta o un colector que nunca responde no puede mantener
el proceso vivo. Los presupuestos están separados a propósito: un drenaje que tarda mucho no puede gastar el tiempo que el vaciado necesita.
Una segunda señal termina inmediatamente.
Dale al proceso espacio para terminar: establece terminationGracePeriodSeconds (o docker stop -t) a al menos 20 segundos, o
los spans y registros de log almacenados en búfer en el momento de la señal se perderán.
Un transporte que falla al iniciar — un puerto ya en uso, una dirección de escucha no utilizable — se registra como fatal y sale
con estado 1.
Hoja de ruta
- Instrumentación OpenTelemetry (traces, métricas y logs sobre OTLP)
- Agregar más herramientas
- Listar todos los charts en un repositorio
- Listar todas las versiones de un chart
- Obtener la última versión del chart
- Obtener valores para el chart
- Obtener valores para la última versión del chart
- Extraer contenido completo del chart
- Extraer charts dependientes de Charts.yaml
- Extraer imágenes usadas en el chart
- Soporte para registros OCI
- Extraer charts de registros OCI
- Listar tags/versiones de registros OCI
- Soporte de autenticación mediante credenciales Docker
- Soporte para usar repositorios HTTP privados
- Agregar una forma de proporcionar credenciales para autenticación básica HTTP