SafetyCard Request a review

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

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.

Safest setup

Grafana MCP Server keeps its token away from the model and on the Grafana host, and labels every tool as read-only or destructive. As shipped it turns on write tools, a general API tool and plugin installs, and records nothing, so the safest setup narrows the Grafana identity and turns on the read-only mode, tool selection and limits the server already includes.

SetupHowWhat it gives you
A read-only service accountGive the service account the Viewer role, or a custom role covering only the folders and datasources the task needsGrafana itself refuses writes, role changes and plugin installs, whatever the model asks for C1
Read-only datasource usersConnect SQL datasources in Grafana with database users that can only readQueries the model writes can read data but cannot change or drop it C4
Read-only mode--disable-writeThe server registers no write tools, so content the model reads cannot steer it into changing or deleting Grafana resources C5
Only the tools needed--disable-api and --disable-plugin, or --enabled-tools <list> naming just the categories the task usesThe model sees typed Grafana tools only, without the general API tool or plugin installs C3
A Loki query guardrail--loki-guardrail-mode enforceLog queries that would scan too much data or too long a time range are rejected before they run C10
Same-origin redirectsKeep the default --allow-cross-origin-redirects offThe token stays on the Grafana origin you configured C8
A rotated token fileGRAFANA_SERVICE_ACCOUNT_TOKEN_FILE pointing at a token you rotate on a scheduleA token that leaks stops working at the next rotation C8
A tool-call traceOTEL_EXPORTER_OTLP_TRACES_ENDPOINT or OTEL_EXPORTER_OTLP_ENDPOINT set to a collector you controlA span for every tool call, with its name, session and outcome, kept off the host C9

Approving with confidence

  • Read each prompt and approve write calls one at a time; every tool carries read-only and destructive hints your host can prompt on.
  • New contact points and plugin installs reach beyond this session, so approve them when you asked for that change.

Handling data

  • Anonymous, content-free usage statistics go to Grafana Labs by default; --usage-stats=disabled or DO_NOT_TRACK=1 turns them off.
  • --include-args-in-spans adds tool arguments to trace spans, so leave it off where traces reach shared storage.

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

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

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

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

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

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

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

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

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

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.