lukleh/mcp-read-only-grafana
If you are the rightful owner of mcp-read-only-grafana and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
A secure MCP server providing read-only access to Grafana instances using session authentication.
MCP Read-Only Grafana Server
A secure MCP (Model Context Protocol) server that provides access to Grafana instances using session authentication or API keys.
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 - All operations are read-only unless
--allow-adminis enabled - Optional admin mode - Enable write operations (create/update/delete alerts) with
--allow-adminflag - Session-based authentication - Uses Grafana session cookies for secure access (default) and also supports Grafana API keys
- Automatic token refresh - Grafana rotates session tokens every 10 minutes; the server automatically captures refreshed tokens from response headers and persists them to
.env(session-cookie mode only) - 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
This project requires:
- uv - Fast Python package installer and resolver
- just - Command runner (optional, but recommended for development)
Quick Start
1. Install Dependencies
uv sync
2. Configure Grafana Connections
Copy the sample configuration file:
cp connections.yaml.sample connections.yaml
Edit connections.yaml with your Grafana instances:
- connection_name: production_grafana
url: https://grafana.example.com
description: Production Grafana instance
3. Set Up Authentication
Create a .env file from the sample:
cp .env.sample .env
You can authenticate either with a session cookie (auto-rotated) or with a Grafana API key (Bearer token):
- Session cookie (default, supports automatic rotation & persistence):
GRAFANA_SESSION_PRODUCTION_GRAFANA=your_session_token_here - API key (no rotation; useful for service accounts or Grafana Cloud tokens):
GRAFANA_API_KEY_PRODUCTION_GRAFANA=your_api_key_here
If both are set, the server will prefer the API key.
How to Get Your Grafana Session Token:
- Login to your Grafana instance in a web browser
- Open Developer Tools
- Go to Application/Storage → Cookies
- Find the cookie named
grafana_sessionorgrafana_sess - Copy the value and paste it in the
.envfile
How to Get a Grafana API Key:
- In Grafana, go to Administration → Service Accounts (or Configuration → API Keys on older versions)
- Create a key with the minimum required read permissions
- Copy the generated token (starts with
glsa_or similar) and paste it into.envas shown above
4. Validate and Test Connections
# Validate configuration file
just validate
# Test Grafana connectivity
just test-connection # Test all connections
just test-connection production_grafana # Test specific connection
5. Run the Server
Run the server manually to test:
just run
# Or with a custom config file
just run /path/to/connections.yaml
# Enable admin mode for write operations (alert management)
just run --allow-admin
6. Add MCP to Your AI Assistant
For Claude Code:
claude mcp add mcp-read-only-grafana -- uv --directory {PATH_TO_MCP_READ_ONLY_GRAFANA} run python -m src.server
For Codex:
codex mcp add mcp-read-only-grafana -- uv --directory {PATH_TO_MCP_READ_ONLY_GRAFANA} run python -m src.server
Replace {PATH_TO_MCP_READ_ONLY_GRAFANA} with the absolute path to where you cloned this repository (e.g., /Users/yourname/projects/mcp-read-only-grafana).
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
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
get_alert_state_history
Get alert state transition history. Useful for debugging alert behavior and understanding evaluation patterns.
Parameters:
connection_name(required): Name of the Grafana connectionrule_uid(optional): Filter by specific rule UIDlabels(optional): Label matchers to filter historyfrom_time(optional): Start time (ISO 8601 or relative like "now-1h")to_time(optional): End time (ISO 8601 or relative like "now")limit(optional): Maximum number of history entries
Returns: State history entries with timestamps and state transitions (Normal, Pending, Alerting, NoData, Error)
list_provisioned_alert_rules
Fetch all alert rules through Grafana's provisioning API (GET /api/v1/provisioning/alert-rules) to audit provisioned definitions exactly as stored on the server.
Parameters:
connection_name(required): Name of the Grafana connection
Returns: Provisioned alert rule payload grouped by folder/namespace and alert rule metadata
list_annotations
List annotations (events marked on dashboards).
Parameters:
connection_name(required): Name of the Grafana connectiontime_from(optional): Start time for annotation searchtime_to(optional): End time for annotation searchdashboard_id(optional): Filter by dashboard IDtags(optional): List of tags to filter by
Returns: Annotations with timestamps, text, and tags
get_dashboard_versions
Get version history for a dashboard.
Parameters:
connection_name(required): Name of the Grafana connectiondashboard_uid(required): UID of the dashboard
Returns: List of dashboard versions with timestamps and change messages
get_current_org
Get current organization information.
Parameters:
connection_name(required): Name of the Grafana connection
Returns: Organization name and ID
get_current_user
Return the profile for the currently authenticated Grafana user (name, login, email, role, theme, etc.).
Note: This endpoint only works with session-based authentication. API keys are service account tokens and are not associated with a user profile - calls will return a 404 error when using API key auth.
Parameters:
connection_name(required): Name of the Grafana connection
Returns: User object as provided by GET /api/user
list_users
List all users in the organization.
Parameters:
connection_name(required): Name of the Grafana connectionpage(optional): Page numberper_page(optional): Page sizefields(optional): Subset of Grafana fields (userId,email,name,login,role,lastSeenAt,lastSeenAtAge)
Returns: User list with IDs, names, emails, and roles
list_teams
List all teams in the organization.
Parameters:
connection_name(required): Name of the Grafana connectionpage(optional): Page numberper_page(optional): Page sizefields(optional): Subset of Grafana fields (id,uid,name,email,memberCount)
Returns: Team list with IDs, names, and member counts
Admin Tools (requires --allow-admin)
The following tools are only available when running the server with --allow-admin. They require Grafana admin permissions and enable write operations for alert management.
Warning: These tools can create, modify, and delete Grafana resources. Use with caution.
Alert Rules
create_alert_rule
Create a new alert rule via the provisioning API.
Parameters:
connection_name(required): Name of the Grafana connectionrule(required): Alert rule definition (JSON object)
Returns: Created alert rule with UID
update_alert_rule
Update an existing alert rule.
Parameters:
connection_name(required): Name of the Grafana connectionrule_uid(required): UID of the alert rule to updaterule(required): Updated alert rule definition (JSON object)
Returns: Updated alert rule
delete_alert_rule
Delete an alert rule.
Parameters:
connection_name(required): Name of the Grafana connectionrule_uid(required): UID of the alert rule to delete
Returns: Confirmation of deletion
update_rule_group
Update a rule group's interval configuration.
Parameters:
connection_name(required): Name of the Grafana connectionfolder_uid(required): UID of the folder containing the rule groupgroup_name(required): Name of the rule groupconfig(required): Rule group configuration (JSON object withinterval, etc.)
Returns: Updated rule group configuration
Contact Points
create_contact_point
Create a new contact point for alert notifications.
Parameters:
connection_name(required): Name of the Grafana connectioncontact_point(required): Contact point definition (JSON object)
Returns: Created contact point with UID
update_contact_point
Update an existing contact point.
Parameters:
connection_name(required): Name of the Grafana connectioncontact_point_uid(required): UID of the contact point to updatecontact_point(required): Updated contact point definition (JSON object)
Returns: Updated contact point
delete_contact_point
Delete a contact point.
Parameters:
connection_name(required): Name of the Grafana connectioncontact_point_uid(required): UID of the contact point to delete
Returns: Confirmation of deletion
Notification Policies
set_notification_policies
Set the entire notification policy tree.
Parameters:
connection_name(required): Name of the Grafana connectionpolicies(required): Notification policy tree (JSON object)
Returns: Updated notification policies
delete_notification_policies
Reset notification policies to default.
Parameters:
connection_name(required): Name of the Grafana connection
Returns: Confirmation of reset
Mute Timings
create_mute_timing
Create a new mute timing for silencing alerts.
Parameters:
connection_name(required): Name of the Grafana connectionmute_timing(required): Mute timing definition (JSON object)
Returns: Created mute timing
update_mute_timing
Update an existing mute timing.
Parameters:
connection_name(required): Name of the Grafana connectionmute_timing_name(required): Name of the mute timing to updatemute_timing(required): Updated mute timing definition (JSON object)
Returns: Updated mute timing
delete_mute_timing
Delete a mute timing.
Parameters:
connection_name(required): Name of the Grafana connectionmute_timing_name(required): Name of the mute timing to delete
Returns: Confirmation of deletion
Notification Templates
set_notification_template
Create or update a notification template.
Parameters:
connection_name(required): Name of the Grafana connectiontemplate_name(required): Name of the templatetemplate(required): Template definition (JSON object withtemplatefield)
Returns: Created/updated template
delete_notification_template
Delete a notification template.
Parameters:
connection_name(required): Name of the Grafana connectiontemplate_name(required): Name of the template to delete
Returns: Confirmation of deletion
Configuration Options
Connection Settings
Each connection in connections.yaml supports:
connection_name: Unique identifier (letters, numbers, underscores)url: Grafana instance URL (without trailing slash)description: Human-readable descriptiontimeout: Request timeout in seconds (default: 30)verify_ssl: Verify SSL certificates (default: true)
Environment Variables
GRAFANA_SESSION_<CONNECTION_NAME>: Session token (optional if API key provided)GRAFANA_API_KEY_<CONNECTION_NAME>: Grafana API key / service-account token (optional)GRAFANA_TIMEOUT_<CONNECTION_NAME>: Override timeout for specific connection
Security
The server implements a secure-by-default model:
- Read-only by default - Only GET requests are performed without
--allow-admin - Opt-in admin mode - Write operations require explicit
--allow-adminflag - Timeout protection - Configurable request timeouts (default: 30s)
- SSL verification - Enabled by default for all connections
- Session token security - Tokens stored only in environment variables, never in code
Default Mode (Read-Only)
Without --allow-admin, the server only performs HTTP GET requests:
- GET - Read operations only (dashboards, datasources, alerts, users, teams, etc.)
- POST - Limited to read-only query execution (
/api/ds/queryfor Explore)
It is impossible to modify, create, or delete any Grafana resources in default mode.
Admin Mode (--allow-admin)
When running with --allow-admin, additional write operations are enabled:
- POST - Create new alert rules, contact points, mute timings
- PUT - Update existing alert rules, contact points, notification policies, mute timings, templates
- DELETE - Remove alert rules, contact points, notification policies, mute timings, templates
Warning: Admin mode enables destructive operations. Only enable when you need to manage Grafana alerting resources. The API key or session must have Grafana admin permissions.
Additional Security Considerations
- Credentials are sensitive - Never commit
.envorconnections.yamlto version control - Automatic token refresh - Session tokens are automatically captured and persisted when Grafana rotates them (API keys are static)
- Permission scope - The server inherits the read permissions of the provided session or API key
- No credential storage - Tokens are only stored in environment variables and
.envfile
Troubleshooting
Session Token Management
Automatic Token Refresh: Grafana rotates session tokens every 10 minutes. The server automatically:
- Captures refreshed tokens from Grafana API response headers
- Updates tokens in memory immediately
- Persists new tokens back to
.envfile - No manual token updates needed - the server keeps itself authenticated!
If you manually need to update a token:
- Update the
GRAFANA_SESSION_*value in.env - The new token will be picked up on the next request automatically
- No need to restart the MCP server or Claude Desktop
Authentication Failed
If you get authentication errors despite automatic refresh:
- Verify the initial token is valid in
.env - Check that the
.envfile is writable (needed for automatic token persistence) - Ensure the environment variable name matches the connection name (e.g.,
GRAFANA_SESSION_PRODUCTION_GRAFANAforconnection_name: production_grafana)
Connection Timeout
If requests are timing out:
- Increase the timeout in
connections.yaml - Or set
GRAFANA_TIMEOUT_<CONNECTION_NAME>in.env - Check network connectivity to the Grafana instance
SSL Verification Issues
For self-signed certificates (not recommended for production):
- connection_name: local_grafana
url: https://localhost:3000
verify_ssl: false
Development
Available Commands
See all available commands:
just
Common commands:
just install # Install dependencies
just validate # Validate configuration
just test-connection # Test Grafana connections
just run # Run the server
just lint # Run linter
just lint-fix # Auto-fix linting issues
just format # Format code
just test # Run tests
Running Tests
just test
# or
uv run pytest
Code Formatting
just format
just lint
# or
uv run black src/
uv run ruff check src/
License
MIT License - See LICENSE file for details