Agentic Data Plane
Preview

Grafana Managed MCP Server

The Grafana managed MCP server lets agents work with a Grafana instance: search dashboards and folders, list datasources, run PromQL queries against Prometheus datasources, run LogQL queries against Loki datasources, and create or update dashboards.

After reading this page, you will be able to:

  • Configure the Grafana managed MCP server with a service-account token

  • Pick the right service-account role for read versus write workflows

  • Search dashboards, query Prometheus and Loki, and upsert dashboards from the Inspector or an agent

What this MCP server does

Wraps Grafana’s HTTP API and proxies Prometheus and Loki queries through Grafana’s datasource proxy (/api/datasources/proxy/uid/{uid}/...). A single base URL plus one service-account token covers both the core API and datasource queries, so the gateway makes no separate network connection to the metric or log backends.

The tool surface is read-heavy. The one write tool is create_or_update_dashboard; there are no tools to mutate alerts or annotations. Authentication is a single shared service-account token, so every caller of this MCP server acts as that service account, and there is no per-user audit trail. Grafana exposes no OAuth client-registration flow for per-user delegation against an arbitrary instance, so the Grafana MCP server does not offer a User-OAuth mode.

Prerequisites

Before you create the server, make sure you have:

  • A Grafana instance and its base URL (for example, https://myorg.grafana.net).

  • Permission to create a service account and a service-account token in Grafana.

Get Grafana credentials

  1. In Grafana, go to Administration > Users and access > Service accounts.

  2. Create a service account with a role that can read dashboards and read and query data sources. To use create_or_update_dashboard, assign Editor (or a custom role with dashboard write permission) instead. If a read tool returns 403 Forbidden, the role is missing the data source permission it needs.

  3. On the service account, click Add service account token, then copy the generated token (glsa_…​). It is shown only once.

  4. Store the token in the Agentic Data Plane secret store under a name like GRAFANA_SERVICE_ACCOUNT_TOKEN.

Note your instance base URL and, if your instance is multi-org, the numeric org ID.

Configure

Create a new Grafana MCP server in Agentic Data Plane:

  1. Open MCP servers in the sidebar.

  2. Click Add MCP server.

  3. Click the Grafana card in the marketplace picker.

  4. Replace the suggested Name, and optionally add a Description.

  5. In the Grafana configuration form:

    Field Notes

    base_url

    Required. Base URL of your Grafana instance (for example, https://myorg.grafana.net). Link-local, cloud metadata, IPv6 unique local, and cluster-local hosts are rejected.

    org_id

    Optional. The numeric organization ID for a multi-org instance. Omit it to use the token’s default organization.

    Auth > service_account_token

    Secret-store reference holding the service-account token (for example, GRAFANA_SERVICE_ACCOUNT_TOKEN). UPPER_SNAKE_CASE.

    log_drop_labels

    Optional. Loki label names to hide from query_loki_logs results in the default compact label mode, as shell-style patterns (*, ?, [...]), for example kubernetes_*. Use it for log-pipeline plumbing labels that carry no diagnostic signal. An agent can still ask for a hidden label by name. An invalid pattern fails server creation.

    default_response_bytes

    Optional. Byte budget for one query_loki_logs or query_prometheus result when the caller sets no byte_budget. Default is 16384. A value above max_response_bytes is lowered to it.

    max_response_bytes

    Optional. Largest byte_budget a caller may ask for per query result. Default is 262144. Maximum is 4194304.

  6. Click Create server.

The create form turns Enable code mode on by default for this server type. rpk ai mcp-server create leaves it off unless you pass --code-mode. See Code Mode.

Configure from the CLI

rpk ai mcp-server create acme-grafana --enabled --managed.config '{
  "@type": "type.googleapis.com/redpanda.mcps.grafana.v1.GrafanaMCPConfig",
  "base_url": "https://myorg.grafana.net",
  "org_id": "1",
  "service_account_token": {
    "key_secret_ref": "GRAFANA_SERVICE_ACCOUNT_TOKEN"
  }
}'

Tools

The Grafana MCP exposes tools across dashboards, datasources, Prometheus, and Loki:

Tool Description

search_dashboards

Search dashboards and folders by query (title substring), tags, and type (dash-db or dash-folder). Returns curated hits (uid, title, type, tags, url, folder).

get_dashboard_summary

Fetch a curated summary of one dashboard by uid (title, tags, folder, and a compact per-panel list with each panel’s id, title, type, and datasource).

list_datasources

List configured datasources (uid, name, type, is_default), optionally only those of one type, such as loki or prometheus. Use the uid with the query tools.

query_prometheus

Run an instant or range PromQL query against a Prometheus datasource (datasource_uid, expr, query_type, time arguments, step, byte_budget, significant_digits). Returns a compacted result. See Query results.

list_prometheus_metric_names

List metric names in a Prometheus datasource (datasource_uid, optional filter regular expression, match series selector, limit).

list_prometheus_label_names

List label names in a Prometheus datasource (datasource_uid, optional filter, limit).

list_prometheus_label_values

List the values of one label in a Prometheus datasource (datasource_uid, label, optional match, filter, limit).

query_loki_logs

Run a LogQL query against a Loki datasource (datasource_uid, query, start, end, limit (default 100), direction; instant, step, and significant_digits for metric queries; labels, label_keys, raw_lines, max_line_bytes, byte_budget for output). Returns a compacted result. See Query results.

list_loki_label_names

List label names in a Loki datasource (datasource_uid, optional start, end, filter, limit).

list_loki_label_values

List the values of one label in a Loki datasource (datasource_uid, label, optional start, end, query stream selector, filter, limit).

create_or_update_dashboard

Create a dashboard or update an existing one (upsert on the model’s uid). Arguments: dashboard_json, folder_uid, overwrite, message. Requires an Editor service account.

On the tools that list metric names, label names, or label values, filter is an RE2 regular expression of at most 1024 bytes, and limit defaults to 500 and can go up to 5000. Each of these tools also returns total, the number of matches before limit was applied, so an agent can tell a full list from a truncated one.

Query results

The query_prometheus and query_loki_logs tools return a compacted result instead of the upstream JSON body, so a large query costs an agent far fewer tokens:

  • Labels that are identical on every entry or series are listed once in common_labels (a metric result with only one series keeps its labels on that series), and a UTC date shared by every timestamp is listed once in day, leaving clock times on the rows.

  • A log query returns entries, each one <time> {<labels not in common_labels>} <line>, in scan order. Consecutive identical entries collapse into one with a (repeated Nx since <time>) suffix, or (repeated Nx until <time>) when direction is forward. Lines are cut at max_line_bytes (default 1000) and marked with …[+N bytes].

  • A metric query returns series, each with its own labels and samples as space-separated time=value change points, where a value holds until the next point and | marks a gap. An instant query returns bare values. To count matching lines, use a LogQL metric query, such as count_over_time, instead of paging through entries.

  • total reports how many entries or series the query produced, and note is set whenever the result was cut or adjusted, with guidance on how to get the rest.

By default, query_loki_logs hides the labels a LogQL parser stage extracted from the line, because their values are already in the line. A parser-extracted label stays hidden even when the rendered line no longer shows its value, such as after the tool unwraps a log-shipper envelope or cuts the line at max_line_bytes. Labels that match the server’s log_drop_labels patterns are also hidden, and they never reappear on their own. To see one, name it in label_keys or set labels to LOKI_LABEL_MODE_ALL. On each entry, the default mode also omits labels whose value is already spelled out in the line, repeats another shown label, or matches the entry’s own timestamp. The tool also unwraps log-shipper envelopes and strips ANSI color codes. To read a narrow window at full fidelity, set labels to LOKI_LABEL_MODE_ALL (or name up to 64 labels in label_keys), set raw_lines to true, and raise max_line_bytes and byte_budget. To drop labels entirely, set labels to LOKI_LABEL_MODE_NONE.

The server caps each result at a byte budget. The budget is the server’s default_response_bytes when the caller sets no byte_budget, and never more than its max_response_bytes. A larger request is lowered to that maximum, and note says so. A range query’s step defaults to about 1/200 of the range (at least 15 seconds for Prometheus, one second for Loki), and significant_digits rounds sample values to save tokens, which is off by default.

Example: List datasources

curl -s https://aigw.<cluster-id>.clusters.rdpa.co/mcp/v1/acme-grafana \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": { "name": "list_datasources", "arguments": {} }
  }'

