Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 44 additions & 11 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
docker:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
with:
persist-credentials: false

- name: Process tag name
id: tag
Expand All @@ -30,17 +34,46 @@
echo "is_stable=false" >> $GITHUB_OUTPUT
fi

- name: Build and Push to Docker Hub
uses: grafana/shared-workflows/actions/build-push-to-dockerhub@81f54fe0cf066c512caafa199a26cb7b3636fd37
- name: Get Vault secrets
id: secrets
uses: grafana/shared-workflows/actions/get-vault-secrets@5d7e361bc7e0a183cde8afe9899fb7b596d2659b # get-vault-secrets-v1.2.0
with:
context: .
file: ./Dockerfile
repository: grafana/mcp-grafana
platforms: linux/amd64,linux/arm64
tags: |
${{ steps.tag.outputs.is_stable == 'true' && 'latest' || '' }}
${{ steps.tag.outputs.version }}
push: true
common_secrets: |
DOCKERHUB_USERNAME=dockerhub:username
DOCKERHUB_PASSWORD=dockerhub:password
export_env: false

- name: Login to Docker Hub
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
username: ${{ fromJSON(steps.secrets.outputs.secrets || '{}').DOCKERHUB_USERNAME }}
password: ${{ fromJSON(steps.secrets.outputs.secrets || '{}').DOCKERHUB_PASSWORD }}

- name: Setup Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
with:
go-version-file: "go.mod"
cache: true
Comment on lines +54 to +56

Check failure

Code scanning / zizmor

runtime artifacts potentially vulnerable to a cache poisoning attack Error

runtime artifacts potentially vulnerable to a cache poisoning attack

- name: Setup ko
uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
with:
version: v0.18.0

- name: Build and push with ko
env:
KO_DOCKER_REPO: "docker.io/grafana/mcp-grafana"
VERSION: ${{ steps.tag.outputs.version }}
run: |
ko build ./cmd/mcp-grafana --platform linux/amd64,linux/arm64 --bare \
-t "${VERSION}" ${{ steps.tag.outputs.is_stable == 'true' && '-t latest' || '' }} \
--image-label org.opencontainers.image.title=mcp-grafana \
--image-label org.opencontainers.image.description="Model Context Protocol server for Grafana" \
--image-label org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }} \
--image-label org.opencontainers.image.revision=${{ github.sha }} \
--image-label org.opencontainers.image.version=${VERSION} \
--image-label org.opencontainers.image.created="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
--image-label io.modelcontextprotocol.server.name="io.github.grafana/mcp-grafana"

mcp-registry:
runs-on: ubuntu-latest
Expand Down
85 changes: 51 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,19 @@ The dashboard tools now include several strategies to manage context window usag
- **Patch Annotation:** Update only specific fields of an annotation (partial update).
- **Get Annotation Tags:** List available annotation tags with optional filtering.


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-<category>` flag when starting the server. For example, to disable
the OnCall tools, use `--disable-oncall`, or to disable navigation deeplink generation, use `--disable-navigation`.


#### RBAC Permissions

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

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

**Note:** 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)

Expand Down Expand Up @@ -159,6 +158,7 @@ Scopes define the specific resources that permissions apply to. Each action requ
```

- **Dashboard-specific access:** Read only specific dashboards

```
dashboards:uid:monitoring-dashboard (dashboards:read)
dashboards:uid:alerts-dashboard (dashboards:read)
Expand Down Expand Up @@ -225,15 +225,18 @@ Scopes define the specific resources that permissions apply to. Each action requ
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 categories - default: all categories enabled - example: "loki,datasources"
- `--disable-search`: Disable search tools
- `--disable-datasource`: Disable datasource tools
Expand Down Expand Up @@ -262,39 +265,47 @@ The `--disable-write` flag provides a way to run the MCP server in read-only mod
When `--disable-write` is enabled, the following write operations are disabled:

**Dashboard Tools:**

- `update_dashboard`

**Folder Tools:**

- `create_folder`

**Incident Tools:**

- `create_incident`
- `add_activity_to_incident`

**Alerting Tools:**

- `create_alert_rule`
- `update_alert_rule`
- `delete_alert_rule`

**Annotation Tools:**

- `create_annotation`
- `create_graphite_annotation`
- `update_annotation`
- `patch_annotation`

**Sift Tools:**

- `find_error_pattern_logs` (creates investigations)
- `find_slow_requests` (creates investigations)

All read operations remain available, allowing you to query dashboards, run PromQL/LogQL queries, list resources, and retrieve data.

**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

Expand All @@ -310,7 +321,7 @@ This MCP server works with both local Grafana instances and Grafana Cloud. For G
> **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.

### Multi-Organization Support

You can specify which organization to interact with using either:

- **Environment variable:** Set `GRAFANA_ORG_ID` to the numeric organization ID
Expand Down Expand Up @@ -341,43 +352,43 @@ When an organization ID is provided, the MCP server will set the `X-Grafana-Org-

- **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:
The Docker image defaults to **stdio mode**, which is ideal for direct integration with AI assistants like Claude Desktop via the MCP Registry.

1. **STDIO Mode**: For stdio mode you must explicitly override the default with `-t stdio` and include the `-i` flag to keep stdin open:
1. **STDIO Mode** (default): Include the `-i` flag to keep stdin open:

