Skip to main content
Glama
mgcrea

mcp-prometheus

by mgcrea
README.md
# @mgcrea/mcp-prometheus

A [Model Context Protocol](https://modelcontextprotocol.io) server for the
[Prometheus HTTP API](https://prometheus.io/docs/prometheus/latest/querying/api/): PromQL
queries, metric and label discovery, alerts, rules, scrape health and cardinality, shaped to fit
a context window.

The server is **read-only by default**. The admin tools are not merely refused when writes are
off — they are never registered, so an agent cannot call them at all.

## Why another one

Prometheus answers are built for dashboards, not for models. Measured on a
kube-prometheus-stack install (~800k head series, 268 targets):

| Endpoint                           | Raw                                      | What this server returns                                                    |
| ---------------------------------- | ---------------------------------------- | --------------------------------------------------------------------------- |
| `/api/v1/targets`                  | 1.5 MB                                   | totals, unhealthy pools, and the unhealthy targets with `lastError` (~2 KB) |
| `/api/v1/query` (`up`, 124 series) | 9 labels repeated per series             | shared labels once in `common_labels`, numeric values                       |
| `/api/v1/query_range`              | `[ts, "0.005732144858390525"]` per point | one array per series on the step grid, rounded, plus min/max/avg/last       |
| `/api/v1/rules`                    | 200 KB                                   | flat list, filterable by health/state/type/name                             |
| `/api/v1/metadata`                 | 420 KB                                   | searched by name _and_ help text, cached                                    |

It also does the things a model gets wrong on its own: relative times (`now-1h`), a round
step picked for ~60 points, label lookups limited to series that exist _now_ rather than over
the whole retention, and PromQL errors returned verbatim with what to do about them.

## Tools

| Tool                           | What it does                                                                                               | Writes  |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------- | ------- |
| `prometheus_auth_status`       | Which Prometheus answered (version, hostname, external labels, retention, admin API), or what to configure | no      |
| `prometheus_query`             | Instant PromQL query                                                                                       | no      |
| `prometheus_query_range`       | Range query on a step grid, with per-series stats; `view=stats`, `sort=max` to survey                      | no      |
| `prometheus_list_metrics`      | Find metrics by name or help text, with type and help                                                      | no      |
| `prometheus_describe_metric`   | Type, help, series count, and every label with its cardinality and examples                                | no      |
| `prometheus_list_labels`       | Label names, optionally on a selector                                                                      | no      |
| `prometheus_list_label_values` | Values of one label, optionally on a selector                                                              | no      |
| `prometheus_list_alerts`       | Firing and pending alerts, most severe first, with counts                                                  | no      |
| `prometheus_list_rules`        | Alerting and recording rules; `health=err` finds broken ones                                               | no      |
| `prometheus_list_targets`      | Scrape health: totals, unhealthy pools and targets with their errors                                       | no      |
| `prometheus_get_tsdb_status`   | Head-block cardinality: top metrics, labels, label pairs                                                   | no      |
| `prometheus_request`           | GET any `/api/v1/*` endpoint, cut at `max_chars`                                                           | no      |
| `prometheus_delete_series`     | Delete series (counts first, refuses past `max_series`, needs `confirm`)                                   | **yes** |
| `prometheus_clean_tombstones`  | Purge deleted data from disk (needs `confirm`)                                                             | **yes** |
| `prometheus_reload_config`     | `POST /-/reload`                                                                                           | **yes** |

There is deliberately no `/-/quit` and no TSDB snapshot tool (a snapshot copies the whole TSDB
onto a volume sized for one).

## Configure

| Variable                                      | Required | Description                                                                            |
| --------------------------------------------- | -------- | -------------------------------------------------------------------------------------- |
| `PROMETHEUS_URL`                              | yes      | Base URL, including any path prefix (`https://host/prometheus`). No credentials in it. |
| `PROMETHEUS_USERNAME` / `PROMETHEUS_PASSWORD` | no       | Basic auth for a proxy in front of Prometheus.                                         |
| `PROMETHEUS_TOKEN`                            | no       | Bearer token instead of basic auth.                                                    |
| `PROMETHEUS_HEADERS`                          | no       | Extra headers as JSON, e.g. `{"X-Scope-OrgID":"tenant-1"}` for Mimir.                  |
| `PROMETHEUS_ALLOW_WRITES`                     | no       | `1` to register the admin tools.                                                       |
| `PROMETHEUS_TIMEOUT`                          | no       | Query timeout in seconds (default 30).                                                 |
| `PROMETHEUS_MAX_RETRIES`                      | no       | Retries for 429 and proxy 5xx (default 2). Query timeouts are never retried.           |
| `PROMETHEUS_UI_LINKS`                         | no       | `0` to drop the Prometheus UI link from query results.                                 |

A self-signed certificate needs `NODE_EXTRA_CA_CERTS=/path/to/ca.pem`.

A configuration mistake — a malformed URL, a token _and_ basic auth, invalid
`PROMETHEUS_HEADERS` — never stops the server from starting. It starts with only
`prometheus_auth_status`, which says what to fix.

### Which Prometheus is this?

kube-prometheus-stack names everything identically on every cluster, so a `.mcp.json` copied
between projects answers every query with plausible numbers from the wrong one. The server
prints the instance it reached on startup (stderr), and `prometheus_auth_status` returns the
URL, version, hostname and external labels. If you run several clusters, set a distinguishing
external label (`prometheus.prometheusSpec.externalLabels.cluster` in kube-prometheus-stack).

## Quick start

```bash
pnpm install
pnpm build
```

Then copy `.mcp.json.example` to `.mcp.json` and fill it in.

### Inspect the tools

```bash
printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"cli","version":"0"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| PROMETHEUS_URL=http://localhost:9090 node dist/cli.js 2>/dev/null | jq -r '.result.tools[]?.name'
```

## Develop

```bash
pnpm dev            # tsdown --watch
pnpm test           # vitest
pnpm typecheck
pnpm lint
pnpm format
```

### Publish

```bash
pnpm dlx release-it       # bump, commit, tag
git push --follow-tags    # CI publishes to npm + GHCR from the tag
```

## License

MIT

TDQS

A4.2/5.0

Scored across 12 tools

Disambiguation5/5

Each tool targets a distinct resource or action: instant vs. range queries are explicitly contrasted, and list_labels / list_label_values / describe_metric are differentiated with cross-references (e.g. 'describe_metric is more useful' for one metric's labels). The only potential overlap, prometheus_request, is explicitly framed as a read-only escape hatch with guidance to prefer the named tools.

Naming Consistency4/5

All names share the prometheus_ snake_case prefix and are mostly verb_noun (query, query_range, list_metrics, describe_metric, get_tsdb_status). Minor deviations are auth_status (noun phrase) and request (bare verb), but the set remains predictable and readable.

Tool Count5/5

Twelve tools is well within a healthy range and each earns its place: query, discovery, alerts/rules, target health, TSDB cardinality, and a raw escape hatch. No tool appears redundant with another.

Completeness4/5

The read-only Prometheus surface is broadly covered: queries, metric/label discovery, alerts, rules, targets, TSDB status, and auth/version checks. A dedicated series-lookup tool (/api/v1/series) and explicit config/flags endpoints are absent, but the request escape hatch lets agents work around these gaps.

Maintenance

ActivityMaintained
ResponsivenessNo issues