diff --git a/README.md b/README.md index 381d2eb..bd1bd6a 100644 --- a/README.md +++ b/README.md @@ -6,755 +6,112 @@ [![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. +A [Model Context Protocol][mcp] (MCP) server that provides AI assistants with seamless access to your Grafana instance and its ecosystem. Enable your AI to query metrics, search dashboards, manage incidents, investigate issues with Sift, and moreβ€”all through natural language. -This provides access to your Grafana instance and the surrounding ecosystem. +## Quick Start -## Requirements +### Prerequisites -- **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. +- **Grafana 9.0+** (required for full functionality) +- A Grafana instance (local or Grafana Cloud) +- Service account token or username/password credentials -## 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 or other metadata -- **Get dashboard by UID:** Retrieve full dashboard details using its unique identifier. _Warning: Large dashboards can consume significant context window space._ -- **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 - -#### 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._ - -### 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. - -### 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. - -### Incidents - -- **Search, create, and update incidents:** Manage incidents in Grafana Incident, including searching, creating, and adding activities to incidents. - -### Sift Investigations - -- **List Sift investigations:** Retrieve a list of Sift investigations, with support for a limit parameter. -- **Get Sift investigation:** Retrieve details of a specific Sift investigation by its UUID. -- **Get Sift analyses:** Retrieve a specific analysis from a Sift investigation. -- **Find error patterns in logs:** Detect elevated error patterns in Loki logs using Sift. -- **Find slow requests:** Detect slow requests using Sift (Tempo). - -### Alerting - -- **List and fetch alert rule information:** View alert rules and their statuses (firing/normal/error/etc.) in Grafana. -- **List contact points:** View configured notification contact points in Grafana. - -### 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 - -- **List teams:** View all configured teams in Grafana. -- **List Users:** View all users in an organization in Grafana. - -### 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?left={"datasource":"prometheus-uid"}`) - - **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 - -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. - -**Note:** Grafana Incident and Sift tools use basic Grafana roles instead of fine-grained RBAC permissions: -- **Viewer role:** Required for read-only operations (list incidents, get investigations) -- **Editor role:** Required for write operations (create incidents, modify investigations) - -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 all users in an organization | `users:read` | `global.users:*` or `global.users:id:123` | -| `search_dashboards` | Search | Search for dashboards | `dashboards:read` | `dashboards:*` or `dashboards:uid:abc123` | -| `get_dashboard_by_uid` | Dashboard | Get a dashboard by uid | `dashboards:read` | `dashboards:uid:abc123` | -| `update_dashboard` | Dashboard | Update or create a new dashboard | `dashboards:create`, `dashboards:write` | `dashboards:*`, `folders:*` or `folders:uid:xyz789` | -| `get_dashboard_panel_queries` | Dashboard | Get panel title, queries, datasource UID and type from a dashboard | `dashboards:read` | `dashboards:uid:abc123` | -| `get_dashboard_property` | Dashboard | Extract specific parts of a dashboard using JSONPath expressions | `dashboards:read` | `dashboards:uid:abc123` | -| `get_dashboard_summary` | Dashboard | Get a compact summary of a dashboard without full JSON | `dashboards:read` | `dashboards:uid:abc123` | -| `list_datasources` | Datasources | List datasources | `datasources:read` | `datasources:*` | -| `get_datasource_by_uid` | Datasources | Get a datasource by uid | `datasources:read` | `datasources:uid:prometheus-uid` | -| `get_datasource_by_name` | Datasources | Get a datasource by name | `datasources:read` | `datasources:*` or `datasources:uid:loki-uid` | -| `query_prometheus` | Prometheus | Execute a query against a Prometheus datasource | `datasources:query` | `datasources:uid:prometheus-uid` | -| `list_prometheus_metric_metadata` | Prometheus | List metric metadata | `datasources:query` | `datasources:uid:prometheus-uid` | -| `list_prometheus_metric_names` | Prometheus | List available metric names | `datasources:query` | `datasources:uid:prometheus-uid` | -| `list_prometheus_label_names` | Prometheus | List label names matching a selector | `datasources:query` | `datasources:uid:prometheus-uid` | -| `list_prometheus_label_values` | Prometheus | List values for a specific label | `datasources:query` | `datasources:uid:prometheus-uid` | -| `list_incidents` | Incident | List incidents in Grafana Incident | Viewer role | N/A | -| `create_incident` | Incident | Create an incident in Grafana Incident | Editor role | N/A | -| `add_activity_to_incident` | Incident | Add an activity item to an incident in Grafana Incident | Editor role | N/A | -| `get_incident` | Incident | Get a single incident by ID | Viewer role | N/A | -| `query_loki_logs` | Loki | Query and retrieve logs using LogQL (either log or metric queries) | `datasources:query` | `datasources:uid:loki-uid` | -| `list_loki_label_names` | Loki | List all available label names in logs | `datasources:query` | `datasources:uid:loki-uid` | -| `list_loki_label_values` | Loki | List values for a specific log label | `datasources:query` | `datasources:uid:loki-uid` | -| `query_loki_stats` | Loki | Get statistics about log streams | `datasources:query` | `datasources:uid:loki-uid` | -| `list_alert_rules` | Alerting | List alert rules | `alert.rules:read` | `folders:*` or `folders:uid:alerts-folder` | -| `get_alert_rule_by_uid` | Alerting | Get alert rule by UID | `alert.rules:read` | `folders:uid:alerts-folder` | -| `list_contact_points` | Alerting | List notification contact points | `alert.notifications:read` | Global scope | -| `list_oncall_schedules` | OnCall | List schedules from Grafana OnCall | `grafana-oncall-app.schedules:read` | Plugin-specific scopes | -| `get_oncall_shift` | OnCall | Get details for a specific OnCall shift | `grafana-oncall-app.schedules:read` | Plugin-specific scopes | -| `get_current_oncall_users` | OnCall | Get users currently on-call for a specific schedule | `grafana-oncall-app.schedules:read` | Plugin-specific scopes | -| `list_oncall_teams` | OnCall | List teams from Grafana OnCall | `grafana-oncall-app.user-settings:read` | Plugin-specific scopes | -| `list_oncall_users` | OnCall | List users from Grafana OnCall | `grafana-oncall-app.user-settings:read` | Plugin-specific scopes | -| `list_alert_groups` | OnCall | List alert groups from Grafana OnCall with filtering options | `grafana-oncall-app.alert-groups:read` | Plugin-specific scopes | -| `get_alert_group` | OnCall | Get a specific alert group from Grafana OnCall by its ID | `grafana-oncall-app.alert-groups:read` | Plugin-specific scopes | -| `get_sift_investigation` | Sift | Retrieve an existing Sift investigation by its UUID | Viewer role | N/A | -| `get_sift_analysis` | Sift | Retrieve a specific analysis from a Sift investigation | Viewer role | N/A | -| `list_sift_investigations` | Sift | Retrieve a list of Sift investigations with an optional limit | Viewer role | N/A | -| `find_error_pattern_logs` | Sift | Finds elevated error patterns in Loki logs. | Editor role | N/A | -| `find_slow_requests` | Sift | Finds slow requests from the relevant tempo datasources. | Editor role | N/A | -| `list_pyroscope_label_names` | Pyroscope | List label names matching a selector | `datasources:query` | `datasources:uid:pyroscope-uid` | -| `list_pyroscope_label_values` | Pyroscope | List label values matching a selector for a label name | `datasources:query` | `datasources:uid:pyroscope-uid` | -| `list_pyroscope_profile_types` | Pyroscope | List available profile types | `datasources:query` | `datasources:uid:pyroscope-uid` | -| `fetch_pyroscope_profile` | Pyroscope | Fetches a profile in DOT format for analysis | `datasources:query` | `datasources:uid:pyroscope-uid` | -| `get_assertions` | Asserts | Get assertion summary for a given entity | Plugin-specific permissions | Plugin-specific scopes | -| `generate_deeplink` | Navigation | Generate accurate deeplink URLs for Grafana resources | None (read-only URL generation) | N/A | - -## 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 -- `--endpoint-path`: Endpoint path for the streamable-http server - default: `/` - -**Debug and Logging:** -- `--debug`: Enable debug mode for detailed HTTP request/response logging - -**Tool Configuration:** -- `--enabled-tools`: Comma-separated list of enabled tools - default: all tools enabled -- `--disable-search`: Disable search tools -- `--disable-datasource`: Disable datasource tools -- `--disable-incident`: Disable incident tools -- `--disable-prometheus`: Disable prometheus tools -- `--disable-loki`: Disable loki tools -- `--disable-alerting`: Disable alerting tools -- `--disable-dashboard`: Disable dashboard tools -- `--disable-oncall`: Disable oncall tools -- `--disable-asserts`: Disable asserts tools -- `--disable-sift`: Disable sift tools -- `--disable-admin`: Disable admin tools -- `--disable-pyroscope`: Disable pyroscope tools -- `--disable-navigation`: Disable navigation tools - -**Client TLS Configuration (for Grafana connections):** -- `--tls-cert-file`: Path to TLS certificate file for client authentication -- `--tls-key-file`: Path to TLS private key file for client authentication -- `--tls-ca-file`: Path to TLS CA certificate file for server verification -- `--tls-skip-verify`: Skip TLS certificate verification (insecure) - -**Server TLS Configuration (streamable-http transport only):** -- `--server.tls-cert-file`: Path to TLS certificate file for server HTTPS -- `--server.tls-key-file`: Path to TLS private key file for server HTTPS - -## Usage - -This MCP server works with both local Grafana instances and Grafana Cloud. For Grafana Cloud, use your instance URL (e.g., `https://myinstance.grafana.net`) instead of `http://localhost:3000` in the configuration examples below. - -1. If using service account token authentication, create a service account in Grafana with enough permissions to use the tools you want to use, - generate a service account token, and copy it to the clipboard for use in the configuration file. - Follow the [Grafana service account documentation][service-account] for details on creating service account tokens. - - > **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. - -2. You have several options to install `mcp-grafana`: - - - **Docker image**: Use the pre-built Docker image from Docker Hub. - - **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: - - 1. **STDIO Mode**: For stdio mode you must explicitly override the default with `-t stdio` and include the `-i` flag to keep stdin open: - - ```bash - docker pull mcp/grafana - # For local Grafana: - docker run --rm -i -e GRAFANA_URL=http://localhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN= mcp/grafana -t stdio - # For Grafana Cloud: - docker run --rm -i -e GRAFANA_URL=https://myinstance.grafana.net -e GRAFANA_SERVICE_ACCOUNT_TOKEN= mcp/grafana -t stdio - ``` - - 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: - - ```bash - docker pull mcp/grafana - docker run --rm -p 8000:8000 -e GRAFANA_URL=http://localhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN= mcp/grafana - ``` - - 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` +### Installation - ```bash - docker pull mcp/grafana - docker run --rm -p 8000:8000 -e GRAFANA_URL=http://localhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN= mcp/grafana -t streamable-http - ``` +Choose your preferred installation method: - For HTTPS streamable HTTP mode with server TLS certificates: - - ```bash - docker pull mcp/grafana - docker run --rm -p 8443:8443 \ - -v /path/to/certs:/certs:ro \ - -e GRAFANA_URL=http://localhost:3000 \ - -e GRAFANA_SERVICE_ACCOUNT_TOKEN= \ - mcp/grafana \ - -t streamable-http \ - -addr :8443 \ - --server.tls-cert-file /certs/server.crt \ - --server.tls-key-file /certs/server.key - ``` - - - **Download binary**: Download the latest release of `mcp-grafana` from the [releases page](https://github.com/grafana/mcp-grafana/releases) and place it in your `$PATH`. - - - **Build from source**: If you have a Go toolchain installed you can also build and install it from source, using the `GOBIN` environment variable - to specify the directory where the binary should be installed. This should also be in your `PATH`. - - ```bash - GOBIN="$HOME/go/bin" go install github.com/grafana/mcp-grafana/cmd/mcp-grafana@latest - ``` - - - **Deploy to Kubernetes using Helm**: use the [Helm chart from the Grafana helm-charts repository](https://github.com/grafana/helm-charts/tree/main/charts/grafana-mcp) - - ```bash - helm repo add grafana https://grafana.github.io/helm-charts - helm install --set grafana.apiKey= --set grafana.url= my-release grafana/grafana-mcp - ``` - - -3. Add the server configuration to your client configuration file. For example, for Claude Desktop: - - **If using the binary:** - - ```json - { - "mcpServers": { - "grafana": { - "command": "mcp-grafana", - "args": [], - "env": { - "GRAFANA_URL": "http://localhost:3000", // Or "https://myinstance.grafana.net" for Grafana Cloud - "GRAFANA_SERVICE_ACCOUNT_TOKEN": "", - // If using username/password authentication - "GRAFANA_USERNAME": "", - "GRAFANA_PASSWORD": "" - } - } - } - } - ``` - -> Note: if you see `Error: spawn mcp-grafana ENOENT` in Claude Desktop, you need to specify the full path to `mcp-grafana`. - -**If using Docker:** - -```json -{ - "mcpServers": { - "grafana": { - "command": "docker", - "args": [ - "run", - "--rm", - "-i", - "-e", - "GRAFANA_URL", - "-e", - "GRAFANA_SERVICE_ACCOUNT_TOKEN", - "mcp/grafana", - "-t", - "stdio" - ], - "env": { - "GRAFANA_URL": "http://localhost:3000", // Or "https://myinstance.grafana.net" for Grafana Cloud - "GRAFANA_SERVICE_ACCOUNT_TOKEN": "", - // If using username/password authentication - "GRAFANA_USERNAME": "", - "GRAFANA_PASSWORD": "" - } - } - } -} -``` - -> Note: The `-t stdio` argument is essential here because it overrides the default SSE mode in the Docker image. - -**Using VSCode with remote MCP server** - -If 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/settings.json` includes the following: - -```json -"mcp": { - "servers": { - "grafana": { - "type": "sse", - "url": "http://localhost:8000/sse" - } - } -} -``` - -For HTTPS streamable HTTP mode with server TLS certificates: - -```json -"mcp": { - "servers": { - "grafana": { - "type": "sse", - "url": "https://localhost:8443/sse" - } - } -} -``` - -### Debug Mode - -You 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. - -To use debug mode with the Claude Desktop configuration, update your config as follows: - -**If using the binary:** - -```json -{ - "mcpServers": { - "grafana": { - "command": "mcp-grafana", - "args": ["-debug"], - "env": { - "GRAFANA_URL": "http://localhost:3000", // Or "https://myinstance.grafana.net" for Grafana Cloud - "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" - } - } - } -} +**Using Docker (recommended):** +```bash +docker pull mcp/grafana +docker run --rm -i \ + -e GRAFANA_URL=http://localhost:3000 \ + -e GRAFANA_SERVICE_ACCOUNT_TOKEN= \ + mcp/grafana -t stdio ``` -**If using Docker:** - -```json -{ - "mcpServers": { - "grafana": { - "command": "docker", - "args": [ - "run", - "--rm", - "-i", - "-e", - "GRAFANA_URL", - "-e", - "GRAFANA_SERVICE_ACCOUNT_TOKEN", - "mcp/grafana", - "-t", - "stdio", - "-debug" - ], - "env": { - "GRAFANA_URL": "http://localhost:3000", // Or "https://myinstance.grafana.net" for Grafana Cloud - "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" - } - } - } -} +**Using Go:** +```bash +go install github.com/grafana/mcp-grafana/cmd/mcp-grafana@latest ``` -> Note: As with the standard configuration, the `-t stdio` argument is required to override the default SSE mode in the Docker image. - -### TLS Configuration +**Download Binary:** +Download from the [releases page](https://github.com/grafana/mcp-grafana/releases) -If 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: +### Basic Configuration -- `--tls-cert-file`: Path to TLS certificate file for client authentication -- `--tls-key-file`: Path to TLS private key file for client authentication -- `--tls-ca-file`: Path to TLS CA certificate file for server verification -- `--tls-skip-verify`: Skip TLS certificate verification (insecure, use only for testing) - -**Example with client certificate authentication:** +Add to your MCP client configuration (e.g., Claude Desktop): ```json { "mcpServers": { "grafana": { "command": "mcp-grafana", - "args": [ - "--tls-cert-file", - "/path/to/client.crt", - "--tls-key-file", - "/path/to/client.key", - "--tls-ca-file", - "/path/to/ca.crt" - ], - "env": { - "GRAFANA_URL": "https://secure-grafana.example.com", - "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" - } - } - } -} -``` - -**Example with Docker:** - -```json -{ - "mcpServers": { - "grafana": { - "command": "docker", - "args": [ - "run", - "--rm", - "-i", - "-v", - "/path/to/certs:/certs:ro", - "-e", - "GRAFANA_URL", - "-e", - "GRAFANA_SERVICE_ACCOUNT_TOKEN", - "mcp/grafana", - "-t", - "stdio", - "--tls-cert-file", - "/certs/client.crt", - "--tls-key-file", - "/certs/client.key", - "--tls-ca-file", - "/certs/ca.crt" - ], + "args": [], "env": { - "GRAFANA_URL": "https://secure-grafana.example.com", - "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" + "GRAFANA_URL": "http://localhost:3000", + "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" } } } } ``` -The TLS configuration is applied to all HTTP clients used by the MCP server, including: - -- The main Grafana OpenAPI client -- Prometheus datasource clients -- Loki datasource clients -- Incident management clients -- Sift investigation clients -- Alerting clients -- Asserts clients - -**Direct CLI Usage Examples:** - -For testing with self-signed certificates: - -```bash -./mcp-grafana --tls-skip-verify -debug -``` - -With client certificate authentication: - -```bash -./mcp-grafana \ - --tls-cert-file /path/to/client.crt \ - --tls-key-file /path/to/client.key \ - --tls-ca-file /path/to/ca.crt \ - -debug -``` - -With custom CA certificate only: - -```bash -./mcp-grafana --tls-ca-file /path/to/ca.crt -``` - -**Programmatic Usage:** - -If you're using this library programmatically, you can also create TLS-enabled context functions: - -```go -// Using struct literals -tlsConfig := &mcpgrafana.TLSConfig{ - CertFile: "/path/to/client.crt", - KeyFile: "/path/to/client.key", - CAFile: "/path/to/ca.crt", -} -grafanaConfig := mcpgrafana.GrafanaConfig{ - Debug: true, - TLSConfig: tlsConfig, -} -contextFunc := mcpgrafana.ComposedStdioContextFunc(grafanaConfig) - -// Or inline -grafanaConfig := mcpgrafana.GrafanaConfig{ - Debug: true, - TLSConfig: &mcpgrafana.TLSConfig{ - CertFile: "/path/to/client.crt", - KeyFile: "/path/to/client.key", - CAFile: "/path/to/ca.crt", - }, -} -contextFunc := mcpgrafana.ComposedStdioContextFunc(grafanaConfig) -``` - -### Server TLS Configuration (Streamable HTTP Transport Only) - -When 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. - -The server supports the following TLS configuration options for the streamable HTTP transport: - -- `--server.tls-cert-file`: Path to TLS certificate file for server HTTPS (required for TLS) -- `--server.tls-key-file`: Path to TLS private key file for server HTTPS (required for TLS) - -**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. - -**Example with HTTPS streamable HTTP server:** - -```bash -./mcp-grafana \ - -t streamable-http \ - --server.tls-cert-file /path/to/server.crt \ - --server.tls-key-file /path/to/server.key \ - -addr :8443 -``` - -This would start the MCP server on HTTPS port 8443. Clients would then connect to `https://localhost:8443/` instead of `http://localhost:8000/`. - -**Docker example with server TLS:** - -```bash -docker run --rm -p 8443:8443 \ - -v /path/to/certs:/certs:ro \ - -e GRAFANA_URL=http://localhost:3000 \ - -e GRAFANA_SERVICE_ACCOUNT_TOKEN= \ - mcp/grafana \ - -t streamable-http \ - -addr :8443 \ - --server.tls-cert-file /certs/server.crt \ - --server.tls-key-file /certs/server.key -``` - -### Health Check Endpoint - -When using the SSE (`-t sse`) or streamable HTTP (`-t streamable-http`) transports, the MCP server exposes a health check endpoint at `/healthz`. This endpoint can be used by load balancers, monitoring systems, or orchestration platforms to verify that the server is running and accepting connections. - -**Endpoint:** `GET /healthz` - -**Response:** -- Status Code: `200 OK` -- Body: `ok` - -**Example usage:** +For Docker, VSCode, Kubernetes, and other setups, see the [Configuration Guide](docs/CONFIGURATION.md). -```bash -# For streamable HTTP or SSE transport on default port -curl http://localhost:8000/healthz - -# With custom address -curl http://localhost:9090/healthz -``` - -**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. - -## Troubleshooting - -### Grafana Version Compatibility - -If you encounter the following error when using datasource-related tools: - -``` -get datasource by uid : [GET /datasources/uid/{uid}][400] getDataSourceByUidBadRequest {"message":"id is invalid"} -``` - -This typically indicates that you are using a Grafana version earlier than 9.0. The `/datasources/uid/{uid}` API endpoint was introduced in Grafana 9.0, and datasource operations will fail on earlier versions. - -**Solution:** Upgrade your Grafana instance to version 9.0 or later to resolve this issue. - -## Development - -Contributions are welcome! Please open an issue or submit a pull request if you have any suggestions or improvements. - -This project is written in Go. Install Go following the instructions for your platform. - -To run the server locally in STDIO mode (which is the default for local development), use: - -```bash -make run -``` - -To run the server locally in SSE mode, use: - -```bash -go run ./cmd/mcp-grafana --transport sse -``` - -You 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: - -``` -make build-image -``` - -And to run the image in SSE mode (the default), use: - -``` -docker run -it --rm -p 8000:8000 mcp-grafana:latest -``` - -If you need to run it in STDIO mode instead, override the transport setting: - -``` -docker run -it --rm mcp-grafana:latest -t stdio -``` - -### Testing - -There are three types of tests available: - -1. Unit Tests (no external dependencies required): - -```bash -make test-unit -``` - -You can also run unit tests with: - -```bash -make test -``` - -2. Integration Tests (requires docker containers to be up and running): - -```bash -make test-integration -``` +## Features -3. Cloud Tests (requires cloud Grafana instance and credentials): +This MCP server provides AI assistants with powerful Grafana capabilities: -```bash -make test-cloud -``` +- **πŸ“Š Dashboards** - Search, retrieve, update, and create dashboards with context-aware operations +- **πŸ”Œ Datasources** - List and query datasources (Prometheus, Loki, Pyroscope) +- **πŸ“ˆ Prometheus** - Execute PromQL queries and retrieve metric metadata +- **πŸ“ Loki** - Query logs with LogQL and retrieve log metadata +- **🚨 Incidents** - Search, create, and manage incidents in Grafana Incident +- **πŸ” Sift Investigations** - Detect error patterns and slow requests automatically +- **⚠️ Alerting** - View alert rules and notification contact points +- **πŸ“ž Grafana OnCall** - Manage schedules, shifts, and view who's on-call +- **πŸ‘₯ Admin** - List teams and users in your Grafana organization +- **πŸ”— Navigation** - Generate accurate deeplinks to dashboards, panels, and Explore -> Note: Cloud tests are automatically configured in CI. For local development, you'll need to set up your own Grafana Cloud instance and credentials. +See the [Features Guide](docs/FEATURES.md) for detailed descriptions and examples. -More comprehensive integration tests will require a Grafana instance to be running locally on port 3000; you can start one with Docker Compose: +## Documentation -```bash -docker-compose up -d -``` +### Getting Started +- **[Installation Guide](docs/INSTALLATION.md)** - All installation methods (binary, Docker, Kubernetes, from source) +- **[Configuration Guide](docs/CONFIGURATION.md)** - Client setup, authentication, debug mode, TLS configuration -The integration tests can be run with: +### Reference +- **[Features & Capabilities](docs/FEATURES.md)** - Detailed feature descriptions and use cases +- **[Tools Reference](docs/TOOLS_REFERENCE.md)** - Complete list of available tools and CLI flags +- **[RBAC & Permissions](docs/RBAC.md)** - Required permissions and scopes for each tool -```bash -make test-all -``` - -If you're adding more tools, please add integration tests for them. The existing tests should be a good starting point. +### Operations +- **[Troubleshooting](docs/TROUBLESHOOTING.md)** - Common issues and solutions +- **[Development Guide](docs/DEVELOPMENT.md)** - Contributing, testing, and linting -### Linting +### Examples +- [Claude Desktop](docs/examples/claude-desktop.md) +- [VSCode](docs/examples/vscode.md) +- [Docker](docs/examples/docker.md) +- [Kubernetes](docs/examples/kubernetes.md) -To lint the code, run: +## Support & Community -```bash -make lint -``` +- **Issues:** [GitHub Issues](https://github.com/grafana/mcp-grafana/issues) +- **Discussions:** [GitHub Discussions](https://github.com/grafana/mcp-grafana/discussions) +- **Documentation:** [Grafana Docs](https://grafana.com/docs/) -This 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 truncation. You can run just this linter with: - -```bash -make lint-jsonschema -``` +## Contributing -See the [JSONSchema Linter documentation](internal/linter/jsonschema/README.md) for more details. +Contributions are welcome! Please see the [Development Guide](docs/DEVELOPMENT.md) for details on: +- Setting up your development environment +- Running tests +- Code standards and linting +- Submitting pull requests ## License This project is licensed under the [Apache License, Version 2.0](LICENSE). -[mcp]: https://modelcontextprotocol.io/ -[service-account]: https://grafana.com/docs/grafana/latest/administration/service-accounts/#add-a-token-to-a-service-account-in-grafana +[mcp]: https://modelcontextprotocol.io/ \ No newline at end of file diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md new file mode 100644 index 0000000..3fba00e --- /dev/null +++ b/docs/CONFIGURATION.md @@ -0,0 +1,629 @@ +# Configuration Guide + +This guide covers all configuration options for the Grafana MCP server and how to set it up with various MCP clients. + +## Table of Contents + +- [Overview](#overview) +- [Authentication](#authentication) +- [Environment Variables](#environment-variables) +- [Transport Modes](#transport-modes) +- [Client Configuration](#client-configuration) +- [Debug Mode](#debug-mode) +- [TLS Configuration](#tls-configuration) +- [Tool Configuration](#tool-configuration) +- [Health Check Endpoint](#health-check-endpoint) + +## Overview + +The Grafana MCP server can be configured through: +- **Environment variables** - For authentication and Grafana connection details +- **Command-line flags** - For server behavior, transport mode, and feature toggles +- **Client configuration** - For integrating with MCP clients like Claude Desktop, VSCode, etc. + +## Authentication + +The server supports two authentication methods: + +### Service Account Token (Recommended) + +Create a service account in Grafana and generate a token: + +```bash +export GRAFANA_URL=http://localhost:3000 +export GRAFANA_SERVICE_ACCOUNT_TOKEN= +``` + +> **Best Practice:** Service account tokens are more secure and provide better audit trails than username/password authentication. + +### Username/Password + +For development or testing environments: + +```bash +export GRAFANA_URL=http://localhost:3000 +export GRAFANA_USERNAME=admin +export GRAFANA_PASSWORD=admin +``` + +> **Warning:** Username/password authentication may be less secure and is not recommended for production use. + +### Grafana Cloud + +For Grafana Cloud instances, use your instance URL: + +```bash +export GRAFANA_URL=https://myinstance.grafana.net +export GRAFANA_SERVICE_ACCOUNT_TOKEN= +``` + +## Environment Variables + +| Variable | Description | Required | Default | +|----------|-------------|----------|---------| +| `GRAFANA_URL` | Your Grafana instance URL | Yes | - | +| `GRAFANA_SERVICE_ACCOUNT_TOKEN` | Service account token for authentication | Yes* | - | +| `GRAFANA_USERNAME` | Username for basic authentication | Yes* | - | +| `GRAFANA_PASSWORD` | Password for basic authentication | Yes* | - | +| `GRAFANA_API_KEY` | **(Deprecated)** Use `GRAFANA_SERVICE_ACCOUNT_TOKEN` instead | No | - | + +\* Either `GRAFANA_SERVICE_ACCOUNT_TOKEN` or both `GRAFANA_USERNAME` and `GRAFANA_PASSWORD` are required. + +## Transport Modes + +The server supports three transport modes: + +### STDIO (Default) + +Direct stdin/stdout communication, ideal for local AI assistants: + +```bash +mcp-grafana -t stdio +``` + +**Use cases:** +- Claude Desktop +- Local AI assistant integrations +- Testing with MCP Inspector + +### SSE (Server-Sent Events) + +HTTP server mode for remote clients: + +```bash +mcp-grafana -t sse --address localhost:8000 +``` + +**Use cases:** +- Remote client connections +- VSCode with remote MCP servers +- Multiple client connections + +### Streamable HTTP + +HTTP server with streaming support for multiple concurrent connections: + +```bash +mcp-grafana -t streamable-http --address localhost:8000 +``` + +**Use cases:** +- Production deployments +- Load-balanced setups +- Multiple concurrent clients + +## Client Configuration + +### Claude Desktop + +Claude Desktop uses a JSON configuration file located at: +- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json` +- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json` +- **Linux:** `~/.config/Claude/claude_desktop_config.json` + +#### Using Binary + +```json +{ + "mcpServers": { + "grafana": { + "command": "mcp-grafana", + "args": [], + "env": { + "GRAFANA_URL": "http://localhost:3000", + "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" + } + } + } +} +``` + +> **Note:** If you see `Error: spawn mcp-grafana ENOENT`, specify the full path to the binary (e.g., `/usr/local/bin/mcp-grafana` or `C:\\Program Files\\mcp-grafana\\mcp-grafana.exe`). + +#### Using Docker + +```json +{ + "mcpServers": { + "grafana": { + "command": "docker", + "args": [ + "run", + "--rm", + "-i", + "-e", + "GRAFANA_URL", + "-e", + "GRAFANA_SERVICE_ACCOUNT_TOKEN", + "mcp/grafana", + "-t", + "stdio" + ], + "env": { + "GRAFANA_URL": "http://localhost:3000", + "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" + } + } + } +} +``` + +> **Important:** The `-t stdio` argument is essential to override the default SSE mode in the Docker image. + +For more examples, see [Claude Desktop Examples](examples/claude-desktop.md). + +### VSCode + +VSCode configuration depends on the transport mode you're using. + +#### Remote Server (SSE Mode) + +If running the MCP server separately in SSE mode, configure `.vscode/settings.json`: + +```json +{ + "mcp": { + "servers": { + "grafana": { + "type": "sse", + "url": "http://localhost:8000/sse" + } + } + } +} +``` + +#### With HTTPS + +```json +{ + "mcp": { + "servers": { + "grafana": { + "type": "sse", + "url": "https://localhost:8443/sse" + } + } + } +} +``` + +For more examples, see [VSCode Examples](examples/vscode.md). + +### Cline + +Cline (VSCode extension) configuration: + +```json +{ + "mcpServers": { + "grafana": { + "command": "mcp-grafana", + "args": [], + "env": { + "GRAFANA_URL": "http://localhost:3000", + "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" + } + } + } +} +``` + +### MCP Inspector + +For testing with the MCP Inspector: + +```bash +npx @modelcontextprotocol/inspector mcp-grafana +``` + +## Debug Mode + +Enable debug mode for detailed HTTP request/response logging: + +```bash +mcp-grafana --debug +``` + +### Claude Desktop with Debug Mode + +**Binary:** + +```json +{ + "mcpServers": { + "grafana": { + "command": "mcp-grafana", + "args": ["--debug"], + "env": { + "GRAFANA_URL": "http://localhost:3000", + "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" + } + } + } +} +``` + +**Docker:** + +```json +{ + "mcpServers": { + "grafana": { + "command": "docker", + "args": [ + "run", + "--rm", + "-i", + "-e", + "GRAFANA_URL", + "-e", + "GRAFANA_SERVICE_ACCOUNT_TOKEN", + "mcp/grafana", + "-t", + "stdio", + "--debug" + ], + "env": { + "GRAFANA_URL": "http://localhost:3000", + "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" + } + } + } +} +``` + +**What Debug Mode Shows:** +- Full HTTP requests to Grafana API +- Response status codes and headers +- Request/response bodies +- Timing information +- Error details + +## TLS Configuration + +### Client TLS (Grafana Connection) + +Configure TLS for connecting to Grafana instances with custom certificates or mTLS. + +#### Available Options + +| Flag | Description | +|------|-------------| +| `--tls-cert-file` | Path to TLS certificate file for client authentication | +| `--tls-key-file` | Path to TLS private key file for client authentication | +| `--tls-ca-file` | Path to TLS CA certificate file for server verification | +| `--tls-skip-verify` | Skip TLS certificate verification (insecure, testing only) | + +#### Example: Client Certificate Authentication + +**Command Line:** + +```bash +mcp-grafana \ + --tls-cert-file /path/to/client.crt \ + --tls-key-file /path/to/client.key \ + --tls-ca-file /path/to/ca.crt +``` + +**Claude Desktop:** + +```json +{ + "mcpServers": { + "grafana": { + "command": "mcp-grafana", + "args": [ + "--tls-cert-file", + "/path/to/client.crt", + "--tls-key-file", + "/path/to/client.key", + "--tls-ca-file", + "/path/to/ca.crt" + ], + "env": { + "GRAFANA_URL": "https://secure-grafana.example.com", + "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" + } + } + } +} +``` + +**Docker:** + +```json +{ + "mcpServers": { + "grafana": { + "command": "docker", + "args": [ + "run", + "--rm", + "-i", + "-v", + "/path/to/certs:/certs:ro", + "-e", + "GRAFANA_URL", + "-e", + "GRAFANA_SERVICE_ACCOUNT_TOKEN", + "mcp/grafana", + "-t", + "stdio", + "--tls-cert-file", + "/certs/client.crt", + "--tls-key-file", + "/certs/client.key", + "--tls-ca-file", + "/certs/ca.crt" + ], + "env": { + "GRAFANA_URL": "https://secure-grafana.example.com", + "GRAFANA_SERVICE_ACCOUNT_TOKEN": "" + } + } + } +} +``` + +#### Example: Self-Signed Certificates (Testing Only) + +```bash +mcp-grafana --tls-skip-verify --debug +``` + +> **Warning:** Never use `--tls-skip-verify` in production environments. It disables certificate verification and makes connections vulnerable to man-in-the-middle attacks. + +#### Example: Custom CA Only + +```bash +mcp-grafana --tls-ca-file /path/to/ca.crt +``` + +#### What Client TLS Affects + +Client TLS configuration applies to all connections from the MCP server to Grafana, including: +- Main Grafana OpenAPI client +- Prometheus datasource clients +- Loki datasource clients +- Incident management clients +- Sift investigation clients +- Alerting clients +- OnCall clients +- Asserts clients + +### Server TLS (MCP Server Connection) + +Configure TLS for securing connections **to** the MCP server (only for `streamable-http` transport). + +> **Important:** Server TLS is completely separate from client TLS. Server TLS secures the connection between your MCP client and the MCP server, while client TLS secures the connection between the MCP server and Grafana. + +#### Available Options + +| Flag | Description | +|------|-------------| +| `--server.tls-cert-file` | Path to TLS certificate file for server HTTPS | +| `--server.tls-key-file` | Path to TLS private key file for server HTTPS | + +#### Example: HTTPS Server + +**Command Line:** + +```bash +mcp-grafana \ + -t streamable-http \ + --address :8443 \ + --server.tls-cert-file /path/to/server.crt \ + --server.tls-key-file /path/to/server.key +``` + +**Docker:** + +```bash +docker run --rm -p 8443:8443 \ + -v /path/to/certs:/certs:ro \ + -e GRAFANA_URL=http://localhost:3000 \ + -e GRAFANA_SERVICE_ACCOUNT_TOKEN= \ + mcp/grafana \ + -t streamable-http \ + -addr :8443 \ + --server.tls-cert-file /certs/server.crt \ + --server.tls-key-file /certs/server.key +``` + +Clients would then connect to `https://localhost:8443/` instead of `http://localhost:8000/`. + +#### Programmatic Usage + +If you're using this library programmatically in Go: + +```go +// Using struct literals +tlsConfig := &mcpgrafana.TLSConfig{ + CertFile: "/path/to/client.crt", + KeyFile: "/path/to/client.key", + CAFile: "/path/to/ca.crt", +} +grafanaConfig := mcpgrafana.GrafanaConfig{ + Debug: true, + TLSConfig: tlsConfig, +} +contextFunc := mcpgrafana.ComposedStdioContextFunc(grafanaConfig) + +// Or inline +grafanaConfig := mcpgrafana.GrafanaConfig{ + Debug: true, + TLSConfig: &mcpgrafana.TLSConfig{ + CertFile: "/path/to/client.crt", + KeyFile: "/path/to/client.key", + CAFile: "/path/to/ca.crt", + }, +} +contextFunc := mcpgrafana.ComposedStdioContextFunc(grafanaConfig) +``` + +## Tool Configuration + +Control which tools are available to MCP clients. + +### Disable Specific Tool Categories + +```bash +# Disable OnCall tools +mcp-grafana --disable-oncall + +# Disable multiple categories +mcp-grafana --disable-oncall --disable-incident --disable-sift +``` + +### Available Disable Flags + +| Flag | Category | Tools Affected | +|------|----------|----------------| +| `--disable-search` | Search | Dashboard search | +| `--disable-datasource` | Datasources | List/get datasources | +| `--disable-dashboard` | Dashboard | Dashboard CRUD operations | +| `--disable-prometheus` | Prometheus | PromQL queries and metadata | +| `--disable-loki` | Loki | LogQL queries and metadata | +| `--disable-pyroscope` | Pyroscope | Profile queries and metadata | +| `--disable-incident` | Incident | Incident management | +| `--disable-sift` | Sift | Sift investigations | +| `--disable-alerting` | Alerting | Alert rules and contact points | +| `--disable-oncall` | OnCall | OnCall schedules and users | +| `--disable-admin` | Admin | Teams and users | +| `--disable-navigation` | Navigation | Deeplink generation | +| `--disable-asserts` | Asserts | Asserts plugin integration | + +### Enable Specific Tools Only + +```bash +# Enable only specific tools +mcp-grafana --enabled-tools list_dashboards,get_dashboard_by_uid,query_prometheus +``` + +### Why Disable Tools? + +- **Reduce context window usage** - Fewer tools mean less metadata sent to the AI +- **Security** - Limit access to specific Grafana features +- **Performance** - Skip initialization of unused clients +- **Simplicity** - Focus on specific use cases + +## Health Check Endpoint + +When using SSE or streamable-http transports, a health check endpoint is available at `/healthz`. + +### Check Health + +```bash +curl http://localhost:8000/healthz +# Response: ok (HTTP 200) +``` + +### Use Cases + +- Kubernetes liveness/readiness probes +- Load balancer health checks +- Monitoring systems +- Docker healthchecks + +### Kubernetes Example + +```yaml +livenessProbe: + httpGet: + path: /healthz + port: 8000 + initialDelaySeconds: 5 + periodSeconds: 10 +``` + +> **Note:** The health check endpoint is only available for SSE and streamable-http transports, not for stdio. + +## Advanced Configuration Examples + +### Production Setup with All Features + +```bash +mcp-grafana \ + -t streamable-http \ + --address :8443 \ + --server.tls-cert-file /certs/server.crt \ + --server.tls-key-file /certs/server.key \ + --tls-cert-file /certs/client.crt \ + --tls-key-file /certs/client.key \ + --tls-ca-file /certs/ca.crt \ + --debug +``` + +### Minimal Setup for Dashboard Queries Only + +```bash +mcp-grafana \ + --disable-incident \ + --disable-oncall \ + --disable-sift \ + --disable-alerting \ + --disable-admin +``` + +### Development Setup with Debug + +```bash +export GRAFANA_URL=http://localhost:3000 +export GRAFANA_USERNAME=admin +export GRAFANA_PASSWORD=admin + +mcp-grafana --debug +``` + +## Troubleshooting Configuration + +### Common Issues + +**"Error: spawn mcp-grafana ENOENT"** +- Use the full path to the binary in your client configuration +- Ensure the binary is in your PATH + +**"Connection refused"** +- Verify GRAFANA_URL is correct +- Check if Grafana is running and accessible +- Verify firewall rules + +**"Authentication failed"** +- Check your service account token is valid +- Verify the token hasn't expired +- Ensure the service account has necessary permissions + +**"TLS handshake failed"** +- Verify certificate paths are correct +- Check certificate validity +- Ensure CA certificate matches the server certificate + +For more troubleshooting help, see the [Troubleshooting Guide](TROUBLESHOOTING.md). + +## Next Steps + +- [Explore available features](FEATURES.md) +- [Review tool reference](TOOLS_REFERENCE.md) +- [Set up RBAC permissions](RBAC.md) +- [Check out examples](examples/) \ No newline at end of file diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md new file mode 100644 index 0000000..ef38c12 --- /dev/null +++ b/docs/DEVELOPMENT.md @@ -0,0 +1,619 @@ +# Development Guide + +This guide covers everything you need to know to contribute to the Grafana MCP server project. + +## Table of Contents + +- [Getting Started](#getting-started) +- [Development Environment](#development-environment) +- [Building from Source](#building-from-source) +- [Running Locally](#running-locally) +- [Testing](#testing) +- [Linting](#linting) +- [Code Standards](#code-standards) +- [Contributing](#contributing) +- [Release Process](#release-process) + +## Getting Started + +### Prerequisites + +- **Go 1.21 or later** - [Install Go](https://golang.org/doc/install) +- **Git** - For version control +- **Docker** - For running integration tests +- **Docker Compose** - For test Grafana instance +- **Make** - For build automation + +### Clone the Repository + +```bash +git clone https://github.com/grafana/mcp-grafana.git +cd mcp-grafana +``` + +### Verify Setup + +```bash +# Check Go version +go version + +# Check Docker +docker --version +docker-compose --version + +# Check Make +make --version +``` + +## Development Environment + +### IDE Setup + +#### VSCode + +Recommended extensions: +- Go (golang.go) +- Go Test Explorer +- GitLens + +Create `.vscode/settings.json`: + +```json +{ + "go.useLanguageServer": true, + "go.lintTool": "golangci-lint", + "go.lintOnSave": "package", + "editor.formatOnSave": true, + "[go]": { + "editor.defaultFormatter": "golang.go" + } +} +``` + +#### GoLand / IntelliJ IDEA + +1. Open the project directory +2. Enable Go modules support +3. Configure code style to use gofmt + +### Environment Variables + +Create a `.env` file for local development: + +```bash +# .env +GRAFANA_URL=http://localhost:3000 +GRAFANA_SERVICE_ACCOUNT_TOKEN=your-token-here +# Or for basic auth: +# GRAFANA_USERNAME=admin +# GRAFANA_PASSWORD=admin +``` + +Load environment variables: + +```bash +source .env +``` + +## Building from Source + +### Build Binary + +```bash +# Build for current platform +make build + +# Binary will be in ./dist/mcp-grafana +./dist/mcp-grafana --help +``` + +### Build for Multiple Platforms + +```bash +# Build for all platforms using goreleaser +make build-all +``` + +### Install Locally + +```bash +# Install to $GOPATH/bin +go install ./cmd/mcp-grafana + +# Or specify custom location +GOBIN="$HOME/bin" go install ./cmd/mcp-grafana +``` + +### Build Docker Image + +```bash +# Build Docker image +make build-image + +# Image will be tagged as mcp-grafana:latest +docker images | grep mcp-grafana +``` + +## Running Locally + +### STDIO Mode (Default) + +```bash +# Run with make +make run + +# Or run directly +go run ./cmd/mcp-grafana + +# With debug mode +go run ./cmd/mcp-grafana --debug +``` + +### SSE Mode + +```bash +# Run SSE server on default port (8000) +go run ./cmd/mcp-grafana --transport sse + +# Custom port +go run ./cmd/mcp-grafana --transport sse --address :9090 +``` + +### Streamable HTTP Mode + +```bash +go run ./cmd/mcp-grafana --transport streamable-http +``` + +### With Docker Compose + +Start a local Grafana instance for testing: + +```bash +# Start Grafana and dependencies +docker-compose up -d + +# Check status +docker-compose ps + +# View logs +docker-compose logs -f grafana + +# Stop everything +docker-compose down +``` + +The docker-compose setup includes: +- Grafana on port 3000 +- Prometheus on port 9090 +- Loki on port 3100 + +Default Grafana credentials: `admin` / `admin` + +## Testing + +The project has three types of tests: unit tests, integration tests, and cloud tests. + +### Unit Tests + +Unit tests have no external dependencies and run quickly. + +```bash +# Run unit tests +make test-unit + +# Or use go test directly +go test -v -short ./... + +# Run with coverage +go test -v -short -cover ./... + +# Generate coverage report +go test -v -short -coverprofile=coverage.out ./... +go tool cover -html=coverage.out +``` + +### Integration Tests + +Integration tests require Docker containers to be running. + +```bash +# Start test environment +docker-compose up -d + +# Wait for services to be ready +sleep 10 + +# Run integration tests +make test-integration + +# Or with go test +go test -v ./... -run Integration +``` + +**What integration tests cover:** +- Dashboard operations +- Datasource queries (Prometheus, Loki) +- Alert rule operations +- API client functionality + +### Cloud Tests + +Cloud tests run against a real Grafana Cloud instance (used in CI). + +```bash +# Set up cloud credentials +export GRAFANA_CLOUD_URL=https://yourinstance.grafana.net +export GRAFANA_CLOUD_TOKEN=your-cloud-token + +# Run cloud tests +make test-cloud +``` + +> **Note:** Cloud tests require a Grafana Cloud instance. They are primarily used in CI and are optional for local development. + +### Run All Tests + +```bash +# Ensure Docker Compose is running +docker-compose up -d + +# Run all tests +make test-all +``` + +### Test Specific Packages + +```bash +# Test a specific package +go test -v ./internal/tools + +# Test a specific function +go test -v ./internal/tools -run TestDashboardTools +``` + +### Writing Tests + +When adding new tools, please include tests: + +**Unit test example:** + +```go +func TestNewTool(t *testing.T) { + // Arrange + client := mockGrafanaClient() + + // Act + result, err := NewTool(client, params) + + // Assert + require.NoError(t, err) + assert.Equal(t, expectedResult, result) +} +``` + +**Integration test example:** + +```go +func TestNewToolIntegration(t *testing.T) { + if testing.Short() { + t.Skip("Skipping integration test") + } + + // Use real Grafana client + client := setupIntegrationClient(t) + + result, err := NewTool(client, params) + + require.NoError(t, err) + assert.NotNil(t, result) +} +``` + +## Linting + +### Run All Linters + +```bash +# Run golangci-lint +make lint +``` + +### Linter Configuration + +The project uses `golangci-lint` with custom configuration in `.golangci.yaml`. + +Enabled linters include: +- gofmt +- govet +- staticcheck +- gosimple +- ineffassign +- unused +- Custom JSONSchema linter + +### JSONSchema Linter + +The project includes a custom linter that checks for unescaped commas in `jsonschema` struct tags. + +**Why?** Unescaped commas in description fields cause silent truncation in JSON schema generation. + +```bash +# Run JSONSchema linter only +make lint-jsonschema +``` + +**Example of correct usage:** + +```go +// ❌ Wrong - comma will cause truncation +Description string `jsonschema:"description=This is a test, with comma"` + +// βœ… Correct - comma is escaped +Description string `jsonschema:"description=This is a test\\, with comma"` +``` + +See [JSONSchema Linter documentation](../internal/linter/jsonschema/README.md) for more details. + +### Fix Linter Issues + +```bash +# Auto-fix some issues +golangci-lint run --fix + +# Format code +gofmt -w . + +# Or use goimports +goimports -w . +``` + +## Code Standards + +### Go Code Style + +Follow standard Go conventions: +- Use `gofmt` for formatting +- Follow [Effective Go](https://golang.org/doc/effective_go.html) +- Use meaningful variable names +- Add comments for exported functions and types +- Keep functions focused and small + +### Project Structure + +``` +mcp-grafana/ +β”œβ”€β”€ cmd/ +β”‚ └── mcp-grafana/ # Main application entry point +β”œβ”€β”€ internal/ +β”‚ β”œβ”€β”€ grafana/ # Grafana API clients +β”‚ β”œβ”€β”€ tools/ # MCP tool implementations +β”‚ β”œβ”€β”€ linter/ # Custom linters +β”‚ └── ... +β”œβ”€β”€ testdata/ # Test fixtures +β”œβ”€β”€ tests/ # Integration tests +β”œβ”€β”€ docs/ # Documentation +└── examples/ # Configuration examples +``` + +### Adding New Tools + +1. **Define the tool in `tools.go`:** + +```go +func NewMyTool(client *grafana.Client) mcp.Tool { + return mcp.Tool{ + Name: "my_tool", + Description: "Description of what the tool does", + InputSchema: generateSchema(MyToolInput{}), + } +} +``` + +2. **Create input/output structs:** + +```go +type MyToolInput struct { + Param1 string `json:"param1" jsonschema:"required,description=Parameter description"` + Param2 int `json:"param2" jsonschema:"description=Optional parameter"` +} +``` + +3. **Implement the handler:** + +```go +func handleMyTool(ctx context.Context, client *grafana.Client, input MyToolInput) (interface{}, error) { + // Implementation + return result, nil +} +``` + +4. **Add tests:** + +```go +func TestMyTool(t *testing.T) { + // Unit tests +} + +func TestMyToolIntegration(t *testing.T) { + if testing.Short() { + t.Skip("Skipping integration test") + } + // Integration tests +} +``` + +5. **Update documentation:** + - Add tool to `docs/TOOLS_REFERENCE.md` + - Document feature in `docs/FEATURES.md` + - Add RBAC requirements to `docs/RBAC.md` + +### Error Handling + +Use descriptive errors: + +```go +// ❌ Bad +return nil, err + +// βœ… Good +return nil, fmt.Errorf("failed to get dashboard %s: %w", uid, err) +``` + +### Logging + +Use structured logging appropriately: + +```go +// For debug information +if debug { + log.Printf("Querying datasource %s with params: %+v", dsUID, params) +} + +// For errors +log.Printf("ERROR: Failed to query datasource: %v", err) +``` + +## Contributing + +### Workflow + +1. **Fork the repository** +2. **Create a feature branch:** + ```bash + git checkout -b feature/my-new-feature + ``` +3. **Make your changes** +4. **Run tests and linters:** + ```bash + make test-unit + make lint + ``` +5. **Commit with descriptive messages:** + ```bash + git commit -m "Add new dashboard query tool" + ``` +6. **Push to your fork:** + ```bash + git push origin feature/my-new-feature + ``` +7. **Open a Pull Request** + +### Pull Request Guidelines + +- **Title:** Clear, descriptive title +- **Description:** Explain what changes and why +- **Tests:** Include tests for new functionality +- **Documentation:** Update relevant docs +- **Linting:** Ensure all linters pass +- **Commits:** Use clear commit messages + +### Commit Message Format + +``` +: + + + +