```bash
docker pull mcp/grafana
docker pull grafana/mcp-grafana
# For local Grafana:
docker run --rm -i -e GRAFANA_URL=http://localhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN=<your service account token> mcp/grafana -t stdio
docker run --rm -i -e GRAFANA_URL=http://localhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN=<your service account token> grafana/mcp-grafana
# For Grafana Cloud:
docker run --rm -i -e GRAFANA_URL=https://myinstance.grafana.net -e GRAFANA_SERVICE_ACCOUNT_TOKEN=<your service account token> mcp/grafana -t stdio
docker run --rm -i -e GRAFANA_URL=https://myinstance.grafana.net -e GRAFANA_SERVICE_ACCOUNT_TOKEN=<your service account token> grafana/mcp-grafana
```

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:
2. **SSE Mode**: Run as an HTTP server. You must specify `-t sse`, bind to `0.0.0.0`, and expose port 8000:

```bash
docker pull mcp/grafana
docker run --rm -p 8000:8000 -e GRAFANA_URL=http://localhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN=<your service account token> mcp/grafana
docker pull grafana/mcp-grafana
docker run --rm -p 8000:8000 -e GRAFANA_URL=http://localhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN=<your service account token> grafana/mcp-grafana -t sse --address 0.0.0.0:8000
```

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`
3. **Streamable HTTP Mode**: For multiple client connections. Specify `-t streamable-http`, bind to `0.0.0.0`, and expose port 8000:

```bash
docker pull mcp/grafana
docker run --rm -p 8000:8000 -e GRAFANA_URL=http://localhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN=<your service account token> mcp/grafana -t streamable-http
docker pull grafana/mcp-grafana
docker run --rm -p 8000:8000 -e GRAFANA_URL=http://localhost:3000 -e GRAFANA_SERVICE_ACCOUNT_TOKEN=<your service account token> grafana/mcp-grafana -t streamable-http --address 0.0.0.0:8000
```

For HTTPS streamable HTTP mode with server TLS certificates:

```bash
docker pull mcp/grafana
docker pull grafana/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=<your service account token> \
mcp/grafana \
grafana/mcp-grafana \
-t streamable-http \
-addr :8443 \
--address 0.0.0.0:8443 \
--server.tls-cert-file /certs/server.crt \
--server.tls-key-file /certs/server.key
```
Expand All @@ -391,14 +402,29 @@ When an organization ID is provided, the MCP server will set the `X-Grafana-Org-
GOBIN="$HOME/go/bin" go install github.com/grafana/mcp-grafana/cmd/mcp-grafana@latest
```

- **Build container image with ko**: For local development or custom container builds, you can use [ko](https://ko.build/) to build a container image directly from source:

```bash
# Install ko (if not already installed)
go install github.com/google/ko@latest

# Build and load into local Docker daemon
KO_DOCKER_REPO=ko.local ko build ./cmd/mcp-grafana --bare

# Build for a specific registry
KO_DOCKER_REPO=ghcr.io/myorg/mcp-grafana ko build ./cmd/mcp-grafana --bare -t latest

# Build multi-platform image
KO_DOCKER_REPO=docker.io/myorg/mcp-grafana ko build ./cmd/mcp-grafana --platform linux/amd64,linux/arm64 --bare -t v1.0.0
```

- **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=<Grafana_ApiKey> --set grafana.url=<GrafanaUrl> my-release grafana/grafana-mcp
```


3. Add the server configuration to your client configuration file. For example, for Claude Desktop:

**If using the binary:**
Expand Down Expand Up @@ -440,9 +466,7 @@ When an organization ID is provided, the MCP server will set the `X-Grafana-Org-
"GRAFANA_URL",
"-e",
"GRAFANA_SERVICE_ACCOUNT_TOKEN",
"mcp/grafana",
"-t",
"stdio"
"grafana/mcp-grafana"
],
"env": {
"GRAFANA_URL": "http://localhost:3000", // Or "https://myinstance.grafana.net" for Grafana Cloud
Expand All @@ -458,11 +482,9 @@ When an organization ID is provided, the MCP server will set the `X-Grafana-Org-
}
```

> 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:
If you're running the MCP server in SSE mode, make sure your `.vscode/settings.json` includes the following:

```json
"mcp": {
Expand Down Expand Up @@ -526,9 +548,7 @@ To use debug mode with the Claude Desktop configuration, update your config as f
"GRAFANA_URL",
"-e",
"GRAFANA_SERVICE_ACCOUNT_TOKEN",
"mcp/grafana",
"-t",
"stdio",
"grafana/mcp-grafana",
"-debug"
],
"env": {
Expand All @@ -540,8 +560,6 @@ To use debug mode with the Claude Desktop configuration, update your config as f
}
```

> Note: As with the standard configuration, the `-t stdio` argument is required to override the default SSE mode in the Docker image.

### TLS Configuration

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:
Expand Down Expand Up @@ -592,9 +610,7 @@ If your Grafana instance is behind mTLS or requires custom TLS certificates, you
"GRAFANA_URL",
"-e",
"GRAFANA_SERVICE_ACCOUNT_TOKEN",
"mcp/grafana",
"-t",
"stdio",
"grafana/mcp-grafana",
"--tls-cert-file",
"/certs/client.crt",
"--tls-key-file",
Expand Down Expand Up @@ -704,9 +720,9 @@ docker run --rm -p 8443:8443 \
-v /path/to/certs:/certs:ro \
-e GRAFANA_URL=http://localhost:3000 \
-e GRAFANA_SERVICE_ACCOUNT_TOKEN=<your service account token> \
mcp/grafana \
grafana/mcp-grafana \
-t streamable-http \
-addr :8443 \
--address 0.0.0.0:8443 \
--server.tls-cert-file /certs/server.crt \
--server.tls-key-file /certs/server.key
```
Expand All @@ -718,6 +734,7 @@ When using the SSE (`-t sse`) or streamable HTTP (`-t streamable-http`) transpor
**Endpoint:** `GET /healthz`

**Response:**

- Status Code: `200 OK`
- Body: `ok`

Expand Down
Loading