[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-73252":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":15,"forks30d":15,"starsTrendScore":19,"compositeScore":20,"rankGlobal":9,"rankLanguage":9,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":22,"topics":25,"createdAt":9,"pushedAt":9,"updatedAt":26,"readmeContent":27,"aiSummary":28,"trendingCount":15,"starSnapshotCount":15,"syncStatus":29,"lastSyncTime":30,"discoverSource":31},73252,"mcp-grafana","grafana\u002Fmcp-grafana","grafana","MCP server for Grafana",null,"Go",3129,378,115,58,0,20,51,139,60,29.74,"Apache License 2.0",false,"main",true,[],"2026-06-12 02:03:10","# Grafana MCP server\n\n[![Unit Tests](https:\u002F\u002Fgithub.com\u002Fgrafana\u002Fmcp-grafana\u002Factions\u002Fworkflows\u002Funit.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fgrafana\u002Fmcp-grafana\u002Factions\u002Fworkflows\u002Funit.yml)\n[![Integration Tests](https:\u002F\u002Fgithub.com\u002Fgrafana\u002Fmcp-grafana\u002Factions\u002Fworkflows\u002Fintegration.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fgrafana\u002Fmcp-grafana\u002Factions\u002Fworkflows\u002Fintegration.yml)\n[![E2E Tests](https:\u002F\u002Fgithub.com\u002Fgrafana\u002Fmcp-grafana\u002Factions\u002Fworkflows\u002Fe2e.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Fgrafana\u002Fmcp-grafana\u002Factions\u002Fworkflows\u002Fe2e.yml)\n[![Go Reference](https:\u002F\u002Fpkg.go.dev\u002Fbadge\u002Fgithub.com\u002Fgrafana\u002Fmcp-grafana.svg)](https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fgrafana\u002Fmcp-grafana)\n[![MCP Catalog](https:\u002F\u002Farchestra.ai\u002Fmcp-catalog\u002Fapi\u002Fbadge\u002Fquality\u002Fgrafana\u002Fmcp-grafana)](https:\u002F\u002Farchestra.ai\u002Fmcp-catalog\u002Fgrafana__mcp-grafana)\n\nA [Model Context Protocol][mcp] (MCP) server for Grafana.\n\nThis provides access to your Grafana instance and the surrounding ecosystem.\n\n## Quick Start\n\nRequires [uv](https:\u002F\u002Fdocs.astral.sh\u002Fuv\u002Fgetting-started\u002Finstallation\u002F). Add the following to your MCP client configuration (e.g. Claude Desktop, Cursor):\n\n```json\n{\n  \"mcpServers\": {\n    \"grafana\": {\n      \"command\": \"uvx\",\n      \"args\": [\"mcp-grafana\"],\n      \"env\": {\n        \"GRAFANA_URL\": \"http:\u002F\u002Flocalhost:3000\",\n        \"GRAFANA_SERVICE_ACCOUNT_TOKEN\": \"\u003Cyour service account token>\"\n      }\n    }\n  }\n}\n```\n\nFor Grafana Cloud, replace `GRAFANA_URL` with your instance URL (e.g. `https:\u002F\u002Fmyinstance.grafana.net`). See [Usage](#usage) for more installation options including Docker, binary, and Helm.\n\n## Requirements\n\n- **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.\n\n## Features\n\n_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._\n\n### Dashboards\n\n- **Search for dashboards:** Find dashboards by title or other metadata\n- **Get dashboard by UID:** Retrieve full dashboard details using its unique identifier. _Warning: Large dashboards can consume significant context window space._\n- **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\n- **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\n- **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._\n- **Patch dashboard:** Apply specific changes to a dashboard without requiring the full JSON, significantly reducing context window usage for targeted modifications\n- **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\n\n### Run Panel Query\n\n> **Note:** Run panel query tools are **disabled by default**. To enable them, add `runpanelquery` to your `--enabled-tools` flag.\n\n- **Run panel query:** Execute a dashboard panel's query with custom time ranges and variable overrides.\n\n#### Context Window Management\n\nThe dashboard tools now include several strategies to manage context window usage effectively ([issue #101](https:\u002F\u002Fgithub.com\u002Fgrafana\u002Fmcp-grafana\u002Fissues\u002F101)):\n\n- **Use `get_dashboard_summary`** for dashboard overview and planning modifications\n- **Use `get_dashboard_property`** with JSONPath when you only need specific dashboard parts\n- **Avoid `get_dashboard_by_uid`** unless you specifically need the complete dashboard JSON\n\n### Datasources\n\n- **List and fetch datasource information:** View all configured datasources and retrieve detailed information about each.\n  - _Supported datasource types: Prometheus, Loki, ClickHouse, CloudWatch, Elasticsearch, OpenSearch, Snowflake, Athena._\n\n### Query Examples\n\n> **Note:** Query examples tools are **disabled by default**. To enable them, add `examples` to your `--enabled-tools` flag.\n\n- **Get query examples:** Retrieve example queries for different datasource types to learn query syntax.\n\n### Prometheus Querying\n\n- **Query Prometheus:** Execute PromQL queries (supports both instant and range metric queries) against Prometheus datasources.\n- **Query Prometheus metadata:** Retrieve metric metadata, metric names, label names, and label values from Prometheus datasources.\n- **Query histogram percentiles:** Calculate histogram percentile values (p50, p90, p95, p99) using histogram_quantile.\n\n### Loki Querying\n\n- **Query Loki logs and metrics:** Run both log queries and metric queries using LogQL against Loki datasources.\n- **Query Loki metadata:** Retrieve label names, label values, and stream statistics from Loki datasources.\n- **Query Loki patterns:** Retrieve log patterns detected by Loki to identify common log structures and anomalies.\n\n### InfluxDB Querying\n\n> **Note:** InfluxDB tools are **disabled by default**. To enable them, add `influxdb` to your `--enabled-tools` flag.\n\n- **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.\n\n### ClickHouse Querying\n\n> **Note:** ClickHouse tools are **disabled by default**. To enable them, add `clickhouse` to your `--enabled-tools` flag.\n\n- **List ClickHouse tables:** List all tables in a ClickHouse database with row counts and sizes.\n- **Describe table schema:** Get column names, types, and metadata for a ClickHouse table.\n- **Query ClickHouse:** Execute SQL queries with Grafana macro and variable substitution support.\n\n### CloudWatch Querying\n\n> **Note:** CloudWatch tools are **disabled by default**. To enable them, add `cloudwatch` to your `--enabled-tools` flag.\n\n- **List CloudWatch namespaces:** Discover available AWS CloudWatch namespaces.\n- **List CloudWatch metrics:** List metrics available in a specific namespace.\n- **List CloudWatch dimensions:** Get dimensions for filtering metric queries.\n- **Query CloudWatch:** Execute CloudWatch metric queries with time range support.\n\n### Graphite Querying\n\n> **Note:** Graphite tools are **disabled by default**. To enable them, add `graphite` to your `--enabled-tools` flag.\n\n- **Query Graphite:** Execute Graphite render API queries against a Graphite datasource.\n- **List Graphite metrics:** Browse and discover Graphite metric paths.\n- **List Graphite tags:** List available Graphite tags and tag values.\n- **Query Graphite density:** Query Graphite metric density for a given pattern.\n\n### Athena Querying\n\n> **Note:** Athena tools are **disabled by default**. To enable them, add `athena` to your `--enabled-tools` flag.\n\n- **List Athena catalogs:** Discover available data catalogs (e.g. AwsDataCatalog, Iceberg connectors).\n- **List Athena databases:** List databases in an Athena catalog.\n- **List Athena tables:** List tables in an Athena database.\n- **Describe Athena table:** Get column names for an Athena table.\n- **Query Athena:** Execute SQL queries against Amazon Athena via Grafana with macro substitution, limit enforcement, and template variable support.\n\n### Snowflake Querying\n\n> **Note:** Snowflake tools are **disabled by default**. To enable them, add `snowflake` to your `--enabled-tools` flag.\n\nQueries go through Grafana's Snowflake datasource (Grafana Enterprise plugin `grafana-snowflake-datasource`), so authentication is handled by the datasource configuration in Grafana — credentials are never seen by the MCP server. This is the same model used for the ClickHouse tools.\n\n- **List Snowflake tables:** Discover tables (with database, schema, kind, row count, and size) via `INFORMATION_SCHEMA.TABLES`. Optional database\u002Fschema filters.\n- **Describe table schema:** Get column names, data types, nullability, defaults, and comments for a Snowflake table.\n- **Query Snowflake:** Execute SQL queries with macro and variable substitution support. Useful for querying Snowflake's event tables (e.g. `SNOWFLAKE.TELEMETRY.EVENTS`) for logs and traces, or any user table.\n  - Supported macros: `$__timeFilter(column)`, `$__timeFrom`, `$__timeTo`, `$__from`, `$__to` (Unix ms), `$__interval` (seconds), `$__interval_ms`, and `${varname}` for template variable substitution.\n\n### Elasticsearch\u002FOpenSearch Querying\n\n> **Note:** Elasticsearch\u002FOpenSearch tools are **disabled by default**. To enable them, add `elasticsearch` to your `--enabled-tools` flag.\n\n- **Query Elasticsearch\u002FOpenSearch:** 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.\n\n### Incidents\n\n- **Search, create, and update incidents:** Manage incidents in Grafana Incident, including searching, creating, and adding activities to incidents.\n\n### Sift Investigations\n\n- **List Sift investigations:** Retrieve a list of Sift investigations, with support for a limit parameter.\n- **Get Sift investigation:** Retrieve details of a specific Sift investigation by its UUID.\n- **Get Sift analyses:** Retrieve a specific analysis from a Sift investigation.\n- **Find error patterns in logs:** Detect elevated error patterns in Loki logs using Sift.\n- **Find slow requests:** Detect slow requests using Sift (Tempo).\n\n### Alerting\n\n- **List and fetch alert rule information:** View alert rules and their statuses (firing\u002Fnormal\u002Ferror\u002Fetc.) in Grafana. Supports both Grafana-managed rules and datasource-managed rules from Prometheus or Loki datasources.\n- **Create and update alert rules:** Create new alert rules or modify existing ones.\n- **Delete alert rules:** Remove alert rules by UID.\n- **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).\n\n### Grafana OnCall\n\n- **List and manage schedules:** View and manage on-call schedules in Grafana OnCall.\n- **Get shift details:** Retrieve detailed information about specific on-call shifts.\n- **Get current on-call users:** See which users are currently on call for a schedule.\n- **List teams and users:** View all OnCall teams and users.\n- **List alert groups:** View and filter alert groups from Grafana OnCall by various criteria including state, integration, labels, and time range.\n- **Get alert group details:** Retrieve detailed information about a specific alert group by its ID.\n\n### Admin\n\n> **Note:** Admin tools are **disabled by default**. To enable them, include `admin` in your `--enabled-tools` flag.\n- **List teams:** View all configured teams in Grafana.\n- **List Users:** View all users in an organization in Grafana.\n- **List all roles:** List all Grafana roles, with an optional filter for delegatable roles.\n- **Get role details:** Get details for a specific Grafana role by UID.\n- **List assignments for a role:** List all users, teams, and service accounts assigned to a role.\n- **List roles for users:** List all roles assigned to one or more users.\n- **List roles for teams:** List all roles assigned to one or more teams.\n- **List permissions for a resource:** List all permissions defined for a specific resource (dashboard, datasource, folder, etc.).\n- **Describe a Grafana resource:** List available permissions and assignment capabilities for a resource type.\n\n### Navigation\n\n- **Generate deeplinks:** Create accurate deeplink URLs for Grafana resources instead of relying on LLM URL guessing.\n  - **Dashboard links:** Generate direct links to dashboards using their UID (e.g., `http:\u002F\u002Flocalhost:3000\u002Fd\u002Fdashboard-uid`)\n  - **Panel links:** Create links to specific panels within dashboards with viewPanel parameter (e.g., `http:\u002F\u002Flocalhost:3000\u002Fd\u002Fdashboard-uid?viewPanel=5`)\n  - **Explore links:** Generate links to Grafana Explore with pre-configured datasources (e.g., `http:\u002F\u002Flocalhost:3000\u002Fexplore?left={\"datasource\":\"prometheus-uid\"}`)\n  - **Time range support:** Add time range parameters to links (`from=now-1h&to=now`)\n  - **Custom parameters:** Include additional query parameters like dashboard variables or refresh intervals\n\n### Annotations\n\n- **Get Annotations:** Query annotations with filters. Supports time range, dashboard UID, tags, and match mode.\n- **Create Annotation:** Create a new annotation on a dashboard or panel.\n- **Create Graphite Annotation:** Create annotations using Graphite format (`what`, `when`, `tags`, `data`).\n- **Update Annotation:** Replace all fields of an existing annotation (full update).\n- **Patch Annotation:** Update only specific fields of an annotation (partial update).\n- **Get Annotation Tags:** List available annotation tags with optional filtering.\n\n### Rendering\n\n- **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.\n  - _Note: Requires the [Grafana Image Renderer](https:\u002F\u002Fgrafana.com\u002Fdocs\u002Fgrafana\u002Flatest\u002Fsetup-grafana\u002Fimage-rendering\u002F) service to be installed and configured._\n\nThe list of tools is configurable, so you can choose which tools you want to make available to the MCP client.\nThis is useful if you don't use certain functionality or if you don't want to take up too much of the context window.\nTo disable a category of tools, use the `--disable-\u003Ccategory>` flag when starting the server. For example, to disable\nthe OnCall tools, use `--disable-oncall`, or to disable navigation deeplink generation, use `--disable-navigation`.\n\n\n#### RBAC Permissions\n\nEach 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.\n\nTip: 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\u002Fwrite 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.\n\n**Note:** Grafana Incident and Sift tools use basic Grafana roles instead of fine-grained RBAC permissions:\n- **Viewer role:** Required for read-only operations (list incidents, get investigations)\n- **Editor role:** Required for write operations (create incidents, modify investigations)\n\nFor more information about Grafana RBAC, see the [official documentation](https:\u002F\u002Fgrafana.com\u002Fdocs\u002Fgrafana\u002Flatest\u002Fadministration\u002Froles-and-permissions\u002Faccess-control\u002F).\n\n#### RBAC Scopes\n\nScopes define the specific resources that permissions apply to. Each action requires both the appropriate permission and scope combination.\n\n**Common Scope Patterns:**\n\n- **Broad access:** Use `*` wildcards for organization-wide access\n\n  - `datasources:*` - Access to all datasources\n  - `dashboards:*` - Access to all dashboards\n  - `folders:*` - Access to all folders\n  - `teams:*` - Access to all teams\n\n- **Limited access:** Use specific UIDs or IDs to restrict access to individual resources\n  - `datasources:uid:prometheus-uid` - Access only to a specific Prometheus datasource\n  - `dashboards:uid:abc123` - Access only to dashboard with UID `abc123`\n  - `folders:uid:xyz789` - Access only to folder with UID `xyz789`\n  - `teams:id:5` - Access only to team with ID `5`\n  - `global.users:id:123` - Access only to user with ID `123`\n\n**Examples:**\n\n- **Full MCP server access:** Grant broad permissions for all tools\n\n  ```\n  datasources:* (datasources:read, datasources:query)\n  dashboards:* (dashboards:read, dashboards:create, dashboards:write)\n  folders:* (for dashboard creation and alert rules)\n  teams:* (teams:read)\n  global.users:* (users:read)\n  ```\n\n- **Limited datasource access:** Only query specific Prometheus and Loki instances\n\n  ```\n  datasources:uid:prometheus-prod (datasources:query)\n  datasources:uid:loki-prod (datasources:query)\n  ```\n\n- **Dashboard-specific access:** Read only specific dashboards\n  ```\n  dashboards:uid:monitoring-dashboard (dashboards:read)\n  dashboards:uid:alerts-dashboard (dashboards:read)\n  ```\n\n### Tools\n\n| Tool                              | Category    | Description                                                         | Required RBAC Permissions               | Required Scopes                                     |\n| --------------------------------- | ----------- | ------------------------------------------------------------------- | --------------------------------------- | --------------------------------------------------- |\n| `list_teams`                      | Admin       | List all teams                                                      | `teams:read`                            | `teams:*` or `teams:id:1`                           |\n| `list_users_by_org`               | Admin       | List all users in an organization                                   | `users:read`                            | `global.users:*` or `global.users:id:123`           |\n| `list_all_roles`          | Admin    | List all Grafana roles                              | `roles:read`              | `roles:*`                         |\n| `get_role_details`        | Admin    | Get details for a Grafana role                      | `roles:read`              | `roles:uid:editor`                |\n| `get_role_assignments`    | Admin    | List assignments for a role                         | `roles:read`              | `roles:uid:editor`                |\n| `list_user_roles`         | Admin    | List roles for users                                | `roles:read`              | `global.users:id:123`             |\n| `list_team_roles`         | Admin    | List roles for teams                                | `roles:read`              | `teams:id:7`                      |\n| `get_resource_permissions`| Admin    | List permissions for a resource                     | `permissions:read`        | `dashboards:uid:abcd1234`         |\n| `get_resource_description`| Admin    | Describe a Grafana resource type                    | `permissions:read`        | `dashboards:*`                    |\n| `search_dashboards`               | Search      | Search for dashboards                                               | `dashboards:read`                       | `dashboards:*` or `dashboards:uid:abc123`           |\n| `get_dashboard_by_uid`            | Dashboard   | Get a dashboard by uid                                              | `dashboards:read`                       | `dashboards:uid:abc123`                             |\n| `update_dashboard`                | Dashboard   | Update or create a new dashboard                                    | `dashboards:create`, `dashboards:write` | `dashboards:*`, `folders:*` or `folders:uid:xyz789` |\n| `get_dashboard_panel_queries`     | Dashboard   | Get panel title, queries, datasource UID and type from a dashboard  | `dashboards:read`                       | `dashboards:uid:abc123`                             |\n| `run_panel_query`                 | RunPanelQuery* | Execute one or more dashboard panel queries                       | `dashboards:read`, `datasources:query`  | `dashboards:uid:*`, `datasources:uid:*`             |\n| `get_dashboard_property`          | Dashboard   | Extract specific parts of a dashboard using JSONPath expressions    | `dashboards:read`                       | `dashboards:uid:abc123`                             |\n| `get_dashboard_summary`           | Dashboard   | Get a compact summary of a dashboard without full JSON              | `dashboards:read`                       | `dashboards:uid:abc123`                             |\n| `list_datasources`                | Datasources | List datasources                                                    | `datasources:read`                      | `datasources:*`                                     |\n| `get_datasource`                  | Datasources | Get a datasource by UID or name                                     | `datasources:read`                      | `datasources:uid:prometheus-uid`                    |\n| `get_query_examples`              | Examples*   | Get example queries for a datasource type                           | `datasources:read`                      | `datasources:*`                                     |\n| `query_prometheus`                | Prometheus  | Execute a query against a Prometheus datasource                     | `datasources:query`                     | `datasources:uid:prometheus-uid`                    |\n| `list_prometheus_metric_metadata` | Prometheus  | List metric metadata                                                | `datasources:query`                     | `datasources:uid:prometheus-uid`                    |\n| `list_prometheus_metric_names`    | Prometheus  | List available metric names                                         | `datasources:query`                     | `datasources:uid:prometheus-uid`                    |\n| `list_prometheus_label_names`     | Prometheus  | List label names matching a selector                                | `datasources:query`                     | `datasources:uid:prometheus-uid`                    |\n| `list_prometheus_label_values`    | Prometheus  | List values for a specific label                                    | `datasources:query`                     | `datasources:uid:prometheus-uid`                    |\n| `query_prometheus_histogram`      | Prometheus  | Calculate histogram percentile values                               | `datasources:query`                     | `datasources:uid:prometheus-uid`                    |\n| `list_incidents`                  | Incident    | List incidents in Grafana Incident                                  | Viewer role                             | N\u002FA                                                 |\n| `create_incident`                 | Incident    | Create an incident in Grafana Incident                              | Editor role                             | N\u002FA                                                 |\n| `add_activity_to_incident`        | Incident    | Add an activity item to an incident in Grafana Incident             | Editor role                             | N\u002FA                                                 |\n| `get_incident`                    | Incident    | Get a single incident by ID                                         | Viewer role                             | N\u002FA                                                 |\n| `query_loki_logs`                 | Loki        | Query and retrieve logs using LogQL (either log or metric queries)  | `datasources:query`                     | `datasources:uid:loki-uid`                          |\n| `list_loki_label_names`           | Loki        | List all available label names in logs                              | `datasources:query`                     | `datasources:uid:loki-uid`                          |\n| `list_loki_label_values`          | Loki        | List values for a specific log label                                | `datasources:query`                     | `datasources:uid:loki-uid`                          |\n| `query_loki_stats`                | Loki        | Get statistics about log streams                                    | `datasources:query`                     | `datasources:uid:loki-uid`                          |\n| `query_loki_patterns`             | Loki        | Query detected log patterns to identify common structures           | `datasources:query`                     | `datasources:uid:loki-uid`                          |\n| `query_influxdb`                  | InfluxDB    | Query InfluxDB using InfluxQL (v1) or Flux (v2)                     | `datasources:query`                     | `datasources:uid:influxdb-uid`                      |\n| `list_clickhouse_tables`          | ClickHouse* | List tables in a ClickHouse database                                | `datasources:query`                     | `datasources:uid:*`                                 |\n| `describe_clickhouse_table`       | ClickHouse* | Get table schema with column types                                  | `datasources:query`                     | `datasources:uid:*`                                 |\n| `query_clickhouse`                | ClickHouse* | Execute SQL queries with macro substitution                         | `datasources:query`                     | `datasources:uid:*`                                 |\n| `list_cloudwatch_namespaces`      | CloudWatch* | List available AWS CloudWatch namespaces                            | `datasources:query`                     | `datasources:uid:*`                                 |\n| `list_cloudwatch_metrics`         | CloudWatch* | List metrics in a namespace                                         | `datasources:query`                     | `datasources:uid:*`                                 |\n| `list_cloudwatch_dimensions`      | CloudWatch* | List dimensions for a metric                                        | `datasources:query`                     | `datasources:uid:*`                                 |\n| `query_cloudwatch`                | CloudWatch* | Execute CloudWatch metric queries                                   | `datasources:query`                     | `datasources:uid:*`                                 |\n| `list_athena_catalogs`            | Athena*     | List available Athena data catalogs                                 | `datasources:query`                     | `datasources:uid:*`                                 |\n| `list_athena_databases`           | Athena*     | List databases in an Athena catalog                                 | `datasources:query`                     | `datasources:uid:*`                                 |\n| `list_athena_tables`              | Athena*     | List tables in an Athena database                                   | `datasources:query`                     | `datasources:uid:*`                                 |\n| `describe_athena_table`           | Athena*     | Get column names for an Athena table                                | `datasources:query`                     | `datasources:uid:*`                                 |\n| `query_athena`                    | Athena*     | Execute SQL queries with macro substitution                         | `datasources:query`                     | `datasources:uid:*`                                 |\n| `query_elasticsearch`             | Elasticsearch\u002FOpenSearch* | Query Elasticsearch or OpenSearch using Lucene syntax or Query DSL | `datasources:query`                     | `datasources:uid:datasource-uid`                    |\n| `list_snowflake_tables`           | Snowflake*  | List tables in a Snowflake database\u002Fschema via INFORMATION_SCHEMA   | `datasources:query`                     | `datasources:uid:*`                                 |\n| `describe_snowflake_table`        | Snowflake*  | Get table schema (column types, nullability, defaults, comments)    | `datasources:query`                     | `datasources:uid:*`                                 |\n| `query_snowflake`                 | Snowflake*  | Execute SQL queries with macro\u002Fvariable substitution                | `datasources:query`                     | `datasources:uid:*`                                 |\n| `alerting_manage_rules`           | Alerting    | Manage alert rules (list, get, versions, create, update, delete)    | `alert.rules:read` + `alert.rules:write` for mutations | `folders:*` or `folders:uid:alerts-folder` |\n| `alerting_manage_routing`         | Alerting    | Manage notification policies, contact points, and time intervals    | `alert.notifications:read`              | Global scope                                        |\n| `list_oncall_schedules`           | OnCall      | List schedules from Grafana OnCall                                  | `grafana-oncall-app.schedules:read`     | Plugin-specific scopes                              |\n| `get_oncall_shift`                | OnCall      | Get details for a specific OnCall shift                             | `grafana-oncall-app.schedules:read`     | Plugin-specific scopes                              |\n| `get_current_oncall_users`        | OnCall      | Get users currently on-call for a specific schedule                 | `grafana-oncall-app.schedules:read`     | Plugin-specific scopes                              |\n| `list_oncall_teams`               | OnCall      | List teams from Grafana OnCall                                      | `grafana-oncall-app.user-settings:read` | Plugin-specific scopes                              |\n| `list_oncall_users`               | OnCall      | List users from Grafana OnCall                                      | `grafana-oncall-app.user-settings:read` | Plugin-specific scopes                              |\n| `list_alert_groups`               | OnCall      | List alert groups from Grafana OnCall with filtering options        | `grafana-oncall-app.alert-groups:read`  | Plugin-specific scopes                              |\n| `get_alert_group`                 | OnCall      | Get a specific alert group from Grafana OnCall by its ID            | `grafana-oncall-app.alert-groups:read`  | Plugin-specific scopes                              |\n| `get_sift_investigation`          | Sift        | Retrieve an existing Sift investigation by its UUID                 | Viewer role                             | N\u002FA                                                 |\n| `get_sift_analysis`               | Sift        | Retrieve a specific analysis from a Sift investigation              | Viewer role                             | N\u002FA                                                 |\n| `list_sift_investigations`        | Sift        | Retrieve a list of Sift investigations with an optional limit       | Viewer role                             | N\u002FA                                                 |\n| `find_error_pattern_logs`         | Sift        | Finds elevated error patterns in Loki logs.                         | Editor role                             | N\u002FA                                                 |\n| `find_slow_requests`              | Sift        | Finds slow requests from the relevant tempo datasources.            | Editor role                             | N\u002FA                                                 |\n| `list_pyroscope_label_names`      | Pyroscope   | List label names matching a selector                                | `datasources:query`                     | `datasources:uid:pyroscope-uid`                     |\n| `list_pyroscope_label_values`     | Pyroscope   | List label values matching a selector for a label name              | `datasources:query`                     | `datasources:uid:pyroscope-uid`                     |\n| `list_pyroscope_profile_types`    | Pyroscope   | List available profile types                                        | `datasources:query`                     | `datasources:uid:pyroscope-uid`                     |\n| `fetch_pyroscope_profile`         | Pyroscope   | Fetches a profile in DOT format for analysis                        | `datasources:query`                     | `datasources:uid:pyroscope-uid`                     |\n| `get_assertions`                  | Asserts     | Get assertion summary for a given entity                            | Plugin-specific permissions             | Plugin-specific scopes                              |\n| `generate_deeplink`               | Navigation  | Generate accurate deeplink URLs for Grafana resources               | None (read-only URL generation)         | N\u002FA                                                 |\n| `get_annotations`                 | Annotations | Fetch annotations with filters                                      | `annotations:read`                      | `annotations:*` or `annotations:id:123`             |\n| `create_annotation`               | Annotations | Create a new annotation (standard or Graphite format)               | `annotations:write`                     | `annotations:*`                                     |\n| `update_annotation`               | Annotations | Update specific fields of an annotation (partial update)            | `annotations:write`                     | `annotations:*`                                     |\n| `get_annotation_tags`             | Annotations | List annotation tags with optional filtering                        | `annotations:read`                      | `annotations:*`                                     |\n| `get_panel_image`                 | Rendering   | Render a dashboard panel or full dashboard as a PNG image           | `dashboards:read`                       | `dashboards:uid:abc123`                             |\n\n_* Disabled by default. Add category to `--enabled-tools` to enable._\n\n## CLI Flags Reference\n\nThe `mcp-grafana` binary supports various command-line flags for configuration:\n\n**Transport Options:**\n- `-t, --transport`: Transport type (`stdio`, `sse`, or `streamable-http`) - default: `stdio`\n- `--address`: The host and port for SSE\u002Fstreamable-http server - default: `localhost:8000`\n- `--base-path`: Base path for the SSE\u002Fstreamable-http server\n- `--endpoint-path`: Endpoint path for the streamable-http server - default: `\u002F`\n\n**Debug and Logging:**\n- `--debug`: Enable debug mode for detailed HTTP request\u002Fresponse logging\n- `--log-level`: Log level (`debug`, `info`, `warn`, `error`) - default: `info`\n\n**Observability:**\n- `--metrics`: Enable Prometheus metrics endpoint at `\u002Fmetrics`\n- `--metrics-address`: Separate address for metrics server (e.g., `:9090`). If empty, metrics are served on the main server\n- `--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.\n- `--slow-request-log-level`: Log level for slow-request events (`info` or `warn`) - default: `warn`.\n\n**Session Management:**\n- `--session-idle-timeout-minutes`: Session idle timeout in minutes. Sessions with no activity for this duration are automatically reaped - default: `30`. Set to `0` to disable session reaping. Only relevant for SSE and streamable-http transports.\n\n**Tool Configuration:**\n- `--enabled-tools`: Comma-separated list of enabled categories - default: all categories except `admin`, `athena`, `clickhouse`, `cloudwatch`, `elasticsearch`, `examples`, `graphite`, `runpanelquery`, and `snowflake`. To enable disabled categories, add them to the list (e.g., `\"search,datasource,...,snowflake\"`)\n- `--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).\n- `--disable-search`: Disable search tools\n- `--disable-datasource`: Disable datasource tools\n- `--disable-incident`: Disable incident tools\n- `--disable-prometheus`: Disable prometheus tools\n- `--disable-write`: Disable write tools (create\u002Fupdate operations)\n- `--disable-loki`: Disable loki tools\n- `--disable-elasticsearch`: Disable elasticsearch and opensearch tools\n- `--disable-influxdb`: Disable InfluxDB tools\n- `--disable-alerting`: Disable alerting tools\n- `--disable-dashboard`: Disable dashboard tools\n- `--disable-oncall`: Disable oncall tools\n- `--disable-asserts`: Disable asserts tools\n- `--disable-sift`: Disable sift tools\n- `--disable-admin`: Disable admin tools\n- `--disable-pyroscope`: Disable pyroscope tools\n- `--disable-navigation`: Disable navigation tools\n- `--disable-rendering`: Disable rendering tools (panel\u002Fdashboard image export)\n- `--disable-cloudwatch`: Disable CloudWatch tools\n- `--disable-examples`: Disable query examples tools\n- `--disable-clickhouse`: Disable ClickHouse tools\n- `--disable-snowflake`: Disable Snowflake tools\n- `--disable-runpanelquery`: Disable run panel query tools\n- `--disable-graphite`: Disable Graphite tools\n- `--disable-athena`: Disable Athena tools\n\n### Read-Only Mode\n\nThe `--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:\n\n- Using service accounts with limited read-only permissions\n- Providing AI assistants with observability data without modification capabilities\n- Running in production environments where write access should be restricted\n- Testing and development scenarios where you want to prevent accidental modifications\n\nWhen `--disable-write` is enabled, the following write operations are disabled:\n\n**Dashboard Tools:**\n- `update_dashboard`\n\n**Folder Tools:**\n- `create_folder`\n\n**Incident Tools:**\n- `create_incident`\n- `add_activity_to_incident`\n\n**Alerting Tools:**\n- `alerting_manage_rules` (create, update, delete operations)\n\n**Annotation Tools:**\n- `create_annotation`\n- `update_annotation`\n\n**Sift Tools:**\n- `find_error_pattern_logs` (creates investigations)\n- `find_slow_requests` (creates investigations)\n\nAll read operations remain available, allowing you to query dashboards, run PromQL\u002FLogQL queries, list resources, and retrieve data.\n\n**Client TLS Configuration (for Grafana connections):**\n- `--tls-cert-file`: Path to TLS certificate file for client authentication\n- `--tls-key-file`: Path to TLS private key file for client authentication\n- `--tls-ca-file`: Path to TLS CA certificate file for server verification\n- `--tls-skip-verify`: Skip TLS certificate verification (insecure)\n\n**Server TLS Configuration (streamable-http transport only):**\n- `--server.tls-cert-file`: Path to TLS certificate file for server HTTPS\n- `--server.tls-key-file`: Path to TLS private key file for server HTTPS\n\n## Usage\n\nThis MCP server works with both local Grafana instances and Grafana Cloud. For Grafana Cloud, use your instance URL (e.g., `https:\u002F\u002Fmyinstance.grafana.net`) instead of `http:\u002F\u002Flocalhost:3000` in the configuration examples below.\n\n1. If using service account token authentication, create a service account in Grafana with enough permissions to use the tools you want to use,\n   generate a service account token, and copy it to the clipboard for use in the configuration file.\n   Follow the [Grafana service account documentation][service-account] for details on creating service account tokens.\n   Tip: If you're not comfortable configuring fine-grained RBAC scopes, a simpler (but less restrictive) option is to assign the built-in `Editor` role to the service account. This grants broad read\u002Fwrite access that covers most MCP server operations — use it when convenience outweighs strict least-privilege requirements.\n\n   > **Note:** The environment variable `GRAFANA_API_KEY` is deprecated and will be removed in a future version. Please migrate to using `GRAFANA_SERVICE_ACCOUNT_TOKEN` instead. The old variable name will continue to work for backward compatibility but will show deprecation warnings.\n\n### Multi-Organization Support\n \nYou can specify which organization to interact with using either:\n\n- **Environment variable:** Set `GRAFANA_ORG_ID` to the numeric organization ID\n- **HTTP header:** Set `X-Grafana-Org-Id` when using SSE or streamable HTTP transports (header takes precedence over environment variable - meaning you can set a default org as well).\n\nWhen an organization ID is provided, the MCP server will set the `X-Grafana-Org-Id` header on all requests to Grafana, ensuring that operations are performed within the specified organization context.\n\n**Example with organization ID:**\n\n```json\n{\n  \"mcpServers\": {\n    \"grafana\": {\n      \"command\": \"mcp-grafana\",\n      \"args\": [],\n      \"env\": {\n        \"GRAFANA_URL\": \"http:\u002F\u002Flocalhost:3000\",\n        \"GRAFANA_USERNAME\": \"\u003Cyour username>\",\n        \"GRAFANA_PASSWORD\": \"\u003Cyour password>\",\n        \"GRAFANA_ORG_ID\": \"2\"\n      }\n    }\n  }\n}\n```\n\n### Custom HTTP Headers\n\nYou can add arbitrary HTTP headers to all Grafana API requests using the `GRAFANA_EXTRA_HEADERS` environment variable. The value should be a JSON object mapping header names to values.\n\n**Example with custom headers:**\n\n```json\n{\n  \"mcpServers\": {\n    \"grafana\": {\n      \"command\": \"mcp-grafana\",\n      \"args\": [],\n      \"env\": {\n        \"GRAFANA_URL\": \"http:\u002F\u002Flocalhost:3000\",\n        \"GRAFANA_SERVICE_ACCOUNT_TOKEN\": \"\u003Cyour token>\",\n        \"GRAFANA_EXTRA_HEADERS\": \"{\\\"X-Custom-Header\\\": \\\"custom-value\\\", \\\"X-Tenant-ID\\\": \\\"tenant-123\\\"}\"\n      }\n    }\n  }\n}\n```\n\n### Forwarding Headers from the Client (SSE\u002FStreamable-HTTP Only)\n\nWhen the MCP server runs behind a gateway or reverse proxy that handles SSO (e.g. an AWS ALB with OIDC), each user's session cookie must reach Grafana so it can associate the request with the authenticated user. The `GRAFANA_FORWARD_HEADERS` environment variable enables this by specifying a comma-separated allowlist of header names to copy from the **incoming** HTTP request to every outbound Grafana API request.\n\nThis only applies when using SSE (`-t sse`) or streamable-http (`-t streamable-http`) transports. It has no effect in stdio mode.\n\n**Example: forward the session cookie**\n\n```json\n{\n  \"env\": {\n    \"GRAFANA_URL\": \"https:\u002F\u002Fgrafana.internal\",\n    \"GRAFANA_SERVICE_ACCOUNT_TOKEN\": \"\u003Cyour token>\",\n    \"GRAFANA_FORWARD_HEADERS\": \"Cookie\"\n  }\n}\n```\n\nYou can forward multiple headers by separating them with commas:\n\n```\nGRAFANA_FORWARD_HEADERS=Cookie,X-Session-Id\n```\n\nForwarded headers are merged with any headers defined in `GRAFANA_EXTRA_HEADERS`. If a header name appears in both, the value from the incoming request takes precedence for that request.\n\n2. You have several options to install `mcp-grafana`:\n\n   - **uvx (recommended)**: If you have [uv](https:\u002F\u002Fdocs.astral.sh\u002Fuv\u002Fgetting-started\u002Finstallation\u002F) installed, no extra setup is needed — `uvx` will automatically download and run the server:\n\n     ```bash\n     uvx mcp-grafana\n     ```\n\n   - **Docker image**: Use the pre-built Docker image from Docker Hub.\n\n     **Important**: The Docker image's entrypoint is configured to run the MCP server in SSE mode by default, but most users will want to use STDIO mode for direct integration with AI assistants like Claude Desktop:\n\n     1. **STDIO Mode**: For stdio mode you must explicitly override the default with `-t stdio` and include the `-i` flag to keep stdin open:\n\n     ```bash\n     docker pull grafana\u002Fmcp-grafana\n     # For local Grafana:\n     docker run --rm -i -e GRAFANA_URL=http:\u002F\u002Flocalhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN=\u003Cyour service account token> grafana\u002Fmcp-grafana -t stdio\n     # For Grafana Cloud:\n     docker run --rm -i -e GRAFANA_URL=https:\u002F\u002Fmyinstance.grafana.net -e GRAFANA_SERVICE_ACCOUNT_TOKEN=\u003Cyour service account token> grafana\u002Fmcp-grafana -t stdio\n     ```\n\n     2. **SSE Mode**: In this mode, the server runs as an HTTP server that clients connect to. You must expose port 8000 using the `-p` flag:\n\n     ```bash\n     docker pull grafana\u002Fmcp-grafana\n     docker run --rm -p 8000:8000 -e GRAFANA_URL=http:\u002F\u002Flocalhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN=\u003Cyour service account token> grafana\u002Fmcp-grafana\n     ```\n\n     3. **Streamable HTTP Mode**: In this mode, the server operates as an independent process that can handle multiple client connections. You must expose port 8000 using the `-p` flag: For this mode you must explicitly override the default with `-t streamable-http`\n\n     ```bash\n     docker pull grafana\u002Fmcp-grafana\n     docker run --rm -p 8000:8000 -e GRAFANA_URL=http:\u002F\u002Flocalhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN=\u003Cyour service account token> grafana\u002Fmcp-grafana -t streamable-http\n     ```\n\n     For HTTPS streamable HTTP mode with server TLS certificates:\n\n     ```bash\n     docker pull grafana\u002Fmcp-grafana\n     docker run --rm -p 8443:8443 \\\n       -v \u002Fpath\u002Fto\u002Fcerts:\u002Fcerts:ro \\\n       -e GRAFANA_URL=http:\u002F\u002Flocalhost:3000 \\\n       -e GRAFANA_SERVICE_ACCOUNT_TOKEN=\u003Cyour service account token> \\\n       grafana\u002Fmcp-grafana \\\n       -t streamable-http \\\n       -addr :8443 \\\n       --server.tls-cert-file \u002Fcerts\u002Fserver.crt \\\n       --server.tls-key-file \u002Fcerts\u002Fserver.key\n     ```\n\n   - **Download binary**: Download the latest release of `mcp-grafana` from the [releases page](https:\u002F\u002Fgithub.com\u002Fgrafana\u002Fmcp-grafana\u002Freleases) and place it in your `$PATH`.\n\n   - **Build from source**: If you have a Go toolchain installed you can also build and install it from source, using the `GOBIN` environment variable\n     to specify the directory where the binary should be installed. This should also be in your `$PATH`.\n\n     ```bash\n     GOBIN=\"$HOME\u002Fgo\u002Fbin\" go install github.com\u002Fgrafana\u002Fmcp-grafana\u002Fcmd\u002Fmcp-grafana@latest\n     ```\n\n   - **Deploy to Kubernetes using Helm**: use the [Helm chart from the Grafana helm-charts repository](https:\u002F\u002Fgithub.com\u002Fgrafana\u002Fhelm-charts\u002Ftree\u002Fmain\u002Fcharts\u002Fgrafana-mcp)\n\n     ```bash\n     helm repo add grafana https:\u002F\u002Fgrafana.github.io\u002Fhelm-charts\n     helm install --set grafana.apiKey=\u003CGrafana_ApiKey> --set grafana.url=\u003CGrafanaUrl> my-release grafana\u002Fgrafana-mcp\n     ```\n\n\n3. Add the server configuration to your client configuration file. For example, for Claude Desktop:\n\n   **If using uvx:**\n\n   ```json\n   {\n     \"mcpServers\": {\n       \"grafana\": {\n         \"command\": \"uvx\",\n         \"args\": [\"mcp-grafana\"],\n         \"env\": {\n           \"GRAFANA_URL\": \"http:\u002F\u002Flocalhost:3000\",\n           \"GRAFANA_SERVICE_ACCOUNT_TOKEN\": \"\u003Cyour service account token>\"\n         }\n       }\n     }\n   }\n   ```\n\n   **If using the binary:**\n\n   ```json\n   {\n     \"mcpServers\": {\n       \"grafana\": {\n         \"command\": \"mcp-grafana\",\n         \"args\": [],\n         \"env\": {\n           \"GRAFANA_URL\": \"http:\u002F\u002Flocalhost:3000\",  \u002F\u002F Or \"https:\u002F\u002Fmyinstance.grafana.net\" for Grafana Cloud\n           \"GRAFANA_SERVICE_ACCOUNT_TOKEN\": \"\u003Cyour service account token>\",\n           \u002F\u002F If using username\u002Fpassword authentication\n           \"GRAFANA_USERNAME\": \"\u003Cyour username>\",\n           \"GRAFANA_PASSWORD\": \"\u003Cyour password>\",\n           \u002F\u002F Optional: specify organization ID for multi-org support\n           \"GRAFANA_ORG_ID\": \"1\"\n         }\n       }\n     }\n   }\n   ```\n\n> Note: if you see `Error: spawn mcp-grafana ENOENT` in Claude Desktop, you need to specify the full path to `mcp-grafana`.\n\n**If using Docker:**\n\n```json\n{\n  \"mcpServers\": {\n    \"grafana\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\",\n        \"--rm\",\n        \"-i\",\n        \"-e\",\n        \"GRAFANA_URL\",\n        \"-e\",\n        \"GRAFANA_SERVICE_ACCOUNT_TOKEN\",\n        \"grafana\u002Fmcp-grafana\",\n        \"-t\",\n        \"stdio\"\n      ],\n      \"env\": {\n        \"GRAFANA_URL\": \"http:\u002F\u002Flocalhost:3000\",  \u002F\u002F Or \"https:\u002F\u002Fmyinstance.grafana.net\" for Grafana Cloud\n        \"GRAFANA_SERVICE_ACCOUNT_TOKEN\": \"\u003Cyour service account token>\",\n        \u002F\u002F If using username\u002Fpassword authentication\n        \"GRAFANA_USERNAME\": \"\u003Cyour username>\",\n        \"GRAFANA_PASSWORD\": \"\u003Cyour password>\",\n        \u002F\u002F Optional: specify organization ID for multi-org support\n        \"GRAFANA_ORG_ID\": \"1\"\n      }\n    }\n  }\n}\n```\n\n> Note: The `-t stdio` argument is essential here because it overrides the default SSE mode in the Docker image.\n\n**Using VSCode with remote MCP server**\n\nIf you're using VSCode and running the MCP server in SSE mode (which is the default when using the Docker image without overriding the transport), make sure your `.vscode\u002Fsettings.json` includes the following:\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"grafana\": {\n      \"type\": \"sse\",\n      \"url\": \"http:\u002F\u002Flocalhost:8000\u002Fsse\"\n    }\n  }\n}\n```\n\nFor HTTPS streamable HTTP mode with server TLS certificates:\n\n```json\n\"mcp\": {\n  \"servers\": {\n    \"grafana\": {\n      \"type\": \"sse\",\n      \"url\": \"https:\u002F\u002Flocalhost:8443\u002Fsse\"\n    }\n  }\n}\n```\n\n### Debug Mode\n\nYou can enable debug mode for the Grafana transport by adding the `-debug` flag to the command. This will provide detailed logging of HTTP requests and responses between the MCP server and the Grafana API, which can be helpful for troubleshooting.\n\nTo use debug mode with the Claude Desktop configuration, update your config as follows:\n\n**If using the binary:**\n\n```json\n{\n  \"mcpServers\": {\n    \"grafana\": {\n      \"command\": \"mcp-grafana\",\n      \"args\": [\"-debug\"],\n      \"env\": {\n        \"GRAFANA_URL\": \"http:\u002F\u002Flocalhost:3000\",  \u002F\u002F Or \"https:\u002F\u002Fmyinstance.grafana.net\" for Grafana Cloud\n        \"GRAFANA_SERVICE_ACCOUNT_TOKEN\": \"\u003Cyour service account token>\"\n      }\n    }\n  }\n}\n```\n\n**If using Docker:**\n\n```json\n{\n  \"mcpServers\": {\n    \"grafana\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\",\n        \"--rm\",\n        \"-i\",\n        \"-e\",\n        \"GRAFANA_URL\",\n        \"-e\",\n        \"GRAFANA_SERVICE_ACCOUNT_TOKEN\",\n        \"grafana\u002Fmcp-grafana\",\n        \"-t\",\n        \"stdio\",\n        \"-debug\"\n      ],\n      \"env\": {\n        \"GRAFANA_URL\": \"http:\u002F\u002Flocalhost:3000\",  \u002F\u002F Or \"https:\u002F\u002Fmyinstance.grafana.net\" for Grafana Cloud\n        \"GRAFANA_SERVICE_ACCOUNT_TOKEN\": \"\u003Cyour service account token>\"\n      }\n    }\n  }\n}\n```\n\n> Note: As with the standard configuration, the `-t stdio` argument is required to override the default SSE mode in the Docker image.\n\n### TLS Configuration\n\nIf your Grafana instance is behind mTLS or requires custom TLS certificates, you can configure the MCP server to use custom certificates. The server supports the following TLS configuration options:\n\n- `--tls-cert-file`: Path to TLS certificate file for client authentication\n- `--tls-key-file`: Path to TLS private key file for client authentication\n- `--tls-ca-file`: Path to TLS CA certificate file for server verification\n- `--tls-skip-verify`: Skip TLS certificate verification (insecure, use only for testing)\n\n**Example with client certificate authentication:**\n\n```json\n{\n  \"mcpServers\": {\n    \"grafana\": {\n      \"command\": \"mcp-grafana\",\n      \"args\": [\n        \"--tls-cert-file\",\n        \"\u002Fpath\u002Fto\u002Fclient.crt\",\n        \"--tls-key-file\",\n        \"\u002Fpath\u002Fto\u002Fclient.key\",\n        \"--tls-ca-file\",\n        \"\u002Fpath\u002Fto\u002Fca.crt\"\n      ],\n      \"env\": {\n        \"GRAFANA_URL\": \"https:\u002F\u002Fsecure-grafana.example.com\",\n        \"GRAFANA_SERVICE_ACCOUNT_TOKEN\": \"\u003Cyour service account token>\"\n      }\n    }\n  }\n}\n```\n\n**Example with Docker:**\n\n```json\n{\n  \"mcpServers\": {\n    \"grafana\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\",\n        \"--rm\",\n        \"-i\",\n        \"-v\",\n        \"\u002Fpath\u002Fto\u002Fcerts:\u002Fcerts:ro\",\n        \"-e\",\n        \"GRAFANA_URL\",\n        \"-e\",\n        \"GRAFANA_SERVICE_ACCOUNT_TOKEN\",\n        \"grafana\u002Fmcp-grafana\",\n        \"-t\",\n        \"stdio\",\n        \"--tls-cert-file\",\n        \"\u002Fcerts\u002Fclient.crt\",\n        \"--tls-key-file\",\n        \"\u002Fcerts\u002Fclient.key\",\n        \"--tls-ca-file\",\n        \"\u002Fcerts\u002Fca.crt\"\n      ],\n      \"env\": {\n        \"GRAFANA_URL\": \"https:\u002F\u002Fsecure-grafana.example.com\",\n        \"GRAFANA_SERVICE_ACCOUNT_TOKEN\": \"\u003Cyour service account token>\"\n      }\n    }\n  }\n}\n```\n\nThe TLS configuration is applied to all HTTP clients used by the MCP server, including:\n\n- The main Grafana OpenAPI client\n- Prometheus datasource clients\n- Loki datasource clients\n- Incident management clients\n- Sift investigation clients\n- Alerting clients\n- Asserts clients\n\n**Direct CLI Usage Examples:**\n\nFor testing with self-signed certificates:\n\n```bash\n.\u002Fmcp-grafana --tls-skip-verify -debug\n```\n\nWith client certificate authentication:\n\n```bash\n.\u002Fmcp-grafana \\\n  --tls-cert-file \u002Fpath\u002Fto\u002Fclient.crt \\\n  --tls-key-file \u002Fpath\u002Fto\u002Fclient.key \\\n  --tls-ca-file \u002Fpath\u002Fto\u002Fca.crt \\\n  -debug\n```\n\nWith custom CA certificate only:\n\n```bash\n.\u002Fmcp-grafana --tls-ca-file \u002Fpath\u002Fto\u002Fca.crt\n```\n\n**Programmatic Usage:**\n\nIf you're using this library programmatically, you can also create TLS-enabled context functions:\n\n```go\n\u002F\u002F Using struct literals\ntlsConfig := &mcpgrafana.TLSConfig{\n    CertFile: \"\u002Fpath\u002Fto\u002Fclient.crt\",\n    KeyFile:  \"\u002Fpath\u002Fto\u002Fclient.key\",\n    CAFile:   \"\u002Fpath\u002Fto\u002Fca.crt\",\n}\ngrafanaConfig := mcpgrafana.GrafanaConfig{\n    Debug:     true,\n    TLSConfig: tlsConfig,\n}\ncontextFunc := mcpgrafana.ComposedStdioContextFunc(grafanaConfig)\n\n\u002F\u002F Or inline\ngrafanaConfig := mcpgrafana.GrafanaConfig{\n    Debug: true,\n    TLSConfig: &mcpgrafana.TLSConfig{\n        CertFile: \"\u002Fpath\u002Fto\u002Fclient.crt\",\n        KeyFile:  \"\u002Fpath\u002Fto\u002Fclient.key\",\n        CAFile:   \"\u002Fpath\u002Fto\u002Fca.crt\",\n    },\n}\ncontextFunc := mcpgrafana.ComposedStdioContextFunc(grafanaConfig)\n```\n\n**URL validation when wiring your own HTTP server:**\n\nWhen library consumers wire mcp-grafana's context functions into their own `http.Server`, install `ValidateGrafanaURLMiddleware` to reject malformed `X-Grafana-URL` headers with 400 Bad Request (matching the binary's behavior):\n\n```go\nmux.Handle(path, mcpgrafana.ValidateGrafanaURLMiddleware(yourMCPHandler))\n```\n\nWhen calling `NewGrafanaClient` directly (stdio or programmatic construction), pre-validate untrusted URLs to avoid a reachable panic:\n\n```go\nif err := mcpgrafana.ValidateGrafanaURL(urlFromHeader); err != nil {\n    http.Error(w, err.Error(), http.StatusBadRequest)\n    return\n}\nclient := mcpgrafana.NewGrafanaClient(ctx, urlFromHeader, apiKey, nil)\n```\n\nBoth patterns share `ValidateGrafanaURL` as the single validator.\n\n### Server TLS Configuration (Streamable HTTP Transport Only)\n\nWhen using the streamable HTTP transport (`-t streamable-http`), you can configure the MCP server to serve HTTPS instead of HTTP. This is useful when you need to secure the connection between your MCP client and the server itself.\n\nThe server supports the following TLS configuration options for the streamable HTTP transport:\n\n- `--server.tls-cert-file`: Path to TLS certificate file for server HTTPS (required for TLS)\n- `--server.tls-key-file`: Path to TLS private key file for server HTTPS (required for TLS)\n\n**Note**: These flags are completely separate from the client TLS flags documented above. The client TLS flags configure how the MCP server connects to Grafana, while these server TLS flags configure how clients connect to the MCP server when using streamable HTTP transport.\n\n**Example with HTTPS streamable HTTP server:**\n\n```bash\n.\u002Fmcp-grafana \\\n  -t streamable-http \\\n  --server.tls-cert-file \u002Fpath\u002Fto\u002Fserver.crt \\\n  --server.tls-key-file \u002Fpath\u002Fto\u002Fserver.key \\\n  -addr :8443\n```\n\nThis would start the MCP server on HTTPS port 8443. Clients would then connect to `https:\u002F\u002Flocalhost:8443\u002F` instead of `http:\u002F\u002Flocalhost:8000\u002F`.\n\n**Docker example with server TLS:**\n\n```bash\ndocker run --rm -p 8443:8443 \\\n  -v \u002Fpath\u002Fto\u002Fcerts:\u002Fcerts:ro \\\n  -e GRAFANA_URL=http:\u002F\u002Flocalhost:3000 \\\n  -e GRAFANA_SERVICE_ACCOUNT_TOKEN=\u003Cyour service account token> \\\n  grafana\u002Fmcp-grafana \\\n  -t streamable-http \\\n  -addr :8443 \\\n  --server.tls-cert-file \u002Fcerts\u002Fserver.crt \\\n  --server.tls-key-file \u002Fcerts\u002Fserver.key\n```\n\n### Health Check Endpoint\n\nWhen using the SSE (`-t sse`) or streamable HTTP (`-t streamable-http`) transports, the MCP server exposes a health check endpoint at `\u002Fhealthz`. This endpoint can be used by load balancers, monitoring systems, or orchestration platforms to verify that the server is running and accepting connections.\n\n**Endpoint:** `GET \u002Fhealthz`\n\n**Response:**\n- Status Code: `200 OK`\n- Body: `ok`\n\n**Example usage:**\n\n```bash\n# For streamable HTTP or SSE transport on default port\ncurl http:\u002F\u002Flocalhost:8000\u002Fhealthz\n\n# With custom address\ncurl http:\u002F\u002Flocalhost:9090\u002Fhealthz\n```\n\n**Note:** The health check endpoint is only available when using SSE or streamable HTTP transports. It is not available when using the stdio transport (`-t stdio`), as stdio does not expose an HTTP server.\n\n### Observability\n\nThe MCP server supports Prometheus metrics, OpenTelemetry distributed tracing, and OpenTelemetry log export, following the [OTel MCP semantic conventions](https:\u002F\u002Fopentelemetry.io\u002Fdocs\u002Fspecs\u002Fsemconv\u002Fgen-ai\u002Fmcp\u002F). Tracing and log export are configured via standard `OTEL_*` environment variables and work with any transport.\n\n**Note:** mcp-grafana currently only supports the OTLP\u002FgRPC transport for both traces and logs. `OTEL_EXPORTER_OTLP_PROTOCOL` (and its `_TRACES_PROTOCOL` \u002F `_LOGS_PROTOCOL` variants) are not honored — gRPC is used regardless.\n\n#### Metrics\n\nWhen using the SSE or streamable HTTP transports, enable Prometheus metrics with the `--metrics` flag:\n\n```bash\n# Metrics served on the main server at \u002Fmetrics\n.\u002Fmcp-grafana -t streamable-http --metrics\n\n# Metrics served on a separate address\n.\u002Fmcp-grafana -t streamable-http --metrics --metrics-address :9090\n```\n\n**Available Metrics:**\n\n| Metric | Type | Description |\n|--------|------|-------------|\n| `mcp_server_operation_duration_seconds` | Histogram | Duration of MCP operations (labels: `mcp_method_name`, `gen_ai_tool_name`, `error_type`, `network_transport`, `mcp_protocol_version`) |\n| `mcp_server_session_duration_seconds` | Histogram | Duration of MCP client sessions (labels: `network_transport`, `mcp_protocol_version`) |\n| `http_server_request_duration_seconds` | Histogram | Duration of HTTP server requests (from otelhttp) |\n\n**Note:** Metrics are only available when using SSE or streamable HTTP transports. They are not available with the stdio transport.\n\n#### Slow-request logging\n\nThe `--slow-request-threshold` flag emits a structured log event whenever an MCP request (tool invocation, list, resource read, etc.) exceeds the given duration. It is useful for diagnosing slow queries and tool calls without drowning in the full debug log.\n\n```bash\n# Warn on any request slower than 500ms (works on all transports)\n.\u002Fmcp-grafana -t streamable-http --slow-request-threshold 500ms\n\n# Same thing on stdio (the feature is transport-agnostic, unlike --metrics)\n.\u002Fmcp-grafana -t stdio --slow-request-threshold 500ms\n\n# Log at INFO level instead of WARN (useful during investigation)\n.\u002Fmcp-grafana -t streamable-http --slow-request-threshold 500ms --slow-request-log-level info\n```\n\nThe log event carries these structured attributes:\n\n| Attribute | Description |\n|-----------|-------------|\n| `mcp.method` | The MCP method (e.g., `tools\u002Fcall`, `tools\u002Flist`, `resources\u002Fread`) |\n| `duration` | Observed request duration |\n| `threshold` | Configured threshold |\n| `tool` | Tool name (only present for `tools\u002Fcall` methods) |\n| `error` | Error value, when the request failed (best-effort context; content is controlled by upstream error wrapping) |\n| `error.type` | Bounded-cardinality error classification (`_OTHER` for untyped errors) |\n\nSlow-request logging works on all transports (including stdio) and does not require `--metrics`. The default threshold of `0` disables it entirely. Proxied tools flow through `tools\u002Fcall` and are covered automatically.\n\n#### Tracing\n\nDistributed tracing is configured via standard `OTEL_*` environment variables and works independently of the `--metrics` flag. When `OTEL_EXPORTER_OTLP_ENDPOINT` is set, the server exports traces via OTLP\u002FgRPC:\n\n```bash\n# Send traces to a local Tempo instance\nOTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Flocalhost:4317 \\\nOTEL_EXPORTER_OTLP_INSECURE=true \\\n.\u002Fmcp-grafana -t streamable-http\n\n# Send traces to Grafana Cloud with authentication\nOTEL_EXPORTER_OTLP_ENDPOINT=https:\u002F\u002Ftempo-us-central1.grafana.net:443 \\\nOTEL_EXPORTER_OTLP_HEADERS=\"Authorization=Basic ...\" \\\n.\u002Fmcp-grafana -t streamable-http\n```\n\nTool call spans follow semconv naming (`tools\u002Fcall \u003Ctool_name>`) and include attributes like `gen_ai.tool.name`, `mcp.method.name`, and `mcp.session.id`. The server also supports W3C trace context propagation from the `_meta` field of tool call requests.\n\n#### Logs\n\nWhen `OTEL_EXPORTER_OTLP_ENDPOINT` (or the signal-specific `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`) is set — the same trigger that enables tracing — the server also exports structured logs via OTLP\u002FgRPC in addition to the existing plain-text stderr output. The `otelslog` bridge automatically attaches `trace_id` and `span_id` from the active span, so log records correlate with the traces the server already emits.\n\nStderr logging is unchanged when OTLP logging is enabled; you can continue to rely on container logs or pipe stderr to `\u002Fdev\u002Fnull` if you prefer.\n\n```bash\n# Send both logs and traces to a local OTel collector\nOTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Flocalhost:4317 \\\nOTEL_EXPORTER_OTLP_INSECURE=true \\\n.\u002Fmcp-grafana -t streamable-http\n```\n\nThe transport is OTLP\u002FgRPC (default port `4317`). Logs can be sent directly to any managed backend that accepts OTLP\u002FgRPC — for example, Grafana Cloud — by pointing `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT` (or the generic `OTEL_EXPORTER_OTLP_ENDPOINT`) at the remote gRPC endpoint and supplying auth via `OTEL_EXPORTER_OTLP_LOGS_HEADERS` (or `OTEL_EXPORTER_OTLP_HEADERS`), mirroring the tracing example above. A local OTel collector is **optional** — useful for fan-out, batching, or multi-backend routing, but not required.\n\nThe signal-specific variants `OTEL_EXPORTER_OTLP_LOGS_ENDPOINT`, `OTEL_EXPORTER_OTLP_LOGS_HEADERS`, `OTEL_EXPORTER_OTLP_LOGS_INSECURE`, `OTEL_EXPORTER_OTLP_LOGS_CERTIFICATE`, `OTEL_EXPORTER_OTLP_LOGS_TIMEOUT`, and `OTEL_EXPORTER_OTLP_LOGS_COMPRESSION` are honored and override their generic `OTEL_EXPORTER_OTLP_*` counterparts — see the [OTel exporter spec](https:\u002F\u002Fopentelemetry.io\u002Fdocs\u002Fspecs\u002Fotel\u002Fprotocol\u002Fexporter\u002F) for the full list and precedence rules.\n\nIf the configured collector is unreachable, log records are buffered in memory (default queue: 2048) and the oldest records are dropped once the queue fills. The process continues without blocking the service. Configure a local OTel collector if you need lossless buffering during outages.\n\nLogs are also exported under the stdio transport, which makes it easy to centralize logs from local `mcp-grafana` instances invoked by IDE clients.\n\n**Docker example with metrics, tracing, and logs:**\n\n```bash\ndocker run --rm -p 8000:8000 \\\n  -e GRAFANA_URL=http:\u002F\u002Flocalhost:3000 \\\n  -e GRAFANA_SERVICE_ACCOUNT_TOKEN=\u003Cyour token> \\\n  -e OTEL_EXPORTER_OTLP_ENDPOINT=http:\u002F\u002Ftempo:4317 \\\n  -e OTEL_EXPORTER_OTLP_INSECURE=true \\\n  grafana\u002Fmcp-grafana \\\n  -t streamable-http --metrics\n```\n\n## Troubleshooting\n\n### Grafana Version Compatibility\n\nIf you encounter the following error when using datasource-related tools:\n\n```\nget datasource by uid : [GET \u002Fdatasources\u002Fuid\u002F{uid}][400] getDataSourceByUidBadRequest {\"message\":\"id is invalid\"}\n```\n\nThis typically indicates that you are using a Grafana version earlier than 9.0. The `\u002Fdatasources\u002Fuid\u002F{uid}` API endpoint was introduced in Grafana 9.0, and datasource operations will fail on earlier versions.\n\n**Solution:** Upgrade your Grafana instance to version 9.0 or later to resolve this issue.\n\n## Development\n\nContributions are welcome! Please open an issue or submit a pull request if you have any suggestions or improvements.\n\nThis project is written in Go. Install Go following the instructions for your platform.\n\nTo run the server locally in STDIO mode (which is the default for local development), use:\n\n```bash\nmake run\n```\n\nTo run the server locally in SSE mode, use:\n\n```bash\ngo run .\u002Fcmd\u002Fmcp-grafana --transport sse\n```\n\nYou can also run the server using the SSE transport inside a custom built Docker image. Just like the published Docker image, this custom image's entrypoint defaults to SSE mode. To build the image, use:\n\n```\nmake build-image\n```\n\nAnd to run the image in SSE mode (the default), use:\n\n```\ndocker run -it --rm -p 8000:8000 mcp-grafana:latest\n```\n\nIf you need to run it in STDIO mode instead, override the transport setting:\n\n```\ndocker run -it --rm mcp-grafana:latest -t stdio\n```\n\n### Testing\n\nThere are three types of tests available:\n\n1. Unit Tests (no external dependencies required):\n\n```bash\nmake test-unit\n```\n\nYou can also run unit tests with:\n\n```bash\nmake test\n```\n\n2. Integration Tests (requires docker containers to be up and running):\n\n```bash\nmake test-integration\n```\n\n3. Cloud Tests (requires cloud Grafana instance and credentials):\n\n```bash\nmake test-cloud\n```\n\n> Note: Cloud tests are automatically configured in CI. For local development, you'll need to set up your own Grafana Cloud instance and credentials.\n\nMore comprehensive integration tests will require a Grafana instance to be running locally on port 3000; you can start one with Docker Compose:\n\n```bash\ndocker-compose up -d\n```\n\nThe integration tests can be run with:\n\n```bash\nmake test-all\n```\n\nIf you're adding more tools, please add integration tests for them. The existing tests should be a good starting point.\n\n### Linting\n\nTo lint the code, run:\n\n```bash\nmake lint\n```\n\nThis includes a custom linter that checks for unescaped commas in `jsonschema` struct tags. The commas in `description` fields must be escaped with `\\\\,` to prevent silent trun","Grafana MCP server 是一个用于 Grafana 的 Model Context Protocol (MCP) 服务器，它提供了对 Grafana 实例及其周边生态系统的访问。该项目使用 Go 语言开发，支持通过 MCP 协议搜索、获取、更新和创建仪表板等功能，并允许用户通过 JSONPath 表达式提取特定的仪表板属性以减少上下文窗口的使用。此外，还支持数据源信息查询等操作。适用于需要与 Grafana 集成或扩展其功能的应用场景，尤其是当开发者希望在保持高效资源利用的同时，实现对 Grafana 内容的自动化管理时。要求 Grafana 版本至少为 9.0 以确保所有特性正常工作。",2,"2026-06-11 03:44:44","high_star"]