MCP Prometheus
Accede a métricas y consultas de Prometheus a través de interfaces MCP estandarizadas.
Documentación
MCP Prometheus
Un servidor MCP (Model Context Protocol) para Prometheus y Mimir, escrito en Go. Desplegado en el clúster en Giant Swarm para dar a los asistentes de IA acceso autenticado y multi-tenant a la infraestructura de métricas.
Qué hace
MCP Prometheus expone 18 herramientas MCP de solo lectura que envuelven la API HTTP de Prometheus: consultas PromQL instantáneas y por rango, descubrimiento de métricas/etiquetas/series, información de targets y runtime, estadísticas de TSDB, reglas de alerta y exemplars.
Cuando se despliega con OAuth habilitado, actúa como un Servidor de Autorización OAuth 2.1 completo (respaldado por Dex/OIDC o Google), por lo que los clientes MCP se autentican con el servidor antes de cualquier llamada a herramienta. El servidor entonces resuelve los IDs de tenant de Mimir del usuario autenticado y los aplica en cada consulta.
Contenido
- Arquitectura
- Instalación
- Referencia de configuración
- Modos de transporte
- Autenticación OAuth 2.1
- Multi-tenancy
- Herramientas disponibles
- Despliegue en Kubernetes (Helm)
- Desarrollo
Arquitectura
MCP Client (Claude, muster, …)
│ OAuth 2.1 + MCP over HTTP
▼
┌──────────────────────────────────┐
│ mcp-prometheus │
│ │
│ ┌────────────┐ ┌─────────────┐ │
│ │ OAuth 2.1 │ │ MCP Tools │ │
│ │ server │ │ (PromQL, │ │
│ │ (mcp-oauth)│ │ labels, …)│ │
│ └─────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ ┌─────▼──────┐ ┌──────▼──────┐ │
│ │ Dex OIDC │ │ Tenancy │ │
│ │ provider │ │ resolver │ │
│ └────────────┘ └──────┬──────┘ │
└─────────────────────────┼────────┘
│
┌───────────────┴──────────────┐
│ │
┌──────▼───────┐ ┌───────▼──────┐
│ GrafanaOrg │ │ Prometheus │
│ CRDs (k8s) │ │ / Mimir │
└──────────────┘ └──────────────┘
El servidor escucha en dos puertos:
:8080— endpoints MCP + OAuth (servidos a los clientes):9091— observabilidad:/metrics,/healthz,/readyz(solo interno)
Instalación
Binarios precompilados
Descarga la última versión desde la página de releases.
Desde el código fuente
git clone https://github.com/giantswarm/mcp-prometheus.git
cd mcp-prometheus
go build -o mcp-prometheus ./...
Kubernetes (Helm)
Consulta Despliegue en Kubernetes (Helm).
Referencia de configuración
Toda la configuración se realiza mediante variables de entorno.
Conexión a Prometheus
| Variable | Predeterminado | Descripción |
|---|---|---|
PROMETHEUS_URL | — | URL base de Prometheus/Mimir |
PROMETHEUS_USERNAME | — | Usuario de autenticación básica |
PROMETHEUS_PASSWORD | — | Contraseña de autenticación básica |
PROMETHEUS_TOKEN | — | Token Bearer |
PROMETHEUS_ORGID | — | ID de org/tenant predeterminado de Mimir |
PROMETHEUS_TLS_SKIP_VERIFY | false | Omitir verificación TLS (solo desarrollo) |
PROMETHEUS_TLS_CA_CERT | — | Ruta al certificado CA en formato PEM |
ALERTMANAGER_URL | — | URL base de Alertmanager para get_alertmanager_alerts (Mimir: http://mimir-gateway.mimir/alertmanager); usa la autenticación, TLS y configuración de org ID anteriores |
OAuth 2.1
| Variable | Predeterminado | Descripción |
|---|---|---|
MCP_OAUTH_ISSUER | obligatorio | URL base pública de este servidor (p. ej. https://mcp.example.com) |
MCP_OAUTH_ENCRYPTION_KEY | — | Clave AES-256-GCM de 32 bytes en base64 para cifrado de tokens (openssl rand -base64 32) |
MCP_OAUTH_PROVIDER | dex | Proveedor de identidad: dex o google (consulta las tablas de proveedores a continuación) |
OAUTH_REDIRECT_URL | obligatorio | URL de callback registrada en el proveedor (p. ej. https://mcp.example.com/oauth/callback). El DEX_REDIRECT_URL heredado aún se respeta cuando esta no está definida |
MCP_OAUTH_ALLOW_PUBLIC_REGISTRATION | false | Permitir registro dinámico de clientes sin autenticación (solo desarrollo/Inspector MCP) |
MCP_OAUTH_ALLOW_PRIVATE_URLS | false | Permitir descubrimiento OIDC contra Dex en IPs privadas/internas (consulta abajo); solo dex |
OAUTH_TRUSTED_AUDIENCES | — | IDs de cliente separados por comas confiados para reenvío de tokens SSO |
OAUTH_STORAGE | memory | Almacenamiento de tokens: memory o valkey |
VALKEY_URL | — | Dirección de Valkey/Redis (obligatoria cuando OAUTH_STORAGE=valkey) |
VALKEY_PASSWORD | — | Contraseña de autenticación de Valkey |
VALKEY_TLS_ENABLED | false | Habilitar TLS para Valkey |
VALKEY_KEY_PREFIX | mcp: | Prefijo del espacio de nombres de claves |
Proveedor OIDC Dex (MCP_OAUTH_PROVIDER=dex)
| Variable | Predeterminado | Descripción |
|---|---|---|
DEX_ISSUER_URL | obligatorio | URL del emisor de Dex (p. ej. https://dex.mc.example.io) |
DEX_CLIENT_ID | obligatorio | ID de cliente OAuth registrado en Dex |
DEX_CLIENT_SECRET | obligatorio | Secreto de cliente OAuth |
DEX_REDIRECT_URL | — | Alias heredado de OAUTH_REDIRECT_URL; se usa cuando este último no está definido |
DEX_CA_FILE | — | Archivo CA PEM que verifica TLS para endpoints Dex y JWKS (instalaciones con CA privada). Se añade sobre el almacén de confianza del sistema |
Proveedor Google (MCP_OAUTH_PROVIDER=google)
| Variable | Predeterminado | Descripción |
|---|---|---|
GOOGLE_CLIENT_ID | obligatorio | ID de cliente OAuth del cliente OAuth de Google Cloud (….apps.googleusercontent.com) |
GOOGLE_CLIENT_SECRET | obligatorio | Secreto de cliente OAuth de ese cliente |
Los endpoints de descubrimiento, token y JWKS de Google son públicos, por lo que DEX_CA_FILE y
MCP_OAUTH_ALLOW_PRIVATE_URLS no aplican (se ignoran con una advertencia).
Los tokens de ID de Google no llevan claim groups: combina este proveedor con
el modo de tenancy none o con una lista estática de tenants para todos los usuarios.
Tenancy
| Variable | Predeterminado | Descripción |
|---|---|---|
TENANCY_STATIC_GROUP_MAP | — | Mapa JSON de grupo Dex → lista de IDs de tenant de Mimir (modo estático) |
El modo de tenancy es un flag: --tenancy-mode grafana-organization|static|none (consulta Multi-tenancy).
Observabilidad
| Variable | Predeterminado | Descripción |
|---|---|---|
OTEL_EXPORTER_OTLP_ENDPOINT | — | Endpoint OTLP HTTP para tracing (sin operación si no está definido) |
OTEL_SERVICE_NAME | mcp-prometheus | Nombre del servicio en los traces |
Modos de transporte
Inicia el servidor con serve --transport <mode>:
| Modo | Flag | Caso de uso |
|---|---|---|
stdio | --transport stdio | Clientes de escritorio locales (Claude Desktop, MCP Inspector) |
sse | --transport sse | Clientes SSE heredados |
streamable-http | --transport streamable-http | Producción en clúster (predeterminado) |
OAuth requiere sse o streamable-http.
# Local stdio (no OAuth)
./mcp-prometheus serve
# In-cluster HTTP with OAuth
./mcp-prometheus serve --transport streamable-http --http-addr :8080 --enable-oauth
Autenticación OAuth 2.1
MCP Prometheus implementa OAuth 2.1 (RFC 9700) usando mcp-oauth con el
proveedor de identidad de la plataforma como upstream: Dex (predeterminado) o Google, seleccionado con MCP_OAUTH_PROVIDER.
El flujo, los endpoints y el manejo de tokens son idénticos para ambos; solo difieren el inicio de sesión upstream y las
variables de entorno específicas del proveedor.
Endpoints
| Ruta | Método | Propósito |
|---|---|---|
/.well-known/oauth-authorization-server | GET | Metadatos del servidor OAuth (RFC 8414) |
/.well-known/protected-resources | GET | Metadatos del recurso protegido |
/oauth/authorize | GET | Endpoint de autorización (redirige al proveedor de identidad) |
/oauth/callback | GET | Callback del proveedor de identidad (OAUTH_REDIRECT_URL) |
/oauth/token | POST | Intercambio de tokens |
/oauth/register | POST | Registro dinámico de clientes (RFC 7591) |
/oauth/revoke | POST | Revocación de tokens |
Flujo OAuth completo
MCP Client mcp-prometheus Dex OIDC
│ │ │
│ 1. GET /.well-known/… │ │
│──────────────────────────>│ │
│ server metadata │ │
│<──────────────────────────│ │
│ │ │
│ 2. POST /oauth/register │ │
│──────────────────────────>│ │
│ client_id + secret │ │
│<──────────────────────────│ │
│ │ │
│ 3. GET /oauth/authorize │ │
│──────────────────────────>│ │
│ │ 4. redirect to Dex │
│ │───────────────────────>│
│<──────────────────────────────────────────────────│
│ browser: Dex login UI │ │
│ (user authenticates) │ │
│ │ │
│ │ 5. callback + code │
│ │<───────────────────────│
│ │ │
│ 6. POST /oauth/token │ │
│──────────────────────────>│ │
│ access_token + refresh │ │
│<──────────────────────────│ │
│ │ │
│ 7. MCP tool call │ │
│ Authorization: Bearer … │ │
│──────────────────────────>│ │
│ │ 8. validate token │
│ │ resolve tenants │
│ │ forward to Mimir │
El token de acceso es un JWT de corta duración firmado por mcp-prometheus y validado en cada solicitud. La rotación del refresh token está habilitada: cada renovación emite un nuevo refresh token.
Almacenamiento de tokens
memory(predeterminado): en proceso, se pierde al reiniciar. Adecuado para despliegues de una sola réplica y desarrollo.valkey: backend Redis/Valkey de nivel producción. Obligatorio para despliegues multi-réplica.
Permitir URLs privadas
Cuando DEX_ISSUER_URL usa un nombre DNS interno que resuelve a una IP privada (rango RFC-1918),
la protección SSRF integrada en el cliente de descubrimiento OIDC rechazaría la conexión.
Establece MCP_OAUTH_ALLOW_PRIVATE_URLS=true para permitir conexiones a IPs privadas hacia ese Dex para el descubrimiento OIDC
y para la obtención de JWKS que valida los tokens de ID reenviados (OAUTH_TRUSTED_AUDIENCES,
p. ej. desde muster). La URL de JWKS proviene del emisor Dex configurado, nunca del token.
La verificación TLS sigue aplicándose.
MCP_OAUTH_ALLOW_PRIVATE_URLS=true
DEX_ISSUER_URL=https://dex.mc.my-cluster.example.io # resolves to 10.x.x.x
En Helm: app.oauth.allowPrivateURLs: true
CA privada (DEX_CA_FILE)
Cuando Dex se sirve con un certificado de una CA privada/interna (p. ej. clústeres de gestión
privados), la verificación TLS falla con x509: certificate signed by unknown authority.
Apunta DEX_CA_FILE a un archivo CA PEM para añadir esa CA sobre el almacén de confianza del sistema.
El pool verifica la conexión con el proveedor Dex (descubrimiento OIDC, flujo de código, userinfo)
y el endpoint JWKS del token de ID reenviado.
DEX_CA_FILE=/etc/ssl/certs/dex-ca/ca.crt
En Helm, referencia un Secret que contenga el certificado CA:
app:
oauth:
dexCASecret:
name: mcp-prometheus-dex-ca
key: ca.crt
Reenvío de tokens SSO (trustedAudiences)
Cuando los usuarios se conectan a través de un agregador MCP upstream (p. ej. muster) que ya los ha autenticado, el agregador puede reenviar el token de ID del usuario desde el IdP de la plataforma directamente en lugar de iniciar un nuevo flujo OAuth.
Configura OAUTH_TRUSTED_AUDIENCES con una lista separada por comas de los IDs de cliente OAuth del agregador:
OAUTH_TRUSTED_AUDIENCES=muster-client,my-aggregator
mcp-prometheus:
- Detectará que la audiencia del token entrante coincide con un ID de cliente confiado
- Verificará la firma del token contra el endpoint JWKS del proveedor (Dex o Google)
- Aceptará el token y procederá con la resolución de tenant
Los tokens deben originarse del emisor del proveedor configurado. Con el proveedor Google, lista el ID de cliente OAuth de Google de la plataforma (aquel con el que muster inicia sesión para los usuarios) aquí.
Multi-tenancy
Cuando OAuth está habilitado, cada llamada a herramienta se limita a los IDs de tenant de Mimir permitidos del usuario autenticado.
El usuario puede pasar un parámetro explícito org_id; el servidor lo valida contra sus tenants permitidos.
Si no se proporciona org_id, todos los tenants permitidos se inyectan como un selector multi-tenant de Mimir separado por barras verticales.
Hay tres modos de resolución disponibles, seleccionados con --tenancy-mode (o app.tenancy.mode en Helm):
grafana-organization (predeterminado), static y none.
Modo GrafanaOrganization (predeterminado)
--tenancy-mode grafana-organization
Lee los recursos personalizados GrafanaOrganization de la API de Kubernetes.
Cada CR declara qué grupos de Dex tienen acceso (spec.rbac) y qué IDs de tenant de Mimir le corresponden (spec.tenants).
apiVersion: observability.giantswarm.io/v1alpha1
kind: GrafanaOrganization
metadata:
name: team-platform
spec:
rbac:
- groupName: github-org:team-platform # Dex group from LDAP/GitHub
tenants:
- prod-eu-west
- prod-us-east
Cuando un usuario se autentica:
- El servidor lee el claim
groupsde su token de Dex - Busca todos los CR
GrafanaOrganizationdonde cualquier grupo enspec.rbaccoincida - Recopila todos los IDs de tenant de
spec.tenantsen los CR coincidentes - Los resultados se cachean por conjunto de grupos durante 60 segundos
El chart de Helm crea un ClusterRole + ClusterRoleBinding que otorga get, list, watch sobre grafanaorganizations.observability.giantswarm.io cuando este modo está activo.
Modo estático
--tenancy-mode static
No requiere acceso a la API de Kubernetes. Los tenants se configuran estáticamente.
Todos los usuarios: mismos tenants para todos
# All authenticated users get these tenant IDs
--static-tenants=prod-eu,prod-us
Helm:
app:
tenancy:
mode: static
static:
tenants: "prod-eu,prod-us"
Mapeo por grupos: asignación de tenants por grupo
Cuando TENANCY_STATIC_GROUP_MAP está definido (o app.tenancy.static.groups en Helm), los IDs de tenant se resuelven por grupo:
TENANCY_STATIC_GROUP_MAP='{"team-ops":["prod-eu","prod-us"],"team-dev":["staging"]}'
Helm:
app:
tenancy:
mode: static
static:
groups:
team-ops:
- prod-eu
- prod-us
team-dev:
- staging
Los tenants permitidos del usuario son la unión de todos los tenants de sus grupos de Dex.
Modo None (Prometheus de un solo tenant)
--tenancy-mode none
Para un Prometheus simple de un solo tenant (sin Mimir, sin X-Scope-OrgID). OAuth aún
autentica a cada llamador: las solicitudes no autenticadas se rechazan, los tokens reenviados se
validan y la identidad está disponible para auditoría — pero no se deriva ningún tenant de la
identidad ni se inyecta ninguna cabecera de tenant. Un parámetro de herramienta explícito org_id o
PROMETHEUS_ORGID se pasa tal cual. El chart no crea ningún ClusterRole en este modo.
Este es el modo a usar con el proveedor Google (los tokens de Google no tienen claim groups)
y siempre que mcp-prometheus esté detrás de muster frente a un único Prometheus.
Helm:
app:
tenancy:
mode: none
Herramientas disponibles
Todas las herramientas aceptan parámetros opcionales prometheus_url y org_id para anulaciones por llamada.
Ejecución de consultas
| Herramienta | Descripción |
|---|---|
mcp_prometheus_execute_query | Consulta instantánea PromQL |
mcp_prometheus_execute_range_query | Consulta por rango PromQL con start, end, step |
Las herramientas de consulta aceptan: timeout, limit, stats, lookback_delta, unlimited.
Métricas y descubrimiento
| Herramienta | Descripción |
|---|---|
mcp_prometheus_get_metric_metadata | Metadatos de una métrica específica |
mcp_prometheus_list_label_names | Todos los nombres de etiquetas |
mcp_prometheus_list_label_values | Valores para una etiqueta específica |
mcp_prometheus_find_series | Buscar series por coincidencias de etiquetas |
Objetivos e información del sistema
| Herramienta | Descripción |
|---|---|
mcp_prometheus_get_targets | Lista de objetivos de scrape y estado de salud |
mcp_prometheus_get_build_info | Información de compilación/versión |
mcp_prometheus_get_runtime_info | Información de tiempo de ejecución |
mcp_prometheus_get_flags | Banderas de tiempo de ejecución |
mcp_prometheus_get_config | Configuración de Prometheus |
mcp_prometheus_get_tsdb_stats | Estadísticas de cardinalidad de TSDB |
mcp_prometheus_check_ready | Verificación de disponibilidad (/-/ready), funciona con Mimir |
Alertas y reglas
| Herramienta | Descripción |
|---|---|
mcp_prometheus_get_alerts | Alertas activas |
mcp_prometheus_get_alertmanagers | Descubrimiento de AlertManager |
mcp_prometheus_get_rules | Reglas de grabación y alertas |
mcp_prometheus_get_alertmanager_alerts | Alertas que notifican, desde Alertmanager: activas, no silenciadas, no inhibidas |
get_rules acepta los filtros de GET /api/v1/rules, aplicados del lado del servidor por Prometheus o el
ruler de Mimir: type (alert o record), rule_name, rule_group, file (el espacio de nombres
de reglas de Mimir) y exclude_alerts. Los coincidentes de etiquetas (match[]) no están expuestos porque el
ruler de Mimir los ignora. En Mimir pase org_id — la API del ruler rechaza solicitudes sin un tenant.
get_alertmanager_alerts lee GET /api/v2/alerts del Alertmanager en alertmanager_url o
ALERTMANAGER_URL y devuelve las alertas que notifican, primero las más antiguas, cada una con su huella digital,
nombre de alerta, severidad, hora de inicio, etiquetas, anotaciones y receptores. filter toma coincidentes de etiquetas
(team="bumblebee", severity=~"page|notify") y receiver una expresión regular de receptor; ambos son aplicados
por el Alertmanager. El tenant se resuelve como para cada herramienta de Prometheus, por lo que en Mimir el
Alertmanager multi-tenant se lee con el X-Scope-OrgID del llamante.
Avanzado
| Herramienta | Descripción |
|---|---|
mcp_prometheus_query_exemplars | Consultas de exemplars para correlación de trazas |
mcp_prometheus_get_targets_metadata | Metadatos de métricas por objetivo |
Los resultados de consultas grandes se truncan automáticamente con orientación para que la IA refine su consulta.
Despliegue en Kubernetes (Helm)
Mínimo (sin OAuth)
app:
env:
- name: PROMETHEUS_URL
value: "http://mimir-gateway.monitoring:8080/prometheus"
- name: PROMETHEUS_ORGID
value: "my-tenant"
Producción con OAuth + tenencia de GrafanaOrganization
app:
server:
transport: streamable-http
oauth:
enabled: true
dexClientSecret: "..." # stored in K8s Secret
encryptionKey: "..." # openssl rand -hex 32
storage:
type: valkey
valkey:
url: "valkey:6379"
trustedAudiences:
- muster-client
tenancy:
mode: grafana-organization
env:
- name: MCP_OAUTH_ISSUER
value: "https://mcp-prometheus.mc.example.io"
- name: DEX_ISSUER_URL
value: "https://dex.mc.example.io"
- name: DEX_CLIENT_ID
value: "mcp-prometheus"
- name: DEX_REDIRECT_URL
value: "https://mcp-prometheus.mc.example.io/oauth/callback"
- name: PROMETHEUS_URL
value: "http://mimir-gateway.monitoring:8080/prometheus"
Proveedor de Google + Prometheus de un solo tenant detrás de muster
El IdP de la plataforma es Google, muster reenvía el token de ID de Google del usuario
(auth.forwardToken: true), y no hay tenants de Mimir que resolver.
app:
oauth:
enabled: true
provider: google
redirectURL: "https://mcp-prometheus.example.io/oauth/callback"
google:
clientID: "1234567890-abc.apps.googleusercontent.com" # this server's OAuth client
googleClientSecret: "..." # or existingSecret with key GOOGLE_CLIENT_SECRET
encryptionKey: "..." # openssl rand -base64 32
trustedAudiences:
- "1234567890-platform.apps.googleusercontent.com" # the platform client muster logs in with
tenancy:
mode: none
env:
- name: MCP_OAUTH_ISSUER
value: "https://mcp-prometheus.example.io"
- name: PROMETHEUS_URL
value: "http://prometheus-operated.monitoring:9090"
Producción con OAuth + mapeo de grupos estático
app:
oauth:
enabled: true
dexClientSecret: "..."
encryptionKey: "..."
tenancy:
mode: static
static:
groups:
team-ops:
- prod-eu
- prod-us
team-dev:
- staging
Dex privado (DNS interno)
Cuando DEX_ISSUER_URL se resuelve a una IP privada:
app:
oauth:
enabled: true
allowPrivateURLs: true # private-IP Dex: OIDC discovery and forwarded-token JWKS
dexClientSecret: "..."
encryptionKey: "..."
Almacenamiento de tokens Valkey (multi-réplica)
app:
oauth:
storage:
type: valkey
valkey:
url: "valkey.default:6379"
password: ""
tlsEnabled: false
keyPrefix: "mcp-prometheus:"
Desarrollo
Estructura del proyecto
mcp-prometheus/
├── cmd/ # CLI (serve, version)
├── internal/
│ ├── oauth/ # OAuth 2.1 setup (Config, NewHandler)
│ ├── server/ # ServerContext, PrometheusConfig
│ ├── tenancy/ # TenancyResolver, GrafanaOrg + static modes
│ ├── tools/prometheus/ # 18 MCP tool registrations
│ └── observability/ # /metrics, /healthz, /readyz, OTel
├── helm/mcp-prometheus/ # Helm chart
├── go.mod
└── README.md
Compilación y pruebas
go build -o mcp-prometheus ./...
go test ./...
Convenciones de código
- Cada paquete tiene un
doc.go - Cobertura de pruebas unitarias del 80%+ en código nuevo
- Ejecute
goimports -w . && go fmt ./...antes de confirmar - Archivos mantenidos por debajo de 500 líneas; GoDoc en todos los miembros exportados