Replace <cluster-id> with your cluster ID and $TOKEN with a gateway access token.

Example: Run an instant PromQL query

Find the Prometheus datasource uid with list_datasources first, then query it:

curl -s https://aigw.<cluster-id>.clusters.rdpa.co/mcp/v1/acme-grafana \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "query_prometheus",
      "arguments": {
        "datasource_uid": "PBFA97CFB590B2093",
        "expr": "up",
        "query_type": "PROM_QUERY_TYPE_INSTANT"
      }
    }
  }'

Troubleshooting

Common symptoms and fixes:

Symptom What to check

401 Unauthorized

Confirm GRAFANA_SERVICE_ACCOUNT_TOKEN matches the token Grafana showed at creation, and that the service account is enabled.

403 Forbidden on create_or_update_dashboard

The service account’s role can’t write dashboards. Assign Editor (or a role with dashboard write permission).

403 Forbidden on list_datasources or a query tool

The service account’s role can’t read or query data sources. Grant it data source read and query permission.

Wrong organization’s data

The token resolves to its default organization. Set the org_id field to target a specific organization on a multi-org instance.

A query result carries a note saying it was cut or a limit was reached

The result hit a limit, and note names it. If it’s the Loki limit, raise limit, which defaults to 100 and goes up to 5000. If it’s the byte budget, narrow the time range or the selector first, then raise byte_budget up to the server’s max_response_bytes if you need more, or raise that limit on the server. For a metric query with many series, aggregate with sum by or topk, or use a coarser step.

A label you expect is missing from log entries

The default compact label mode hides parser-extracted labels and the server’s log_drop_labels patterns. On each entry it also drops labels whose value is already spelled out in the line or duplicates another label. A parsed label stays hidden even when the rendered line no longer shows its value, such as after the tool unwraps a log-shipper envelope, or when the line was cut at max_line_bytes. Set labels to LOKI_LABEL_MODE_ALL, or name the labels you want in label_keys.

A log line ends with …[+N bytes]

The line was longer than max_line_bytes. Raise it for that call, and raise byte_budget with it if the result then gets cut.

instant applies to metric queries only

A log query can’t be evaluated at a single point in time. Drop instant and pass start and end, or turn the query into a metric query such as count_over_time.

invalid filter regex

The filter argument must be an RE2 regular expression of at most 1024 bytes.