BoundBench

Grafana MCP Server

MCP server for Grafana dashboards, datasources (Prometheus/Loki), alerting, OnCall, incidents

github.com/grafana/mcp-grafana · 2026-10-03 · 9dbfe13

Defense-in-depth score

3.3 / 10

Minimal

Grafana's MCP server is carefully engineered around its credentials: the token never reaches the model, redirects cannot carry it elsewhere, and every tool is annotated so hosts can tell reads from writes. But it ships with write tools on, including a general-purpose Grafana API tool that takes any method and path and can run raw SQL through datasources, plus a plugin installer the model can drive. Nothing in the server marks untrusted log or dashboard content or records what tools did, so a prompt-injected session can read sensitive telemetry, send it out through a new contact point, and delete resources. Run it with --disable-write and a narrowly scoped, read-only service account unless writes are really needed.

Key gaps (3)

  1. The default grafana_api_request tool can call Grafana's service-account and access-control endpoints with the server's own credential, letting the model mint tokens or change roles when the token is Admin (C1-SELFESC). C1 · Identity & least privilege
  2. Default configuration lets a hijacked session both exfiltrate data (new webhook/email contact points) and take irreversible actions (DELETE on any API path, raw SQL) with no server-side gate (C5-WORSTCASE). C5 · Untrusted input blast radius
  3. install_plugin is on by default and installs a model-chosen plugin and version into Grafana, where it runs with Grafana's authority; the only consent is text asking the model to check with the user. C7 · Third-party extensions

Criteria

C1 Identity & least privilege

Minimal 0.25 / 1.00

The server uses one Grafana credential for everything: a service account token (or a username and password) taken from its environment, attached to every request by every tool. It does not narrow that credential per tool or per request, and the README's quick-path advice is to give the service account the broad Editor role. Write tools, including a general-purpose Grafana API tool that accepts any method and path, are on by default, so the model can call service-account and access-control endpoints and, with an Admin token, mint new tokens or change its own roles; only Grafana's own permission checks stop that.

C2 Approval gates

Minimal 0.33 / 1.00

The host, not the server, decides what to approve, so this rates the signals the server gives it. Every tool declares read-only, destructive and open-world hints, and a test fails the build if any tool is missing them, so hosts can tell reads from writes. But the default toolset includes grafana_api_request, one tool that does both reads and writes (correctly flagged destructive), there is no dry-run or preview for destructive operations, and the read-only mode is opt-in. Approved or bypassed calls can delete alert rules, snapshots and annotations, or run destructive SQL through datasources, with no undo in the server.

C3 Tool & action scoping

Moderate 0.53 / 1.00

Most tools are narrow, typed Grafana operations, and a shared wrapper rejects unknown arguments for every tool. The generic grafana_api_request tool, enabled by default, undoes much of that: it accepts any HTTP method, any API path on the Grafana host, arbitrary request headers and a free-form body, which includes raw datasource queries. The host is fixed and cross-origin redirects are refused, so it cannot be pointed at other servers directly. Write tools are on by default; a read-only mode and per-category switches exist but must be turned on.

C4 Code-execution isolation

Minimal 0.05 / 1.00

The server never runs commands or code on its own machine: there is no subprocess or eval path, and the jq filter language it accepts runs in a pure-Go interpreter that is denied access to environment variables. It does, however, let the model have code run elsewhere. The default grafana_api_request tool can POST to /api/ds/query, which runs model-written raw SQL against any SQL datasource with that datasource's credentials, and the project's own README notes such queries will run DROP TABLE if the credentials allow. Nothing isolates that path.

C5 Untrusted input blast radius

Minimal 0.00 / 1.00

The server returns logs, traces, dashboards, annotations, incident text and other content that anyone who can write to those systems controls, with no marking of what is untrusted. Several tool descriptions and outputs also carry instructions to the model (for example 'you MUST ask the user' and 'Ask the user whether to install'), relying on the model for consent. In the default configuration the same session can read sensitive telemetry, create contact points that send data to external webhooks or email, install plugins, and delete resources, so a hijacked model can both leak and destroy without a human in the loop as far as the server is concerned.

C6 Memory, context & configuration integrity

N/A · full credit 1.00 / 1.00

The server keeps no memory, retrieval store, or conversation history between sessions, and it does not load instruction or configuration files from a working directory. Configuration comes only from command-line flags and environment variables set by the operator, plus optional token, TLS and CA file paths the operator names. Caches (clients, frontend settings, docs index) live only in process memory.

C7 Third-party extensions

Minimal 0.00 / 1.00

The server itself loads no plugins or remote code, but its default toolset includes install_plugin, which lets the model install any Grafana plugin at any version into the connected Grafana server through Grafana's install API. The only consent step is a message telling the model to ask the user when no version is given; if the model supplies a version, the install happens immediately. Installed plugins run inside Grafana (backend code on the server, frontend code in every user's browser), with far more access than the MCP server itself.

C8 Secrets & sensitive-data protection

Minimal 0.40 / 1.00

The Grafana token never appears in tool output: tools have no way to read it, it is attached only by the transport layer, cross-origin redirects are refused so it cannot follow a redirect elsewhere, and URLs with embedded credentials are rejected. Debug logging of HTTP traffic masks Authorization and similar headers, and startup logs record only whether a key is set. However, tool results such as log lines are passed to the model without any secret scanning, the token is a long-lived credential from an environment variable or file, and anonymous usage statistics are sent to Grafana Labs by default (content-free: counts, tool names, auth method).

C9 Audit & traceability

Minimal 0.35 / 1.00

In the default configuration the server keeps no record of the tool calls it makes: the observability middleware is a no-op unless metrics, tracing or slow-request logging is enabled, and tool handlers log nothing at info level. If the operator configures an OpenTelemetry endpoint, every tool call becomes a span with its name, session ID, status and error, exported off the host; arguments are added only with an extra flag, and there is no record of which human or principal asked for the call.

C10 Limits & kill switch

Minimal 0.40 / 1.00

The server bounds some of its own work: most HTTP responses are capped at 10 MB, Loki log queries at 100 lines, and the typed Grafana client has a 10-second default timeout. Other paths are open-ended: the generic API tool's HTTP client has no timeout, jq filters run until the caller cancels, the model can set any rendering timeout, and the Loki cost guardrail is off by default. There are no rate or concurrency limits on tool calls, including write tools.