Install
$ agentstack add mcp-lukleh-mcp-read-only-grafana ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
MCP Read-Only Grafana Server
[](https://github.com/lukleh/mcp-read-only-grafana/actions/workflows/test.yml)
A secure MCP (Model Context Protocol) server for Grafana with a read-only default and a separate mcp-grafana-write command for write-capable workflows.
> Default layout: > - Live config: ~/.config/lukleh/mcp-read-only-grafana/connections.yaml > - Credentials: injected via the MCP client or shell environment > - Rotated session state: ~/.local/state/lukleh/mcp-read-only-grafana/session_tokens.json > - Cache: ~/.cache/lukleh/mcp-read-only-grafana/
Compatibility: Targeted and tested against Grafana 9.5.x. Newer versions (e.g., 10.x) should work for read-only endpoints but may expose extra fields not covered here.
Features
- Read-only by default -
mcp-read-only-grafanaexposes the safe default surface - Separate write command -
mcp-grafana-writeenables dashboard saves, alerting writes, folders, and related mutations from the same package - API key first authentication - Prefers Grafana API keys or service-account tokens for stable machine access
- Deprecated session-cookie fallback - Still supports Grafana session cookies, including automatic capture of rotated cookies in
session_tokens.json - Hierarchical dashboard navigation - Handle large dashboards efficiently with lightweight metadata queries and per-panel detail fetching
- Multiple instances - Support for multiple Grafana connections
- Comprehensive API coverage - Access dashboards, panels, folders, datasources, and alerts
- Security focused - Timeouts, SSL verification, and secure token storage
Prerequisites
- Python 3.11 or higher
- uv
- Grafana credentials for at least one instance
- an MCP client such as Claude Code or Codex
Quick Start
1. Install the Server
# Run the published package without cloning the repository
uvx mcp-read-only-grafana@latest --write-sample-config
# Or install it once and reuse the command directly
uv tool install mcp-read-only-grafana
mcp-read-only-grafana --write-sample-config
# The same install also provides the separate write-capable command
mcp-grafana-write --print-paths
When using uvx, prefer mcp-read-only-grafana@latest in user-facing docs and MCP client configs. This avoids reusing a stale cached tool environment after a new release is published. For the separate write-capable command, use uvx --from mcp-read-only-grafana@latest mcp-grafana-write.
The command above writes a starter config and matching schema to:
~/.config/lukleh/mcp-read-only-grafana/connections.yaml~/.config/lukleh/mcp-read-only-grafana/connections.schema.json
The live runtime config file used by the installed server is ~/.config/lukleh/mcp-read-only-grafana/connections.yaml.
2. Confirm Runtime Paths
uvx mcp-read-only-grafana@latest --print-paths
Where connections.yaml Lives
By default, the server reads the live runtime config from:
~/.config/lukleh/mcp-read-only-grafana/connections.yaml
On this machine, that expands to:
/Users//.config/lukleh/mcp-read-only-grafana/connections.yaml
Important distinction:
- The live runtime file is
~/.config/lukleh/mcp-read-only-grafana/connections.yaml - The checked-in repo sample is [
connections.yaml.sample](connections.yaml.sample)
The sample file documents the format, but it is not the file the installed server reads unless you explicitly copy or generate it into the runtime config directory.
3. Edit the Connections File
Edit ~/.config/lukleh/mcp-read-only-grafana/connections.yaml with your Grafana instances:
- connection_name: production_grafana
url: https://grafana.example.com
description: Production Grafana instance
api_key: glsa_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- connection_name: staging_grafana
url: https://staging-grafana.example.com
description: Staging Grafana instance
4. Set Up Authentication
You can keep credentials either directly in connections.yaml or in the environment used to launch the server. Prefer api_key for normal use. For local shell testing you can export credentials directly; for normal MCP use, inject them through the client config when you want runtime overrides.
YAML credentials:
- connection_name: production_grafana
url: https://grafana.example.com
api_key: glsa_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
You can authenticate with either a Grafana API key or a deprecated session cookie fallback:
- API key or service-account token:
``bash export GRAFANA_API_KEY_PRODUCTION_GRAFANA=your_api_key_here ``
- Deprecated session cookie fallback:
``bash export GRAFANA_SESSION_PRODUCTION_GRAFANA=your_session_token_here ``
Precedence is:
- Rotated session cookies in
session_tokens.json - Runtime environment variables
- Credentials declared in
connections.yaml
If both a session token and an API key are available for the same connection, the server prefers the API key.
Deprecated: How to Get a Grafana Session Token
- Log in to Grafana in a web browser
- Open developer tools
- Go to Application/Storage -> Cookies
- Find the cookie named
grafana_sessionorgrafana_sess - Copy the value and export or inject it as
GRAFANA_SESSION_
Use this only as a temporary fallback. Browser session cookies rotate and expire quickly, so they are less reliable than API keys for MCP usage.
How to Get a Grafana API Key
- In Grafana, go to Administration -> Service Accounts or Configuration -> API Keys
- Create a key with the minimum required permissions
- Export or inject it as
GRAFANA_API_KEY_
If you start with a session cookie, the server will keep refreshed cookies in ~/.local/state/lukleh/mcp-read-only-grafana/session_tokens.json. On later requests, that persisted state file takes precedence over the live GRAFANA_SESSION_* environment value and any static session_token in connections.yaml until you update or remove it.
5. Configure Your MCP Client
Claude Code
claude mcp add mcp-read-only-grafana \
--scope user \
-e GRAFANA_API_KEY_PRODUCTION_GRAFANA=your_api_key_here \
-- uvx mcp-read-only-grafana@latest
Codex
codex mcp add mcp-read-only-grafana \
--env GRAFANA_API_KEY_PRODUCTION_GRAFANA=your_api_key_here \
-- uvx mcp-read-only-grafana@latest
If you absolutely need the deprecated session-cookie fallback, swap GRAFANA_API_KEY_* for GRAFANA_SESSION_* in the MCP client config.
If you want the write-capable endpoints, launch the separate write command from the same package:
uvx --from mcp-read-only-grafana@latest mcp-grafana-write
For a persistent install created with uv tool install mcp-read-only-grafana, run mcp-grafana-write directly.
6. Restart and Test
Restart your MCP client and try a simple query such as:
List all dashboards in the production Grafana instance.
Command Line Testing
# Show the resolved runtime paths
uvx mcp-read-only-grafana@latest --print-paths
# Write or refresh the default connections.yaml
uvx mcp-read-only-grafana@latest --write-sample-config
uvx mcp-read-only-grafana@latest --write-sample-config --overwrite
# Run the server with the default home-directory config
uvx mcp-read-only-grafana@latest
# Run the separate write-capable command from the same package
uvx --from mcp-read-only-grafana@latest mcp-grafana-write
# Point the server at a different config root
uvx mcp-read-only-grafana@latest --config-dir /path/to/config-dir
# Validate the generated configuration
uvx mcp-read-only-grafana@latest validate-config
# Test all configured Grafana connections
uvx mcp-read-only-grafana@latest test-connection
# Test one specific connection
uvx mcp-read-only-grafana@latest test-connection production_grafana
Local Development
If you want to work on the repository itself:
git clone https://github.com/lukleh/mcp-read-only-grafana.git
cd mcp-read-only-grafana
uv sync --extra dev
uv run pytest -q
uv run mcp-read-only-grafana --print-paths
uv run mcp-grafana-write --print-paths
The checked-in sample file remains available at [connections.yaml.sample](connections.yaml.sample) for documentation and review, but package users should prefer --write-sample-config.
Even during local development, the server still uses the resolved runtime config path by default. It does not automatically read the repo's connections.yaml.sample.
Available MCP Tools
list_connections
List all configured Grafana instances.
Returns: JSON with connection names, URLs, and descriptions
get_health
Check Grafana instance health and version.
Parameters:
connection_name(required): Name of the Grafana connection
Returns: Health status and version information
search_dashboards
Search for dashboards by name or tag.
Parameters:
connection_name(required): Name of the Grafana connectionquery(optional): Search query for dashboard namestag(optional): Tag to filter dashboardslimit(optional): Maximum results per page (Grafana default 1000, max 5000)page(optional): Page number (1-indexed)fields(optional): Subset of Grafana fields to return (e.g.,uid,title,url,type,tags,folderTitle,folderUid)
Returns: List of matching dashboards with UIDs, titles, and tags
get_dashboard_info
Get lightweight dashboard metadata and panel list (without full panel definitions). Recommended first step for exploring dashboards, especially large ones.
Parameters:
connection_name(required): Name of the Grafana connectiondashboard_uid(required): UID of the dashboard
Returns: Dashboard metadata, variables, and list of all panels with basic info
get_dashboard_panel
Get full configuration for a single panel from a dashboard. Use this after get_dashboard_info() to explore specific panels in detail.
Parameters:
connection_name(required): Name of the Grafana connectiondashboard_uid(required): UID of the dashboardpanel_id(required): Panel ID to retrieve
Returns: Full panel JSON including queries, transformations, and field config
get_dashboard
Get complete dashboard definition. Use with caution for large dashboards - may exceed token limits. Prefer get_dashboard_info() + get_dashboard_panel() for large dashboards.
Parameters:
connection_name(required): Name of the Grafana connectiondashboard_uid(required): UID of the dashboard
Returns: Full dashboard JSON including panels, variables, and settings
get_dashboard_panels
Get simplified panel information from a dashboard. Returns basic panel metadata without full configuration.
Parameters:
connection_name(required): Name of the Grafana connectiondashboard_uid(required): UID of the dashboard
Returns: List of panels with IDs, titles, types, and descriptions
list_folders
List all folders in Grafana.
Parameters:
connection_name(required): Name of the Grafana connection
Returns: Folder hierarchy with IDs and titles
list_folder_dashboards
List all dashboards within a specific folder.
Parameters:
connection_name(required): Name of the Grafana connectionfolder_uid(required): UID of the folderlimit(optional): Maximum results per pagepage(optional): Page numberfields(optional): Subset of Grafana fields (e.g.,uid,title,url,tags,folderUid)
Returns: List of dashboards in the folder with UIDs, titles, and URLs
list_datasources
List configured data sources.
Parameters:
connection_name(required): Name of the Grafana connection
Returns: Data source names, types, UIDs, and configuration
get_datasource_health
Run the datasource-specific Grafana health check when the datasource plugin supports it.
> Note: Not every datasource plugin implements GET /api/datasources/uid/:uid/health. When Grafana returns 404, the MCP returns a structured unsupported or not_found result instead of surfacing the raw error.
Parameters:
connection_name(required): Name of the Grafana connectiondatasource_uid(required): UID of the datasource
Returns: Health information for supported datasources, or a structured explanation when the health endpoint is unavailable
query_prometheus
Execute a PromQL query against a Prometheus datasource.
Parameters:
connection_name(required): Name of the Grafana connectiondatasource_uid(required): UID of the Prometheus datasourcequery(required): PromQL query stringtime_from(optional): Start time (RFC3339 or relative like "now-1h")time_to(optional): End time (RFC3339 or "now")step(optional): Query resolution step (e.g., "15s", "1m")
Returns: Query results with timestamps and values
query_loki
Execute a LogQL query against a Loki datasource.
Parameters:
connection_name(required): Name of the Grafana connectiondatasource_uid(required): UID of the Loki datasourcequery(required): LogQL query stringtime_from(optional): Start time (RFC3339 or relative like "now-1h")time_to(optional): End time (RFC3339 or "now")limit(optional): Maximum number of log lines (default: 100)
Returns: Log query results with timestamps and log lines
explore_query
Execute Grafana Explore queries via the /api/ds/query endpoint.
> Note: This is the only tool that issues an HTTP POST (required by Grafana Explore). The call is still read-only and does not mutate Grafana state.
Parameters:
connection_name(required): Name of the Grafana connectionqueries(required): List of Explore query definitions (including datasource,refId, etc.)range_from(optional): Relative or absolute start time (e.g.,now-6h)range_to(optional): End time (e.g.,now)max_data_points(optional): Maximum number of datapoints to requestinterval_ms(optional): Query interval in millisecondsadditional_options(optional): Extra request fields that must not overlap with reserved keys
Returns: Raw Explore results as returned by Grafana
list_alerts
List alert rules.
Parameters:
connection_name(required): Name of the Grafana connectionfolder_uid(optional): Filter alerts by folder
Returns: Alert rules with status and conditions
get_alert_rule_by_uid
Get a specific alert rule by its UID.
Parameters:
connection_name(required): Name of the Grafana connectionalert_uid(required): UID of the alert rule
Returns: Alert rule details including conditions, labels, and annotations
get_alert_rules_with_state
Get all alert rules with their current evaluation state. This is the same endpoint used by Grafana's Alert List panel - useful for checking if an alert is working after creation.
Parameters:
connection_name(required): Name of the Grafana connectionstate(optional): Filter by state (e.g., "firing", "pending", "inactive")rule_name(optional): Filter by rule name (partial match)
Returns: Rules organized by namespace with current state (Normal, Pending, Alerting, NoData, Error), health status, and evaluation info
get_firing_alerts
Get currently firing alert instances from Alertmanager. Returns alerts that have transitioned from Pending to Firing state.
Parameters:
connection_name(required): Name of the Grafana connectionfilter_labels(optional): Label matchers (e.g.,["alertname=HighCPU", "severity=critical"])silenced(optional): Include silenced alerts (default: true)inhibited(optional): Include inhibited alerts (default: true)active(optional): Include active alerts (default: true)
Returns: List of firing alert instances with labels, annotations, startsAt, and other metadata
`getalertstate_history
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: lukleh
- Source: lukleh/mcp-read-only-grafana
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.