An open API service indexing awesome lists of open source software.

https://github.com/grafana/mcp-grafana

MCP server for Grafana
https://github.com/grafana/mcp-grafana

Last synced: about 23 hours ago
JSON representation

MCP server for Grafana

Awesome Lists containing this project

README

          

# Grafana MCP server

[![Unit Tests](https://github.com/grafana/mcp-grafana/actions/workflows/unit.yml/badge.svg)](https://github.com/grafana/mcp-grafana/actions/workflows/unit.yml)
[![Integration Tests](https://github.com/grafana/mcp-grafana/actions/workflows/integration.yml/badge.svg)](https://github.com/grafana/mcp-grafana/actions/workflows/integration.yml)
[![E2E Tests](https://github.com/grafana/mcp-grafana/actions/workflows/e2e.yml/badge.svg)](https://github.com/grafana/mcp-grafana/actions/workflows/e2e.yml)
[![Go Reference](https://pkg.go.dev/badge/github.com/grafana/mcp-grafana.svg)](https://pkg.go.dev/github.com/grafana/mcp-grafana)
[![MCP Catalog](https://archestra.ai/mcp-catalog/api/badge/quality/grafana/mcp-grafana)](https://archestra.ai/mcp-catalog/grafana__mcp-grafana)

A [Model Context Protocol][mcp] (MCP) server for Grafana.

This provides access to your Grafana instance and the surrounding ecosystem.

## Quick Start

Requires [uv](https://docs.astral.sh/uv/getting-started/installation/). Add the following to your MCP client configuration (e.g. Claude Desktop, Cursor):

```json
{
"mcpServers": {
"grafana": {
"command": "uvx",
"args": ["mcp-grafana"],
"env": {
"GRAFANA_URL": "http://localhost:3000",
"GRAFANA_SERVICE_ACCOUNT_TOKEN": ""
}
}
}
}
```

For Grafana Cloud, replace `GRAFANA_URL` with your instance URL (e.g. `https://myinstance.grafana.net`). See [Usage](#usage) for more installation options including Docker, binary, and Helm.

## Requirements

- **Grafana version 9.0 or later** is required for full functionality. Some features, particularly datasource-related operations, may not work correctly with earlier versions due to missing API endpoints.

## Features

_The following features are currently available in MCP server. This list is for informational purposes only and does not represent a roadmap or commitment to future features._

### Dashboards

- **Search for dashboards:** Find dashboards by title, folder UID, tag, or starred status
- **Get dashboard by UID:** Retrieve full dashboard details using its unique identifier. Pass optional `version` to load a saved snapshot instead of the current dashboard. _Warning: Large dashboards can consume significant context window space._
- **List dashboard versions:** List saved versions of a dashboard as compact metadata (version number, author, timestamp, save message)
- **Get dashboard summary:** Get a compact overview of a dashboard including title, panel count, panel types, variables, and metadata without the full JSON to minimize context window usage
- **Get dashboard property:** Extract specific parts of a dashboard using JSONPath expressions (e.g., `$.title`, `$.panels[*].title`) to fetch only needed data and reduce context window consumption
- **Update or create a dashboard:** Modify existing dashboards or create new ones. _Warning: Requires full dashboard JSON which can consume large amounts of context window space._
- **Patch dashboard:** Apply specific changes to a dashboard without requiring the full JSON, significantly reducing context window usage for targeted modifications
- **Get panel queries and datasource info:** Get the title, query string, and datasource information (including UID and type, if available) from every panel in a dashboard

### Run Panel Query

> **Note:** Run panel query tools are **disabled by default**. To enable them, add `runpanelquery` to your `--enabled-tools` flag.

- **Run panel query:** Execute a dashboard panel's query with custom time ranges and variable overrides.

#### Context Window Management

The dashboard tools now include several strategies to manage context window usage effectively ([issue #101](https://github.com/grafana/mcp-grafana/issues/101)):

- **Use `get_dashboard_summary`** for dashboard overview and planning modifications
- **Use `get_dashboard_property`** with JSONPath when you only need specific dashboard parts
- **Avoid `get_dashboard_by_uid`** unless you specifically need the complete dashboard JSON

### Datasources

- **List and fetch datasource information:** View all configured datasources and retrieve detailed information about each.
- _Supported datasource types: Prometheus, Loki, ClickHouse, CloudWatch, Elasticsearch, OpenSearch, Snowflake, Athena._

### Query Examples

> **Note:** Query examples tools are **disabled by default**. To enable them, add `examples` to your `--enabled-tools` flag.

- **Get query examples:** Retrieve example queries for different datasource types to learn query syntax.

### Prometheus Querying

- **Query Prometheus:** Execute PromQL queries (supports both instant and range metric queries) against Prometheus datasources.
- **Query Prometheus metadata:** Retrieve metric metadata, metric names, label names, and label values from Prometheus datasources.
- **Query histogram percentiles:** Calculate histogram percentile values (p50, p90, p95, p99) using histogram_quantile.

### Loki Querying

- **Query Loki logs and metrics:** Run both log queries and metric queries using LogQL against Loki datasources.
- **Query Loki metadata:** Retrieve label names, label values, and stream statistics from Loki datasources.
- **Query Loki patterns:** Retrieve log patterns detected by Loki to identify common log structures and anomalies.

### InfluxDB Querying

> **Note:** InfluxDB tools are **disabled by default**. To enable them, add `influxdb` to your `--enabled-tools` flag.

- **Query InfluxDB:** Execute queries against InfluxDB datasources using either InfluxQL (v1.x) or Flux (v2.x). The dialect is inferred from the datasource configuration, or can be set explicitly via the `dialect` parameter.

### SQL Datasource Querying

> **Note:** SQL tools are **disabled by default**. To enable them, add `sql` to your `--enabled-tools` flag. Back-compat aliases `clickhouse`, `snowflake`, and `athena` also work.

Unified SQL tools support **ClickHouse, Snowflake, Athena, MySQL, PostgreSQL, and MSSQL** through a single set of tools. Queries go through Grafana's datasource plugins, so authentication is handled by datasource configuration — credentials are never seen by the MCP server.

- **List databases/schemas/catalogs:** Discover organizational units for a SQL datasource. For Athena, omit catalog to list catalogs, or pass a catalog to list databases.
- **List tables:** List tables in a database or schema with metadata (row counts, sizes where available).
- **Describe table schema:** Get column names, types, nullability, defaults, and comments.
- **Query SQL:** Execute SQL queries with datasource-specific macro substitution (`$__timeFilter(col)`, `$__from/$__to`, `$__interval`, `${varname}`), automatic limit enforcement, and template variable support.

### CloudWatch Querying

> **Note:** CloudWatch tools are **disabled by default**. To enable them, add `cloudwatch` to your `--enabled-tools` flag.

- **List CloudWatch namespaces:** Discover available AWS CloudWatch namespaces.
- **List CloudWatch metrics:** List metrics available in a specific namespace.
- **List CloudWatch dimensions:** Get dimensions for filtering metric queries.
- **Query CloudWatch:** Execute CloudWatch metric queries with time range support.

### Google Cloud Logging Querying

> **Note:** Google Cloud Logging tools are **disabled by default**. To enable them, add `cloudlogging` to your `--enabled-tools` flag. Requires the [Google Cloud Logging datasource plugin](https://grafana.com/grafana/plugins/googlecloud-logging-datasource/) (`googlecloud-logging-datasource`) version 1.8.0 or later, which needs Grafana 11.2+. Older plugin versions return a different response layout and `query_cloud_logging` reports an error asking for an upgrade.

- **List Cloud Logging projects:** Discover the GCP project IDs the datasource can read logs from.
- **List Cloud Logging buckets and views:** Discover log buckets and log views to scope a query.
- **Query Cloud Logging:** Run Cloud Logging query language filters (e.g. `resource.type="k8s_container" AND severity>=ERROR`) with time range and limit; returns entries newest-first with severity, body, labels, and trace ID. GCP authentication is handled by the datasource configuration.

### Graphite Querying

> **Note:** Graphite tools are **disabled by default**. To enable them, add `graphite` to your `--enabled-tools` flag.

- **Query Graphite:** Execute Graphite render API queries against a Graphite datasource.
- **List Graphite metrics:** Browse and discover Graphite metric paths.
- **List Graphite tags:** List available Graphite tags and tag values.
- **Query Graphite density:** Query Graphite metric density for a given pattern.

### Elasticsearch/OpenSearch Querying

> **Note:** Elasticsearch/OpenSearch tools are **disabled by default**. To enable them, add `elasticsearch` to your `--enabled-tools` flag.

- **Query Elasticsearch/OpenSearch:** Execute search queries against Elasticsearch or OpenSearch datasources using either Lucene query syntax or Elasticsearch Query DSL. Supports filtering by time range and retrieving logs, metrics, or any indexed data. Returns documents with their index, ID, source fields, and optional relevance score.

### Quickwit Querying

> **Note:** Quickwit tools are **disabled by default**. To enable them, add `quickwit` to your `--enabled-tools` flag.

- **Query Quickwit:** Execute search queries against Quickwit datasources using Lucene query syntax or partial Elasticsearch-compatible Query DSL. Supports filtering by time range and retrieving logs or other indexed documents. Returns documents with their index, ID, source fields, and optional relevance score.

### Agent Observability

> **Note:** Agent Observability tools are **disabled by default** and work only in Grafana Cloud. To enable them, add `agento11y` to your `--enabled-tools` flag.

- **List and search conversations:** List recent LLM conversations or search them with a filter expression (model, provider, agent, status, error type, eval results, and more) over a time range. Search results include error counts, rating summaries, evaluation summaries, and trace IDs.
- **Get conversation detail:** Fetch a single conversation with all its generations, including prompts and outputs.
- **Get generation detail and scores:** Fetch a single generation by ID, and its evaluation scores (evaluator, score key, value, passed, explanation).
- **Read the agent catalog:** List the agents that send telemetry, fetch one agent version in full (complete system prompt, every tool with its JSON schema, and the models it ran on), walk an agent's version history, and compare evaluation score aggregates per version. Effective versions are `sha256:` hashes that a tool change never affects; for an agent that reports no version of its own they hash the system prompt, so a prompt edit mints a new version. Catalog and version rows carry a `token_estimate`, which is worth checking before fetching a full prompt.
- **Inspect evaluators and templates:** Read the evaluators a score came from, the templates they were derived from, and the judge providers and models available to LLM-judge evaluators. With write tools enabled, also create, fork, test, and delete evaluators.
- **Inspect eval rules and guards:** Read the asynchronous eval rules that bind evaluators to production traffic, and the guards (hook rules) that run inline and can warn or deny. With write tools enabled, also create, update, preview, and delete them. Writes and the non-persisting `preview_rule` and `test_evaluator` operations need the `grafana-agento11y-app.eval:write` permission, granted by the Agento11y Admin role.
- **Curate saved conversations and collections:** Read the saved conversations (bookmarks that give a conversation a stable ID, name, and tags) and the collections that group them, including each collection's member count and the collections embedded in every saved-conversation row. With write tools enabled, also bookmark a conversation, create and edit collections, and add or remove members. These writes need the same `grafana-agento11y-app.eval:write` permission.
- **Read and edit test suites:** List the versioned test suites that offline experiments run against, read one with its full version history, and page through the test cases of a version. With write tools enabled, also create a suite, rename or retag it, open a draft version, publish it, and write or delete its test cases. A published version is frozen, so an edit means opening a new draft. These writes need `grafana-agento11y-app.eval:write`.
- **Read offline experiments:** List the evaluation runs over a test suite and read one with its headline pass rate, cost, and token totals. Drill down through a per-test-case report to trials, their scores with each judge's explanation, and their artifact metadata. With write tools enabled, also rename or retag an experiment and cancel a running one, which need `grafana-agento11y-app.eval:write`. Experiments are created by SDK runners, not by this tool.

### Grafana Assistant

> **Note:** Assistant tools are **disabled by default** and require the [Grafana Assistant](https://grafana.com/docs/grafana-cloud/machine-learning/assistant/) plugin (`grafana-assistant-app`) to be installed on the target Grafana instance. They are also **write tools** (the assistant may mutate stack state), so they are skipped when `--disable-write` is set. To enable them, add `assistant` to your `--enabled-tools` flag.

- **Ask the assistant:** Send a natural-language prompt to Grafana Assistant and wait for the full text reply. The assistant may use tools, metrics, logs, and other stack context—broader than firing one isolated data-source query. Pass the returned `contextId` back in a follow-up call to continue the same conversation. Complex tasks can take several minutes; the call blocks until the reply is done or the request times out (5 minutes).

### Incidents

- **Search, create, and update incidents:** Manage incidents in Grafana Incident, including searching, creating, adding activities, and reading or setting custom fields.

### Alerting

- **List and fetch alert rule information:** View alert rules and their statuses (firing/normal/error/etc.) in Grafana. Supports both Grafana-managed rules and datasource-managed rules from Prometheus or Loki datasources.
- **Create and update alert rules:** Create new alert rules or modify existing ones.
- **Delete alert rules:** Remove alert rules by UID.
- **Manage alerting routing:** View notification policies, contact points, and time intervals. Supports both Grafana-managed contact points and receivers from external Alertmanager datasources (Prometheus Alertmanager, Mimir, Cortex).

### Grafana OnCall

- **List and manage schedules:** View and manage on-call schedules in Grafana OnCall.
- **Get shift details:** Retrieve detailed information about specific on-call shifts.
- **Get current on-call users:** See which users are currently on call for a schedule.
- **List teams and users:** View all OnCall teams and users.
- **List alert groups:** View and filter alert groups from Grafana OnCall by various criteria including state, integration, labels, and time range.
- **Get alert group details:** Retrieve detailed information about a specific alert group by its ID.

### Admin

> **Note:** Admin tools are **disabled by default**. To enable them, include `admin` in your `--enabled-tools` flag.
- **List teams:** View all configured teams in Grafana.
- **List Users:** View all users in an organization in Grafana.
- **List all roles:** List all Grafana roles, with an optional filter for delegatable roles.
- **Get role details:** Get details for a specific Grafana role by UID.
- **List assignments for a role:** List all users, teams, and service accounts assigned to a role.
- **List roles for users:** List all roles assigned to one or more users.
- **List roles for teams:** List all roles assigned to one or more teams.
- **List permissions for a resource:** List all permissions defined for a specific resource (dashboard, datasource, folder, etc.).
- **Describe a Grafana resource:** List available permissions and assignment capabilities for a resource type.

### User

- **User info:** Get the current Grafana identity — login, email, name, whether it is a Grafana (server) admin, the current organization, and the organizations the credential can access (with roles). Use it to discover valid `orgId` values for [multi-organization](#multi-organization-support) requests.

### Navigation

- **Generate deeplinks:** Create accurate deeplink URLs for Grafana resources instead of relying on LLM URL guessing.
- **Dashboard links:** Generate direct links to dashboards using their UID (e.g., `http://localhost:3000/d/dashboard-uid`)
- **Panel links:** Create links to specific panels within dashboards with viewPanel parameter (e.g., `http://localhost:3000/d/dashboard-uid?viewPanel=5`)
- **Explore links:** Generate links to Grafana Explore with pre-configured datasources (e.g., `http://localhost:3000/explore?schemaVersion=1&panes={"a":{"datasource":"prometheus-uid"}}`). Grafana below 10.2 does not understand `panes`, so the legacy `?left={...}` format is emitted for those versions instead.
- **Time range support:** Add time range parameters to links (`from=now-1h&to=now`)
- **Custom parameters:** Include additional query parameters like dashboard variables or refresh intervals

### Annotations

- **Get Annotations:** Query annotations with filters. Supports time range, dashboard UID, tags, and match mode.
- **Create Annotation:** Create a new annotation on a dashboard or panel.
- **Create Graphite Annotation:** Create annotations using Graphite format (`what`, `when`, `tags`, `data`).
- **Update Annotation:** Replace all fields of an existing annotation (full update).
- **Patch Annotation:** Update only specific fields of an annotation (partial update).
- **Delete Annotation:** Permanently delete an annotation by ID.
- **Get Annotation Tags:** List available annotation tags with optional filtering.

### Snapshots

- **List snapshots:** List dashboard snapshots with optional query and limit filters.
- **Get snapshot:** Retrieve snapshot metadata and dashboard payload by snapshot key.
- **Create snapshot:** Create a dashboard snapshot from a full dashboard payload, with optional expiration and external snapshot options.
- **Delete snapshot:** Delete a snapshot by snapshot key.

### Rendering

- **Get panel or dashboard image:** Render a Grafana dashboard panel or full dashboard as a PNG image. Returns the image as base64 encoded data for use in reports, alerts, or presentations. Supports customizing dimensions, time range, theme, scale, and dashboard variables. Also supports rendering not-yet-applied dashboards from a provisioning repository branch (e.g. a git-sync PR preview) via the optional `provisioningPreview` parameter.
- _Note: Requires the [Grafana Image Renderer](https://grafana.com/docs/grafana/latest/setup-grafana/image-rendering/) service to be installed and configured._

### Provisioning

- **List provisioning repositories:** List provisioning repositories configured for this Grafana instance (e.g. git-sync sources), returning each repository's slug along with its source URL, branch, path, sync state, and health.
- **Validate provisioning file:** Dry-run-apply a file from a provisioning repository at a given branch or commit. Returns whether it would be accepted, the resource action (create/update), the target resource type, and any structured validation errors — the same admission surface Grafana's PR commenter uses.

The list of tools is configurable, so you can choose which tools you want to make available to the MCP client.
This is useful if you don't use certain functionality or if you don't want to take up too much of the context window.
To disable a category of tools, use the `--disable-` flag when starting the server. For example, to disable
the OnCall tools, use `--disable-oncall`, or to disable navigation deeplink generation, use `--disable-navigation`.

#### RBAC Permissions

Each tool requires specific RBAC permissions to function properly. When creating a service account for the MCP server, ensure it has the necessary permissions based on which tools you plan to use. The permissions listed are the minimum required actions - you may also need appropriate scopes (e.g., `datasources:*`, `dashboards:*`, `folders:*`) depending on your use case.

Tip: If you're not familiar with Grafana RBAC or you want a quicker, simpler setup instead of configuring many granular scopes, you can assign a built-in role such as `Editor` to the service account. The `Editor` role grants broad read/write access that will allow most MCP server operations; it is less granular (and therefore less restrictive) than manually-applied scopes, so use it only when convenience is more important than strict least-privilege access.

**Note:** OnCall and other plugin-backed tools are authorized by plugin actions such as `grafana-irm-app.schedules:read`. The basic Viewer role includes the read actions and Editor the write actions. Incident tools need only `plugins.app:access`; IRM authorizes incident actions by basic role.

Actions in `group/resource:verb` form, such as `dashboard.grafana.app/dashboards:get`, apply only to on-behalf-of access tokens. A service account needs only the other actions listed.

For more information about Grafana RBAC, see the [official documentation](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/access-control/).

#### RBAC Scopes

Scopes define the specific resources that permissions apply to. Each action requires both the appropriate permission and scope combination.

**Common Scope Patterns:**

- **Broad access:** Use `*` wildcards for organization-wide access

- `datasources:*` - Access to all datasources
- `dashboards:*` - Access to all dashboards
- `folders:*` - Access to all folders
- `teams:*` - Access to all teams

- **Limited access:** Use specific UIDs or IDs to restrict access to individual resources
- `datasources:uid:prometheus-uid` - Access only to a specific Prometheus datasource
- `dashboards:uid:abc123` - Access only to dashboard with UID `abc123`
- `folders:uid:xyz789` - Access only to folder with UID `xyz789`
- `teams:id:5` - Access only to team with ID `5`
- `global.users:id:123` - Access only to user with ID `123`

**Examples:**

- **Full MCP server access:** Grant broad permissions for all tools

```
datasources:* (datasources:read, datasources:query)
dashboards:* (dashboards:read, dashboards:create, dashboards:write)
folders:* (for dashboard creation and alert rules)
teams:* (teams:read)
global.users:* (users:read)
```

- **Limited datasource access:** Only query specific Prometheus and Loki instances

```
datasources:uid:prometheus-prod (datasources:query)
datasources:uid:loki-prod (datasources:query)
```

- **Dashboard-specific access:** Read only specific dashboards
```
dashboards:uid:monitoring-dashboard (dashboards:read)
dashboards:uid:alerts-dashboard (dashboards:read)
```

### Tools

| Tool | Category | Description | Required RBAC Permissions | Required Scopes |
| ----------------------------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
| `list_teams` | Admin* | List all teams | `teams:read` | `teams:*` or `teams:id:1` |
| `list_users_by_org` | Admin* | List users in an organization, with search and pagination | `org.users:read` | `global.users:*` or `global.users:id:123` |
| `list_all_roles` | Admin* | List all Grafana roles | `roles:read` | `roles:*` |
| `get_role_details` | Admin* | Get details for a Grafana role | `roles:read` | `roles:uid:editor` |
| `get_role_assignments` | Admin* | List assignments for a role | `roles:read`, `teams.roles:read`, `users.roles:read` | `roles:uid:editor` |
| `list_user_roles` | Admin* | List roles for users | `users.roles:read` | `global.users:id:123` |
| `list_team_roles` | Admin* | List roles for teams | `teams.roles:read` | `teams:id:7` |
| `get_resource_permissions` | Admin* | List permissions for a resource | `dashboards.permissions:read`, `datasources.permissions:read`, `folders.permissions:read`, `serviceaccounts.permissions:read`, `teams.permissions:read`, `users.permissions:read` | `dashboards:uid:abcd1234` |
| `get_resource_description` | Admin* | Describe a Grafana resource type | `dashboards.permissions:read`, `datasources.permissions:read`, `folders.permissions:read`, `serviceaccounts.permissions:read`, `teams.permissions:read`, `users.permissions:read` | `dashboards:*` |
| `user_info` | User | Current identity, capabilities, and accessible organizations | None | — |
| `search_dashboards` | Search | Search for dashboards by query, folder UID, tag, or starred | `dashboards:read`, `folders:read` | `dashboards:*` or `dashboards:uid:abc123` |
| `search_folders` | Search | Search for folders by title | `folders:read` | `folders:*` or `folders:uid:xyz789` |
| `get_dashboard_by_uid` | Dashboard | Get a dashboard by uid, optionally a saved version | `dashboard.grafana.app/dashboards:get`, `dashboards:read` | `dashboards:uid:abc123` |
| `list_dashboard_versions` | Dashboard | List saved versions of a dashboard (version, author, time, message) | `dashboards:read` | `dashboards:uid:abc123` |
| `update_dashboard` | Dashboard | Update or create a new dashboard | `dashboard.grafana.app/dashboards:create`, `dashboard.grafana.app/dashboards:get`, `dashboard.grafana.app/dashboards:update`, `dashboards:create`, `dashboards:read`, `dashboards:write`, `folders:read` | `dashboards:*`, `folders:*` or `folders:uid:xyz789` |
| `get_dashboard_panel_queries` | Dashboard | Get panel title, queries, datasource UID and type from a dashboard | `dashboard.grafana.app/dashboards:get`, `dashboards:read` | `dashboards:uid:abc123` |
| `run_panel_query` | RunPanelQuery* | Execute one or more dashboard panel queries | `dashboard.grafana.app/dashboards:get`, `dashboards:read`, `datasources:query`, `datasources:read` | `dashboards:uid:*`, `datasources:uid:*` |
| `get_dashboard_property` | Dashboard | Extract specific parts of a dashboard using JSONPath expressions | `dashboard.grafana.app/dashboards:get`, `dashboards:read` | `dashboards:uid:abc123` |
| `get_dashboard_summary` | Dashboard | Get a compact summary of a dashboard without full JSON | `dashboard.grafana.app/dashboards:get`, `dashboards:read` | `dashboards:uid:abc123` |
| `create_folder` | Dashboard | Create a folder | `folders:create`, `folders:read`, `folders:write` | `folders:*` |
| `list_datasources` | Datasources | List datasources | `datasources:read` | `datasources:*` |
| `get_datasource` | Datasources | Get a datasource by UID or name | `datasources:read` | `datasources:uid:prometheus-uid` |
| `check_datasources_health` | Datasources | Check the health of one or more datasources | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `create_datasource` | Datasources | Create a datasource | `datasources:create`, `datasources:read` | `datasources:*` |
| `update_datasource` | Datasources | Update a datasource | `datasources:read`, `datasources:write` | `datasources:*` or `datasources:uid:abc123` |
| `get_query_examples` | Examples* | Get example queries for a datasource type | None | `datasources:*` |
| `query_prometheus` | Prometheus | Execute a query against a Prometheus datasource | `datasources:query`, `datasources:read` | `datasources:uid:prometheus-uid` |
| `list_prometheus_metric_metadata` | Prometheus | List metric metadata | `datasources:query`, `datasources:read` | `datasources:uid:prometheus-uid` |
| `list_prometheus_metric_names` | Prometheus | List available metric names | `datasources:query`, `datasources:read` | `datasources:uid:prometheus-uid` |
| `list_prometheus_label_names` | Prometheus | List label names matching a selector | `datasources:query`, `datasources:read` | `datasources:uid:prometheus-uid` |
| `list_prometheus_label_values` | Prometheus | List values for a specific label | `datasources:query`, `datasources:read` | `datasources:uid:prometheus-uid` |
| `query_prometheus_histogram` | Prometheus | Calculate histogram percentile values | `datasources:query`, `datasources:read` | `datasources:uid:prometheus-uid` |
| `list_incidents` | Incident | List incidents in Grafana Incident, optionally with their custom field values | `plugins.app:access` | N/A |
| `create_incident` | Incident | Create an incident in Grafana Incident, optionally setting custom fields | `plugins.app:access` | N/A |
| `add_activity_to_incident` | Incident | Add an activity item to an incident in Grafana Incident | `plugins.app:access` | N/A |
| `update_incident` | Incident | Update an incident in Grafana Incident (status, severity, title, or custom fields) | `plugins.app:access` | N/A |
| `get_incident` | Incident | Get a single incident by ID, including its custom fields | `plugins.app:access` | N/A |
| `list_incident_custom_fields` | Incident | List the custom fields configured for incidents, with their types and select options | `plugins.app:access` | N/A |
| `query_loki_logs` | Loki | Query and retrieve logs using LogQL (either log or metric queries) | `datasources:query`, `datasources:read` | `datasources:uid:loki-uid` |
| `list_loki_label_names` | Loki | List all available label names in logs | `datasources:query`, `datasources:read` | `datasources:uid:loki-uid` |
| `list_loki_label_values` | Loki | List values for a specific log label | `datasources:query`, `datasources:read` | `datasources:uid:loki-uid` |
| `query_loki_stats` | Loki | Get statistics about log streams | `datasources:query`, `datasources:read` | `datasources:uid:loki-uid` |
| `query_loki_patterns` | Loki | Query detected log patterns to identify common structures | `datasources:query`, `datasources:read` | `datasources:uid:loki-uid` |
| `analyze_loki_labels` | Loki | Audit a Loki label strategy (live or static) and optionally diagnose query performance | `datasources:query`, `datasources:read` | `datasources:uid:loki-uid` |
| `suggest_loki_alloy_label_config` | Config | Generate an Alloy `loki.process` snippet enforcing approved labels | None | N/A |
| `query_influxdb` | InfluxDB* | Query InfluxDB using InfluxQL (v1) or Flux (v2) | `datasources:query`, `datasources:read` | `datasources:uid:influxdb-uid` |
| `list_sql_databases` | SQL* | List databases, schemas, or catalogs from a SQL datasource | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `list_sql_tables` | SQL* | List tables in a SQL datasource | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `describe_sql_table` | SQL* | Get column schema for a table | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `query_sql` | SQL* | Execute SQL queries with macro substitution | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `list_cloudwatch_namespaces` | CloudWatch* | List available AWS CloudWatch namespaces | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `list_cloudwatch_metrics` | CloudWatch* | List metrics in a namespace | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `list_cloudwatch_dimensions` | CloudWatch* | List dimensions for a metric | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `list_cloudwatch_dimension_values` | CloudWatch* | List values for a dimension key | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `query_cloudwatch` | CloudWatch* | Execute CloudWatch metric queries | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `list_cloud_logging_projects` | Cloud Logging* | List GCP projects readable by a Google Cloud Logging datasource | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `list_cloud_logging_buckets` | Cloud Logging* | List log buckets in a GCP project | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `list_cloud_logging_views` | Cloud Logging* | List log views in a log bucket | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `query_cloud_logging` | Cloud Logging* | Query logs with the Cloud Logging query language | `datasources:query`, `datasources:read` | `datasources:uid:*` |
| `query_elasticsearch` | Elasticsearch/OpenSearch* | Query Elasticsearch or OpenSearch using Lucene syntax or Query DSL | `datasources:query`, `datasources:read` | `datasources:uid:datasource-uid` |
| `query_quickwit` | Quickwit* | Query Quickwit using Lucene syntax or Query DSL | `datasources:query`, `datasources:read` | `datasources:uid:quickwit-uid` |
| `alerting_rules_read` | Alerting | List and inspect alert rules (list, get, versions) | `alert.rules.external:read`, `alert.rules:read`, `datasources:read`, `folders:read` | `folders:*` or `folders:uid:alerts-folder` |
| `alerting_rules_write` | Alerting | Create, update, and delete alert rules | `alert.provisioning.provenance:write`, `alert.rules:create`, `alert.rules:delete`, `alert.rules:read`, `alert.rules:write`, `folders:read` | `folders:*` or `folders:uid:alerts-folder` |
| `alerting_manage_routing` | Alerting | Manage notification policies, contact points, and time intervals | `alert.notifications.external:read`, `alert.notifications:read`, `datasources:query`, `datasources:read` | Global scope |
| `alerting_routing_write` | Alerting | Create Grafana-managed contact points | `alert.notifications.receivers:create`, `alert.provisioning.provenance:write` | Global scope |
| `alerting_silences_read` | Alerting | List and inspect alerting silences (list, get) | `alert.instances:read`, `alert.silences:read` | Global scope |
| `alerting_silences_write` | Alerting | Create, update, and expire alerting silences | `alert.instances:create`, `alert.instances:read`, `alert.instances:write`, `alert.silences:create`, `alert.silences:read`, `alert.silences:write` | Global scope |
| `list_oncall_schedules` | OnCall | List schedules from Grafana OnCall | `grafana-irm-app.schedules:read`, `plugins.app:access` | Plugin-specific scopes |
| `get_oncall_shift` | OnCall | Get details for a specific OnCall shift | `grafana-irm-app.schedules:read`, `plugins.app:access` | Plugin-specific scopes |
| `get_current_oncall_users` | OnCall | Get users currently on-call for a specific schedule | `grafana-irm-app.schedules:read`, `grafana-irm-app.user-settings:read`, `plugins.app:access` | Plugin-specific scopes |
| `list_oncall_teams` | OnCall | List teams from Grafana OnCall | `grafana-irm-app.user-settings:read`, `plugins.app:access` | Plugin-specific scopes |
| `list_oncall_users` | OnCall | List users from Grafana OnCall | `grafana-irm-app.user-settings:read`, `plugins.app:access` | Plugin-specific scopes |
| `list_alert_groups` | OnCall | List alert groups from Grafana OnCall with filtering options | `grafana-irm-app.alert-groups:read`, `plugins.app:access` | Plugin-specific scopes |
| `get_alert_group` | OnCall | Get a specific alert group from Grafana OnCall by its ID | `grafana-irm-app.alert-groups:read`, `plugins.app:access` | Plugin-specific scopes |
| `update_alert_group` | OnCall | Acknowledge, unacknowledge, resolve, or unresolve an alert group | `grafana-irm-app.alert-groups:read`, `grafana-irm-app.alert-groups:write`, `plugins.app:access` | Plugin-specific scopes |
| `list_pyroscope_label_names` | Pyroscope | List label names matching a selector | `datasources:query`, `datasources:read` | `datasources:uid:pyroscope-uid` |
| `list_pyroscope_label_values` | Pyroscope | List label values matching a selector for a label name | `datasources:query`, `datasources:read` | `datasources:uid:pyroscope-uid` |
| `list_pyroscope_profile_types` | Pyroscope | List available profile types | `datasources:query`, `datasources:read` | `datasources:uid:pyroscope-uid` |
| `query_pyroscope` | Pyroscope | Query profiles, metrics, or both from Pyroscope | `datasources:query`, `datasources:read` | `datasources:uid:pyroscope-uid` |
| `get_assertions` | Asserts | Get assertion summary for a given entity | `plugins.app:access` | Plugin-specific scopes |
| `agento11y_manage_conversations` | Agent Observability* | List, search, and fetch LLM conversations from Grafana Agent Observability | `grafana-agento11y-app.conversations:read`, `grafana-agento11y-app.data:read`, `plugins.app:access` | N/A |
| `agento11y_manage_generations` | Agent Observability* | Fetch LLM generation details and evaluation scores from Grafana Agent Observability | `grafana-agento11y-app.conversations:read`, `grafana-agento11y-app.data:read`, `plugins.app:access` | N/A |
| `agento11y_manage_agents` | Agent Observability* | Read the agent catalog: list agents, get one agent version in full, list version history, and per-version score aggregates | `grafana-agento11y-app.conversations:read`, `grafana-agento11y-app.data:read`, `plugins.app:access` | N/A |
| `agento11y_manage_evaluators` | Agent Observability* | Manage evaluators, evaluator templates, and the judge catalog (list, get, upsert, fork, test, delete) | `grafana-agento11y-app.conversations:read`, `grafana-agento11y-app.data:read`, `plugins.app:access`; with writes enabled also `grafana-agento11y-app.eval:write` | N/A |
| `agento11y_manage_eval_rules` | Agent Observability* | Manage eval rules and guards (list, get, create, update, preview, delete) | `grafana-agento11y-app.conversations:read`, `grafana-agento11y-app.data:read`, `plugins.app:access`; with writes enabled also `grafana-agento11y-app.eval:write` | N/A |
| `agento11y_manage_eval_collections` | Agent Observability* | Manage saved conversations and the collections that group them (list, get, save, create, update, delete, add and remove members) | `grafana-agento11y-app.conversations:read`, `grafana-agento11y-app.data:read`, `plugins.app:access`; with writes enabled also `grafana-agento11y-app.eval:write` | N/A |
| `agento11y_manage_experiments` | Agent Observability* | Read offline experiments, their trials, scores, artifact metadata, and filter facets; update and cancel an experiment | `grafana-agento11y-app.conversations:read`, `grafana-agento11y-app.data:read`, `plugins.app:access`; with writes enabled also `grafana-agento11y-app.eval:write` | N/A |
| `agento11y_manage_test_suites` | Agent Observability* | Manage the test suites that offline experiments run against, their versions, and their test cases (list, get, create, update, draft, publish, upsert, delete) | `grafana-agento11y-app.conversations:read`, `grafana-agento11y-app.data:read`, `plugins.app:access`; with writes enabled also `grafana-agento11y-app.eval:write` | N/A |
| `ask_assistant` | Assistant* | Send a prompt to Grafana Assistant and return the full text reply (multi-turn via `contextId`) | `plugins.app:access` | Plugin-specific scopes |
| `generate_deeplink` | Navigation | Generate accurate deeplink URLs for Grafana resources | None | N/A |
| `get_annotations` | Annotations | Fetch annotations with filters | `annotations:read` | `annotations:*` or `annotations:id:123` |
| `create_annotation` | Annotations | Create a new annotation (standard or Graphite format) | `annotations:create` | `annotations:*` |
| `update_annotation` | Annotations | Update specific fields of an annotation (partial update) | `annotations:write` | `annotations:*` |
| `delete_annotation` | Annotations | Delete an annotation by ID | `annotations:delete` | `annotations:*` |
| `get_annotation_tags` | Annotations | List annotation tags with optional filtering | `annotations:read` | `annotations:*` |
| `list_snapshots` | Snapshot | List dashboard snapshots with optional query and limit filters | `snapshots:read` | N/A |
| `get_snapshot` | Snapshot | Get snapshot metadata and dashboard payload by snapshot key | None | N/A |
| `create_snapshot` | Snapshot | Create a dashboard snapshot from a full dashboard payload | `dashboards:read`, `snapshots:create` | `dashboards:uid:abc123` |
| `delete_snapshot` | Snapshot | Delete a dashboard snapshot by snapshot key | `dashboards:write`, `snapshots:delete` | `dashboards:uid:abc123` |
| `get_panel_image` | Rendering | Render a stored dashboard or panel, a provisioning preview, or an ad-hoc Explore view as a PNG image | `dashboards:read`, `datasources:explore`, `datasources:query`, `datasources:read`, `provisioning.repositories:read` | `dashboards:uid:abc123` |
| `list_provisioning_repositories` | Provisioning | List provisioning repositories (e.g. git-sync sources) with their source URL, branch, sync state, and health | `provisioning.grafana.app/repositories:list`, `provisioning.repositories:read` | N/A |
| `validate_provisioning_file` | Provisioning | Dry-run-apply a file from a provisioning repository and report admission validation errors | `dashboard.grafana.app/dashboards:get`, `dashboards:read`, `folder.grafana.app/folders:get`, `folders:read`, `provisioning.grafana.app/repositories:get`, `provisioning.repositories:read` | N/A |
| `search_docs` | Docs | Search Grafana documentation or list product groups (omit query to list products) | None | N/A |
| `get_doc` | Docs | Fetch a documentation page; set outline_only for headings, or section for bounded retrieval | None | N/A |
| `search_tempo_traces` | Tempo | Search traces with TraceQL | `datasources:query`, `datasources:read` | `datasources:uid:tempo-uid` |
| `query_tempo_metrics` | Tempo | Compute metrics from traces with TraceQL | `datasources:query`, `datasources:read` | `datasources:uid:tempo-uid` |
| `get_tempo_trace` | Tempo | Fetch a trace by ID | `datasources:query`, `datasources:read` | `datasources:uid:tempo-uid` |
| `diff_tempo_traces` | Tempo | Compare two traces | `datasources:query`, `datasources:read` | `datasources:uid:tempo-uid` |
| `list_tempo_attribute_names` | Tempo | List span and resource attribute names | `datasources:query`, `datasources:read` | `datasources:uid:tempo-uid` |
| `list_tempo_attribute_values` | Tempo | List values for a trace attribute | `datasources:query`, `datasources:read` | `datasources:uid:tempo-uid` |
| `get_tempo_traceql_docs` | Tempo | Get TraceQL documentation | None | N/A |
| `query_graphite` | Graphite* | Query Graphite metrics | `datasources:query`, `datasources:read` | `datasources:uid:graphite-uid` |
| `query_graphite_density` | Graphite* | Query Graphite metric density | `datasources:query`, `datasources:read` | `datasources:uid:graphite-uid` |
| `list_graphite_metrics` | Graphite* | List Graphite metrics | `datasources:query`, `datasources:read` | `datasources:uid:graphite-uid` |
| `list_graphite_tags` | Graphite* | List Graphite tags | `datasources:query`, `datasources:read` | `datasources:uid:graphite-uid` |
| `get_plugin` | Plugins | Get an installed plugin | `plugins.app:access` | N/A |
| `search_plugin_information` | Plugins | Search the grafana.com plugin catalog | None | N/A |
| `install_plugin` | Plugins | Install a plugin | `plugins:install` | N/A |
| `grafana_api_request` | API | Call a Grafana HTTP API endpoint | None | Depends on the endpoint |

_* Disabled by default. Add category to `--enabled-tools` to enable._

The `get_tempo_trace` tool displays an interactive trace viewer in compatible MCP hosts whenever Tempo query tools are enabled. Its existing text output remains available. See [MCP Apps](docs/mcp-apps.md) for setup and library embedding.

## CLI Flags Reference

The `mcp-grafana` binary supports various command-line flags for configuration:

**Transport Options:**
- `-t, --transport`: Transport type (`stdio`, `sse`, or `streamable-http`) - default: `stdio`
- `--address`: The host and port for SSE/streamable-http server - default: `localhost:8000`
- `--base-path`: Base path for the SSE/streamable-http server. `/healthz` and `/metrics` are always served at the server root, not under this prefix — they're internal-only endpoints for probes and scrapers, and keeping them off the application prefix makes it easier to expose the API through a reverse proxy without also exposing them
- `--endpoint-path`: Endpoint path for the streamable-http server, appended to `--base-path` - default: `/mcp`
- `--server-name`: Server name used in the MCP handshake and OTel `service.name` - default: `mcp-grafana`. Overrides `GRAFANA_MCP_SERVER_NAME` env var
- `--instructions-append`: Text appended to the server instructions returned to MCP clients on initialize, so every connecting agent sees it

> [!NOTE]
> Over SSE, per-request headers do not reach tool calls: `X-Grafana-Service-Account-Token` / `X-Grafana-API-Key`, `X-Grafana-Org-Id`, and headers listed in `GRAFANA_FORWARD_HEADERS` have no effect, tool calls use the server's environment credentials, and `X-Grafana-URL` overrides do not work. Use streamable-http when each caller needs its own Grafana URL, credentials, or organization.

**HTTP Transport Security (SSE / streamable-http only):**

`Host`/`Origin` validation is enforced on *every* route on the MCP listener — `/sse`, `/mcp`, and `/healthz` / `/metrics` when they share that listener — so a DNS-rebinding browser cannot reach any of them. Stdio transport is unaffected. `--healthz-address` and `--metrics-address` start a separate listener that is not wrapped.

- `--allowed-hosts`: Comma-separated allowlist of `Host` header values. Defaults to loopback variants of `--address` (e.g. `localhost:8000,127.0.0.1:8000,[::1]:8000`). A value that parses to empty (unset, `,`, ` , `, etc.) also falls back to the defaults so a typo cannot silently disable the check. Requests with a `Host` header outside the allowlist are rejected with `403`. Pass `*` to disable `Host` validation — only safe when a trusted reverse proxy validates `Host`. K8s `httpGet` probes and external `/metrics` scrapes will need either an explicit hostname in this list, `*`, a `tcpSocket` probe, or a separate port (`--healthz-address` / `--metrics-address`).
- `--allowed-origins`: Comma-separated allowlist of `Origin` header values. Empty by default — any request that carries an `Origin` header is rejected (browsers always send one for cross-origin requests, and no browser should be calling this server directly). Set to an explicit list to permit browser-based clients, or `*` to disable the check.
- `--allow-grafana-url-override`: Enable `X-Grafana-URL` selection. Falls back to `GRAFANA_ALLOW_URL_OVERRIDE`; disabled by default. Without an allowlist, callers can select any HTTP(S) URL the server can reach.
- `--allowed-grafana-urls`: Optional comma-separated exact Grafana base URL allowlist for URL overrides. Falls back to `GRAFANA_ALLOWED_URLS`. Requires `--allow-grafana-url-override`; an explicit empty flag disables an inherited list.

**Caller Authentication (SSE / streamable-http only):**

Optionally require MCP clients to authenticate *to the server*. This is separate from the credentials the server uses to reach Grafana. Stdio is unaffected.

- `--server-auth-token`: Bearer token callers must send as `Authorization: Bearer `. Falls back to the `MCP_GRAFANA_SERVER_TOKEN` environment variable. When set, requests without a valid token are rejected with `401` before any tool runs. Prefer the env var so the secret isn't visible in the process arguments.

Caller authentication is enforced only when `--server-auth-token` is set. When it isn't and the server binds a non-loopback address, the server **starts but logs a security error** — emitted at the `error` log level so it isn't hidden by `--log-level` (loopback and stdio are unaffected); a future major release will make that a startup error. Use TLS (or TLS termination) whenever caller auth is enabled on a non-loopback address. When caller auth is enabled, the validated `Authorization` header is stripped before requests reach Grafana; combining `--server-auth-token` with `GRAFANA_FORWARD_HEADERS=Authorization` is rejected at startup.

**Grafana URL overrides (streamable-http only):**

> [!WARNING]
> URL overrides let MCP callers select outbound HTTP(S) destinations. An allowlist limits URLs but does not authenticate callers or bind tokens to targets.
>
> Deploy behind an authenticating proxy that authorizes each target, replaces client-supplied URL and token headers, and supplies the matching token. Restrict the server's outbound network access to approved destinations.
>
> Without an allowlist, a fake request token can cause requests to any reachable HTTP(S) service, including internal and metadata services.

Set `GRAFANA_ALLOW_URL_OVERRIDE=true` (or `--allow-grafana-url-override`) to enable selection for a large fleet. To restrict destinations, also set `GRAFANA_ALLOWED_URLS=https://one.example.com,https://two.example.com/grafana` (or `--allowed-grafana-urls`).

Send these headers on each MCP request that selects a target:

```http
X-Grafana-URL: https://one.example.com
X-Grafana-Service-Account-Token:
```

If `--server-auth-token` is configured, also send `Authorization: Bearer `. This authenticates to the MCP server and is separate from `X-Grafana-Service-Account-Token`, which is for the selected Grafana instance. Your proxy can send a different Grafana token for each instance; the server never shares one configured token across them. The deprecated `X-Grafana-API-Key` header also works. A URL header without a request Grafana token is rejected. Use TLS for incoming requests because they carry tokens.

The allowlist matches exact base URLs, including scheme, port, and path; wildcards are not supported. Grafana authentication is not an SSRF defense.

For a selected URL, the server does not use `GRAFANA_SERVICE_ACCOUNT_TOKEN`, `GRAFANA_SERVICE_ACCOUNT_TOKEN_FILE`, `GRAFANA_API_KEY`, environment basic authentication, `GRAFANA_EXTRA_HEADERS`, or client certificates. TLS verification remains enabled even if `--tls-skip-verify` is set; a configured CA file still applies. Headers explicitly forwarded from that request still apply. Redirects and other Grafana API requests outside the selected base URL are blocked. Requests without `X-Grafana-URL` retain the usual `GRAFANA_URL` and environment credential behavior. This option applies to streamable HTTP only. It does not work over SSE, which does not pass per-request headers to tool calls; a selected URL there is used without the caller's token, so the calls fail.

**Debug and Logging:**
- `--debug`: Enable debug mode for detailed HTTP request/response logging
- `--log-level`: Log level (`debug`, `info`, `warn`, `error`) - default: `info`

**Grafana Client Options:**
- `--grafana-timeout`: Time limit for requests made by the Grafana client. Accepts Go duration strings (e.g., `10s`, `500ms`) - default: `10s`
- `--allow-cross-origin-redirects`: Allow outbound Grafana clients to follow redirects to a different scheme, host, or port. Defaults to false; `GRAFANA_ALLOW_CROSS_ORIGIN_REDIRECTS` is the environment fallback. Enabling this can send Grafana credentials to the redirect target. Request-selected Grafana URLs remain pinned to their selected target.
- `--include-args-in-spans`: Include tool call arguments in OpenTelemetry spans. Only enable in non-production environments or when arguments are known not to contain PII - default: `false`

**Observability:**
- `--metrics`: Enable Prometheus metrics endpoint at `/metrics`
- `--metrics-address`: Separate address for metrics server (e.g., `:9090`). If empty, metrics are served on the main server
- `--healthz-address`: Separate address for `/healthz` (e.g., `:8080`). If empty, `/healthz` is served on the main server. Shares a listener with `--metrics-address` when the two addresses match. Side listeners skip Host/Origin validation.
- `--slow-request-threshold`: Log an event when any MCP request (tool invocation, list, resource read, etc.) takes longer than this duration. Accepts Go duration strings (e.g., `500ms`, `5s`). Default `0` disables slow-request logging. See the [Slow-request logging](#slow-request-logging) section.
- `--slow-request-log-level`: Log level for slow-request events (`info` or `warn`) - default: `warn`.

**Anonymous Usage Statistics:**
- `--usage-stats`: Anonymous usage statistics reporting: `enabled`, `disabled`, or `log` (print the report that would be sent to stderr and send nothing). Overrides the `GRAFANA_USAGE_STATS` env var, which in turn overrides `DO_NOT_TRACK`; any unrecognised value disables reporting. See the [Anonymous usage statistics](#anonymous-usage-statistics) section.

**Tool Configuration:**
- `--enabled-tools`: Comma-separated list of enabled categories - default: all categories except `admin`, `agento11y`, `assistant`, `athena`, `clickhouse`, `cloudlogging`, `cloudwatch`, `elasticsearch`, `examples`, `graphite`, `quickwit`, `runpanelquery`, and `snowflake`. To enable disabled categories, add them to the list (e.g., `"search,datasource,...,snowflake"`)
- `--max-loki-log-limit`: Maximum number of log lines returned per `query_loki_logs` call - default: `100`. Note: Set this at least 1 below Loki's server-side `max_entries_limit_per_query` to allow truncation detection (the tool requests `limit+1` internally to detect if more data exists).
- `--loki-guardrail-mode`: Loki query cost guardrail for `query_loki_logs` - default: `off`. Loki does not enforce `max_query_bytes_read` on log queries without a line filter, so a broad selector over a wide range can scan terabytes; the guardrail requires a selective stream selector, caps the effective time range (including range-vector durations like `[30d]`), and pre-checks Loki's index/stats byte estimate before running the query. `shadow` logs queries that would be blocked but lets them run (it still pays the index/stats round trip); `enforce` rejects them with rewrite guidance the LLM can act on. On VictoriaLogs the guardrail applies only to selector-shaped (`{...}`) queries — when no selector parses (the normal brace-less LogsQL shape), the query passes through entirely, and the byte-budget check never applies (no cheap index estimate). Env fallback: `GRAFANA_LOKI_GUARDRAIL_MODE`.
- `--loki-guardrail-max-bytes`: Maximum bytes a single `query_loki_logs` call may scan, estimated via Loki's index/stats API - default: `107374182400` (100 GiB). `0` disables the byte-budget check. Env fallback: `GRAFANA_LOKI_GUARDRAIL_MAX_BYTES`.
- `--loki-guardrail-max-range`: Maximum effective time range for a single `query_loki_logs` call, including range-vector durations - default: `24h`. Accepts Go duration strings. `0` disables the range check. Env fallback: `GRAFANA_LOKI_GUARDRAIL_MAX_RANGE`.
- `--loki-enforced-matchers`: LogQL label matchers AND-ed into every native-Loki query to restrict which log streams can be read (e.g. `environment=~"prod|staging"`). Requires `--disable-api`. See [Loki query enforcement](#loki-query-enforcement).
- `--loki-label-enumeration-fallback`: What the label-enumeration tools do when negative enforced matchers can't scope them: `reject` (default) or `unfiltered`. See [Loki query enforcement](#loki-query-enforcement).
- `--disable-search`: Disable search tools
- `--disable-datasource`: Disable datasource tools
- `--disable-incident`: Disable incident tools
- `--disable-prometheus`: Disable prometheus tools
- `--disable-write`: Disable write tools (create/update operations)
- `--disable-query`: Disable query tools (tools that execute a query against a datasource); metadata and discovery tools stay available
- `--enable-query`: Keep the raw-SQL query tools (`query_sql`, `query_influxdb`) registered even under `--disable-write`. Equivalent to `--enable-write-tools=query_sql,query_influxdb`; kept as a shorthand for that common case.
- `--enable-write-tools`: Comma separated list of individual tool names to keep registered even under `--disable-write`, for tools whose write behavior is scoped enough to opt back in independently. Has no effect on a tool whose whole category is disabled.
- `--disable-loki`: Disable loki tools
- `--disable-elasticsearch`: Disable elasticsearch and opensearch tools
- `--disable-quickwit`: Disable quickwit tools
- `--disable-influxdb`: Disable InfluxDB tools
- `--disable-alerting`: Disable alerting tools
- `--disable-dashboard`: Disable dashboard tools
- `--disable-oncall`: Disable oncall tools
- `--disable-asserts`: Disable asserts tools
- `--disable-admin`: Disable admin tools
- `--disable-pyroscope`: Disable pyroscope tools
- `--disable-navigation`: Disable navigation tools
- `--disable-rendering`: Disable rendering tools (panel/dashboard image export)
- `--disable-snapshot`: Disable snapshot tools
- `--disable-cloudwatch`: Disable CloudWatch tools
- `--disable-cloudlogging`: Disable Google Cloud Logging tools
- `--disable-examples`: Disable query examples tools
- `--disable-sql`: Disable SQL datasource tools (ClickHouse, Snowflake, Athena, MySQL, PostgreSQL, MSSQL). Aliases `--disable-clickhouse`, `--disable-snowflake`, `--disable-athena` also work.
- `--disable-runpanelquery`: Disable run panel query tools
- `--disable-graphite`: Disable Graphite tools
- `--disable-provisioning`: Disable provisioning tools
- `--disable-agento11y`: Disable Agent Observability tools
- `--disable-assistant`: Disable Grafana Assistant tools
- `--disable-docs`: Disable documentation tools

### Read-Only Mode

The `--disable-write` flag provides a way to run the MCP server in read-only mode, preventing any write operations to your Grafana instance. This is useful for scenarios where you want to provide safe, read-only access such as:

- Using service accounts with limited read-only permissions
- Providing AI assistants with observability data without modification capabilities
- Running in production environments where write access should be restricted
- Testing and development scenarios where you want to prevent accidental modifications

When `--disable-write` is enabled, the following write operations are disabled:

**Dashboard Tools:**
- `update_dashboard`

**Folder Tools:**
- `create_folder`

**Incident Tools:**
- `create_incident`
- `add_activity_to_incident`
- `update_incident`

**Alerting Tools:**
- `alerting_rules_write` (create, update, delete operations)
- `alerting_silences_write` (create, update, delete operations)
- `alerting_routing_write` (create_contact_point operation)

**OnCall Tools:**
- `update_alert_group`

**Annotation Tools:**
- `create_annotation`
- `update_annotation`
- `delete_annotation`

**Snapshot Tools:**
- `create_snapshot`
- `delete_snapshot`

**Raw-SQL Query Tools:**

These execute whatever query you give them without inspecting it, so they can write when the datasource credentials permit it — `query_sql` will run a `DROP TABLE`, `query_influxdb` will run a `DELETE`. Read-only mode therefore removes them. Pass `--enable-query` to keep them when the datasource credentials are known to be read-only.

- `query_sql`
- `query_influxdb`

**Agent Observability Tools:**
- `agento11y_manage_evaluators` (upsert, delete, fork, test evaluator operations)
- `agento11y_manage_eval_rules` (create, update, delete, preview rule and guard operations)
- `agento11y_manage_eval_collections` (save and delete saved conversations; create, update, delete collections; add and remove collection members)
- `agento11y_manage_experiments` (update and cancel experiment operations)
- `agento11y_manage_test_suites` (create and update test suites; create and publish versions; upsert and delete test cases)

All read operations remain available, allowing you to query dashboards, run PromQL/LogQL queries, list resources, and retrieve data. The query languages that cannot express a write — PromQL, LogQL, TraceQL, the Elasticsearch DSL, Graphite, CloudWatch — keep their query tools in read-only mode; only the raw-SQL ones listed above are removed.

### Query-Free Mode

The `--disable-query` flag removes every tool that executes a query against a datasource, while leaving the metadata and discovery tools in place. This is useful when you want an assistant that can explore what exists — datasources, dashboards, metric names, labels, table schemas — without running potentially expensive or data-revealing queries, for example when the service account has `datasources:read` but not `datasources:query`.

It is the strongest of the three query settings, and it wins over `--enable-query`:

| Flags | Safe query tools (`query_prometheus`, `query_loki_logs`, `run_panel_query`, …) | Raw-SQL query tools (`query_sql`, `query_influxdb`) |
| --- | --- | --- |
| _(none)_ | registered | registered |
| `--disable-write` | registered | **not registered** |
| `--disable-write --enable-query` | registered | registered |
| `--disable-query` | not registered | not registered |
| `--disable-query --enable-query` | not registered | not registered |

When `--disable-query` is enabled, the following tools are not registered:

**Prometheus Tools:**
- `query_prometheus`
- `query_prometheus_histogram`

**Loki Tools:**
- `query_loki_logs`
- `query_loki_patterns`

`query_loki_stats` and `analyze_loki_labels` stay registered: both send a selector to the datasource, but they read the index and return stream, chunk, and byte counts rather tha