npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mgcrea/mcp-grafana

v0.2.0

Published

Model Context Protocol server for the Grafana HTTP API

Readme

@mgcrea/mcp-grafana

A Model Context Protocol server for the Grafana HTTP API: dashboards and the data their panels show, PromQL and LogQL through Grafana's datasources, alerts, alert rules, silences and annotations, shaped to fit a context window.

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

What it does that the API does not

  • Runs a panel the way the dashboard does. grafana_run_panel_query fills in template variables before sending the query, which /api/ds/query will not do for you. It takes them from vars, else the dashboard's saved value, else what the browser would pick: All, or the first value of a label_values(...) query, or "" ("None") when that query has no values. That last case is common, not an edge: provisioned dashboards (every kube-prometheus-stack mixin) are saved with no current values, and on a single-cluster install the mixins' cluster variable has no values at all. Mixed panels, datasource variables, hidden queries, expressions and library panels are handled. The result says which values were used and what query was sent.
  • Shapes data frames. Grafana answers every datasource in columnar frames: one frame per Prometheus series, each repeating its schema, and Loki log rows that each repeat the full stream label set alongside three UI-only columns. Here, time series come back on one step grid with min/max/avg/last, labels shared by every series or line come back once as common_labels, log lines are cut at max_line_chars, and anything else is a table.
  • Summarizes dashboards. grafana_get_dashboard flattens rows (collapsed, expanded and pre-schema-16), and lists each panel's id, type, unit and queries without the layout and styling: about half the JSON on the kubernetes mixins. view=full is there for editing.
  • Reads alerting from everywhere it lives. Grafana-managed rules and Grafana's own Alertmanager, plus every Prometheus/Loki datasource's ruler and every Alertmanager datasource. A kube-prometheus-stack install usually has everything in the datasources and nothing in Grafana. A source that does not answer (a Loki with no ruler) shows up in unavailable and does not fail the call.
  • Says which org it is reading. A service account token is bound to one org and takes no org in the request, so a token copied from the wrong org answers everything with plausible data. The org is shown in the startup banner and in grafana_auth_status, and stamped on every data response. With GRAFANA_ORG_ID set, every data tool refuses on a mismatch.

Tools

| Tool | What it does | Writes | | --------------------------- | ------------------------------------------------------------------------------------ | ------ | | grafana_auth_status | URL, version, org, login, effective role and permissions; setup steps when unset | no | | grafana_search | Dashboards and folders by title, tag, folder, starred | no | | grafana_get_dashboard | Summary (variables, panels, queries), one panel's JSON, or the full JSON | no | | grafana_run_panel_query | A panel's queries with variables filled in, and the data they return | no | | grafana_query_prometheus | PromQL, instant or range, through a Prometheus datasource | no | | grafana_query_loki | LogQL log lines or metric queries through a Loki datasource | no | | grafana_query | Raw queries against any datasource, including server-side expressions | no | | grafana_list_labels | Label names or values for Prometheus/Loki, restricted by selector, last hour | no | | grafana_list_datasources | uid, name, type, default — never credentials | no | | grafana_list_alerts | Active alerts from every Alertmanager, most severe first | no | | grafana_list_alert_rules | Rules and their state from Grafana and every datasource ruler | no | | grafana_list_silences | Silences with readable matchers | no | | grafana_list_annotations | Deploys, incidents and alert state changes in a window | no | | grafana_request | GET any /api/ or /apis/ endpoint; any method (with confirm) when writes are on | gated | | grafana_save_dashboard | Create or update a dashboard; refuses to overwrite a concurrent edit | yes | | grafana_delete_dashboard | Delete a dashboard (confirm: true) | yes | | grafana_create_annotation | Mark a moment or region | yes | | grafana_create_silence | Silence alerts matching matchers, for a duration | yes | | grafana_expire_silence | End a silence (confirm: true) | yes |

Configure

| Variable | Required | Description | | ------------------------------- | -------- | ------------------------------------------------------------------------------------------- | | GRAFANA_URL | yes | Grafana root URL, including any sub-path, e.g. https://grafana.example.com. | | GRAFANA_SERVICE_ACCOUNT_TOKEN | one of | A service account token (glsa_…). GRAFANA_API_KEY is accepted as an alias. | | GRAFANA_USERNAME / PASSWORD | one of | Basic auth instead of a token. | | GRAFANA_ORG_ID | no | The org this server must read. Sent as X-Grafana-Org-Id; data tools refuse on a mismatch. | | GRAFANA_ALLOW_WRITES | no | 1 to register the write tools. | | GRAFANA_HEADERS | no | Extra headers as JSON, e.g. a Cloudflare Access service token. | | GRAFANA_TIMEOUT | no | Seconds per request. Defaults to 30. | | GRAFANA_MAX_RETRIES | no | Retries on 429/502/503/504 for reads. Defaults to 2. Writes are never retried. | | GRAFANA_DEBUG | no | 1 to log each request to stderr. |

The names match Grafana's own mcp-grafana, so swapping is a change of command in an .mcp.json.

A token needs Viewer for every read tool (with Viewer, the datasource list comes from the frontend settings, since /api/datasources needs more), Editor for dashboards and annotations, and whatever your alerting setup requires for silences. grafana_auth_status reports the role and the permissions the tools depend on.

Security

  • Read-only by default. GRAFANA_ALLOW_WRITES=1 adds the write tools; the destructive ones then additionally require an explicit confirm: true on every call, and grafana_request requires it for any method but GET.
  • Saves never overwrite. grafana_save_dashboard sends overwrite: false, so a dashboard changed since it was read is refused, not clobbered; every save stays in the version history.
  • No runtime dependencies beyond the MCP SDK and Zod — native fetch throughout.
  • Credentials stay in your environment, are never echoed back (grafana_auth_status lists header names, not values), and are refused when embedded in GRAFANA_URL.

Quick start

pnpm install
pnpm build
{
  "mcpServers": {
    "grafana": {
      "command": "npx",
      "args": ["-y", "@mgcrea/mcp-grafana"],
      "env": {
        "GRAFANA_URL": "https://grafana.example.com",
        "GRAFANA_SERVICE_ACCOUNT_TOKEN": "glsa_..."
      }
    }
  }
}

Inspect the tools

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"}' \
| node dist/cli.js 2>/dev/null | jq -r '.result.tools[]?.name'

Develop

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

Publish

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

License

MIT