---
Executes Grafana operations via REST API for dashboards, datasources, alerts, and queries.
/plugin marketplace add shepherdjerred/monorepo/plugin install jerred@shepherdjerredComplete Grafana operations via REST API. This skill replaces Grafana MCP server functionality, providing API equivalents for all operations.
| MCP Tool | API Equivalent |
|---|---|
search_dashboards | curl "$URL/api/search?query=..." |
get_dashboard_by_uid | curl "$URL/api/dashboards/uid/{uid}" |
get_dashboard_summary | Parse dashboard JSON response |
get_dashboard_property | jq on dashboard JSON |
get_dashboard_panel_queries | Extract from dashboard JSON |
update_dashboard | curl -X POST "$URL/api/dashboards/db" |
list_datasources | curl "$URL/api/datasources" |
get_datasource_by_uid | curl "$URL/api/datasources/uid/{uid}" |
get_datasource_by_name | curl "$URL/api/datasources/name/{name}" |
query_prometheus | curl "$URL/api/ds/query" |
list_prometheus_metric_names | curl "$URL/api/datasources/proxy/{id}/api/v1/label/__name__/values" |
list_prometheus_label_names | curl "$URL/api/datasources/proxy/{id}/api/v1/labels" |
list_prometheus_label_values | curl "$URL/api/datasources/proxy/{id}/api/v1/label/{name}/values" |
list_prometheus_metric_metadata | curl "$URL/api/datasources/proxy/{id}/api/v1/metadata" |
query_loki_logs | curl "$URL/api/ds/query" |
query_loki_stats | curl "$URL/api/datasources/proxy/{id}/loki/api/v1/index/stats" |
list_loki_label_names | curl "$URL/api/datasources/proxy/{id}/loki/api/v1/labels" |
list_loki_label_values | curl "$URL/api/datasources/proxy/{id}/loki/api/v1/label/{name}/values" |
list_alert_rules | curl "$URL/api/v1/provisioning/alert-rules" |
get_alert_rule_by_uid | curl "$URL/api/v1/provisioning/alert-rules/{uid}" |
create_alert_rule | curl -X POST "$URL/api/v1/provisioning/alert-rules" |
update_alert_rule | curl -X PUT "$URL/api/v1/provisioning/alert-rules/{uid}" |
delete_alert_rule | curl -X DELETE "$URL/api/v1/provisioning/alert-rules/{uid}" |
list_contact_points | curl "$URL/api/v1/provisioning/contact-points" |
get_annotations | curl "$URL/api/annotations" |
create_annotation | curl -X POST "$URL/api/annotations" |
update_annotation | curl -X PUT "$URL/api/annotations/{id}" |
patch_annotation | curl -X PATCH "$URL/api/annotations/{id}" |
create_graphite_annotation | curl -X POST "$URL/api/annotations/graphite" |
get_annotation_tags | curl "$URL/api/annotations/tags" |
create_folder | curl -X POST "$URL/api/folders" |
search_folders | curl "$URL/api/search?type=dash-folder" |
list_sift_investigations | curl "$URL/api/plugins/grafana-sift-app/resources/investigations" |
get_sift_investigation | curl "$URL/api/plugins/grafana-sift-app/resources/investigations/{id}" |
get_sift_analysis | curl "$URL/api/plugins/grafana-sift-app/resources/investigations/{id}/analyses/{id}" |
find_error_pattern_logs | Via Sift plugin API |
find_slow_requests | Via Sift plugin API |
get_assertions | Via Asserts plugin API |
# Set environment variables
export GRAFANA_URL="https://your-grafana.com"
export GRAFANA_API_KEY="your-api-key"
# Or use service account token
export GRAFANA_TOKEN="glsa_..."
# Auth header helper
AUTH="Authorization: Bearer $GRAFANA_API_KEY"
# Test connection
curl -H "$AUTH" "$GRAFANA_URL/api/health"
# Search all dashboards
curl -H "$AUTH" "$GRAFANA_URL/api/search?type=dash-db"
# Search by query
curl -H "$AUTH" "$GRAFANA_URL/api/search?query=kubernetes"
# Search by tag
curl -H "$AUTH" "$GRAFANA_URL/api/search?tag=monitoring"
# Search in folder
curl -H "$AUTH" "$GRAFANA_URL/api/search?folderIds=1,2"
# Search starred dashboards
curl -H "$AUTH" "$GRAFANA_URL/api/search?starred=true"
# JSON output with jq
curl -H "$AUTH" "$GRAFANA_URL/api/search?query=api" | \
jq '.[] | {uid, title, folderTitle}'
# Get full dashboard
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}"
# Extract just the dashboard JSON
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}" | jq '.dashboard'
# Get dashboard metadata
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}" | jq '.meta'
# Get summary info (title, panel count, etc.)
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}" | \
jq '{
title: .dashboard.title,
uid: .dashboard.uid,
panelCount: (.dashboard.panels | length),
tags: .dashboard.tags,
folder: .meta.folderTitle,
url: .meta.url
}'
# Get title
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}" | jq '.dashboard.title'
# Get all panel titles
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}" | jq '.dashboard.panels[].title'
# Get first panel
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}" | jq '.dashboard.panels[0]'
# Get templating variables
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}" | jq '.dashboard.templating.list'
# Get all queries from panels
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}" | \
jq '.dashboard.panels[].targets[]?.expr // empty'
# Extract panel queries with datasource info
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}" | \
jq '.dashboard.panels[] | {
title: .title,
type: .type,
datasource: .datasource,
queries: [.targets[]? | {expr: .expr, refId: .refId}]
}'
# Create/update dashboard
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/dashboards/db" \
-d '{
"dashboard": {
"title": "My Dashboard",
"tags": ["monitoring"],
"panels": [],
"schemaVersion": 36,
"version": 0
},
"folderUid": "folder-uid",
"message": "Initial version",
"overwrite": false
}'
# Update existing (with overwrite)
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/dashboards/db" \
-d '{
"dashboard": {...},
"overwrite": true
}'
curl -X DELETE -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/{uid}"
# List all folders
curl -H "$AUTH" "$GRAFANA_URL/api/search?type=dash-folder"
# Get folder by UID
curl -H "$AUTH" "$GRAFANA_URL/api/folders/{uid}"
# List folders
curl -H "$AUTH" "$GRAFANA_URL/api/folders"
# Create folder
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/folders" \
-d '{
"title": "My Folder"
}'
# Create with custom UID
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/folders" \
-d '{
"uid": "my-folder-uid",
"title": "My Folder"
}'
# Create nested folder (under parent)
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/folders" \
-d '{
"title": "Child Folder",
"parentUid": "parent-folder-uid"
}'
# List all datasources
curl -H "$AUTH" "$GRAFANA_URL/api/datasources"
# List with details
curl -H "$AUTH" "$GRAFANA_URL/api/datasources" | \
jq '.[] | {id, uid, name, type, url, isDefault}'
# Filter by type
curl -H "$AUTH" "$GRAFANA_URL/api/datasources" | \
jq '.[] | select(.type == "prometheus")'
curl -H "$AUTH" "$GRAFANA_URL/api/datasources/uid/{uid}"
curl -H "$AUTH" "$GRAFANA_URL/api/datasources/name/{name}"
curl -H "$AUTH" "$GRAFANA_URL/api/datasources/{id}"
# Using unified query API (recommended)
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/ds/query" \
-d '{
"queries": [{
"refId": "A",
"datasource": {"type": "prometheus", "uid": "datasource-uid"},
"expr": "up",
"instant": false,
"range": true,
"intervalMs": 15000,
"maxDataPoints": 1000
}],
"from": "now-1h",
"to": "now"
}'
# Instant query
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/ds/query" \
-d '{
"queries": [{
"refId": "A",
"datasource": {"type": "prometheus", "uid": "datasource-uid"},
"expr": "up",
"instant": true
}],
"from": "now",
"to": "now"
}'
# Via datasource proxy
DATASOURCE_ID=1
curl -G -H "$AUTH" \
--data-urlencode "query=up" \
--data-urlencode "start=$(date -d '1 hour ago' +%s)" \
--data-urlencode "end=$(date +%s)" \
--data-urlencode "step=60" \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/query_range"
# Get all metric names
curl -H "$AUTH" \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/label/__name__/values"
# Filter by regex (use match[] param)
curl -G -H "$AUTH" \
--data-urlencode 'match[]={__name__=~"http.*"}' \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/label/__name__/values"
# All label names
curl -H "$AUTH" \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/labels"
# Labels for specific metric
curl -G -H "$AUTH" \
--data-urlencode 'match[]={__name__="http_requests_total"}' \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/labels"
# Values for specific label
curl -H "$AUTH" \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/label/job/values"
# Values with filter
curl -G -H "$AUTH" \
--data-urlencode 'match[]={__name__="http_requests_total"}' \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/label/status/values"
# All metadata
curl -H "$AUTH" \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/metadata"
# Specific metric
curl -G -H "$AUTH" \
--data-urlencode "metric=http_requests_total" \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/metadata"
# Using unified query API
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/ds/query" \
-d '{
"queries": [{
"refId": "A",
"datasource": {"type": "loki", "uid": "loki-uid"},
"expr": "{job=\"app\"} |= \"error\"",
"queryType": "range",
"maxLines": 100
}],
"from": "now-1h",
"to": "now"
}'
# Via datasource proxy
LOKI_ID=2
curl -G -H "$AUTH" \
--data-urlencode 'query={job="app"} |= "error"' \
--data-urlencode "start=$(date -d '1 hour ago' +%s)000000000" \
--data-urlencode "end=$(date +%s)000000000" \
--data-urlencode "limit=100" \
"$GRAFANA_URL/api/datasources/proxy/$LOKI_ID/loki/api/v1/query_range"
# Get stream stats
curl -G -H "$AUTH" \
--data-urlencode 'query={job="app"}' \
--data-urlencode "start=$(date -d '1 hour ago' +%s)000000000" \
--data-urlencode "end=$(date +%s)000000000" \
"$GRAFANA_URL/api/datasources/proxy/$LOKI_ID/loki/api/v1/index/stats"
curl -H "$AUTH" \
"$GRAFANA_URL/api/datasources/proxy/$LOKI_ID/loki/api/v1/labels"
# With time range
curl -G -H "$AUTH" \
--data-urlencode "start=$(date -d '1 hour ago' +%s)000000000" \
--data-urlencode "end=$(date +%s)000000000" \
"$GRAFANA_URL/api/datasources/proxy/$LOKI_ID/loki/api/v1/labels"
# Values for label
curl -H "$AUTH" \
"$GRAFANA_URL/api/datasources/proxy/$LOKI_ID/loki/api/v1/label/job/values"
# With time range
curl -G -H "$AUTH" \
--data-urlencode "start=$(date -d '1 hour ago' +%s)000000000" \
--data-urlencode "end=$(date +%s)000000000" \
"$GRAFANA_URL/api/datasources/proxy/$LOKI_ID/loki/api/v1/label/job/values"
# All alert rules
curl -H "$AUTH" "$GRAFANA_URL/api/v1/provisioning/alert-rules"
# Legacy alerting API
curl -H "$AUTH" "$GRAFANA_URL/api/ruler/grafana/api/v1/rules"
# By folder
curl -H "$AUTH" "$GRAFANA_URL/api/ruler/grafana/api/v1/rules/{folderName}"
curl -H "$AUTH" "$GRAFANA_URL/api/v1/provisioning/alert-rules/{uid}"
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/v1/provisioning/alert-rules" \
-d '{
"title": "High CPU Usage",
"ruleGroup": "my-group",
"folderUID": "folder-uid",
"condition": "A",
"data": [{
"refId": "A",
"datasourceUid": "prometheus-uid",
"model": {
"expr": "avg(rate(node_cpu_seconds_total{mode!=\"idle\"}[5m])) > 0.8",
"instant": true
}
}],
"noDataState": "NoData",
"execErrState": "Error",
"for": "5m",
"labels": {"severity": "warning"},
"annotations": {"summary": "CPU usage above 80%"}
}'
curl -X PUT -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/v1/provisioning/alert-rules/{uid}" \
-d '{...}'
curl -X DELETE -H "$AUTH" "$GRAFANA_URL/api/v1/provisioning/alert-rules/{uid}"
curl -H "$AUTH" "$GRAFANA_URL/api/v1/provisioning/contact-points"
# Filter by name
curl -H "$AUTH" "$GRAFANA_URL/api/v1/provisioning/contact-points?name=slack"
# All annotations
curl -H "$AUTH" "$GRAFANA_URL/api/annotations"
# With filters
curl -G -H "$AUTH" \
--data-urlencode "dashboardUID=dashboard-uid" \
--data-urlencode "from=$(date -d '24 hours ago' +%s)000" \
--data-urlencode "to=$(date +%s)000" \
"$GRAFANA_URL/api/annotations"
# By tags
curl -G -H "$AUTH" \
--data-urlencode "tags=deployment" \
"$GRAFANA_URL/api/annotations"
# Limit results
curl -H "$AUTH" "$GRAFANA_URL/api/annotations?limit=100"
# Dashboard annotation
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/annotations" \
-d '{
"dashboardUID": "dashboard-uid",
"panelId": 1,
"time": 1234567890000,
"timeEnd": 1234567900000,
"text": "Deployment started",
"tags": ["deployment", "v1.2.0"]
}'
# Global annotation (no dashboard)
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/annotations" \
-d '{
"time": '$(date +%s)000',
"text": "System maintenance",
"tags": ["maintenance"]
}'
curl -X PUT -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/annotations/{id}" \
-d '{
"text": "Updated annotation text",
"tags": ["updated", "tag"]
}'
curl -X PATCH -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/annotations/{id}" \
-d '{
"text": "Partially updated text"
}'
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/annotations/graphite" \
-d '{
"what": "Deployment",
"tags": ["deploy", "production"],
"when": 1234567890,
"data": "v1.2.0"
}'
curl -H "$AUTH" "$GRAFANA_URL/api/annotations/tags"
# Filter by tag prefix
curl -H "$AUTH" "$GRAFANA_URL/api/annotations/tags?tag=deploy"
curl -X DELETE -H "$AUTH" "$GRAFANA_URL/api/annotations/{id}"
curl -H "$AUTH" \
"$GRAFANA_URL/api/plugins/grafana-sift-app/resources/investigations"
# With limit
curl -H "$AUTH" \
"$GRAFANA_URL/api/plugins/grafana-sift-app/resources/investigations?limit=10"
curl -H "$AUTH" \
"$GRAFANA_URL/api/plugins/grafana-sift-app/resources/investigations/{id}"
curl -H "$AUTH" \
"$GRAFANA_URL/api/plugins/grafana-sift-app/resources/investigations/{investigationId}/analyses/{analysisId}"
# Create investigation for error patterns
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/plugins/grafana-sift-app/resources/investigations" \
-d '{
"name": "Error Pattern Analysis",
"type": "error-patterns",
"labels": {"app": "my-app", "env": "production"},
"start": "2024-01-01T00:00:00Z",
"end": "2024-01-01T01:00:00Z"
}'
# Create investigation for slow requests
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/plugins/grafana-sift-app/resources/investigations" \
-d '{
"name": "Slow Request Analysis",
"type": "slow-requests",
"labels": {"service": "api-gateway"},
"start": "2024-01-01T00:00:00Z",
"end": "2024-01-01T01:00:00Z"
}'
curl -G -H "$AUTH" \
--data-urlencode "entityType=Service" \
--data-urlencode "entityName=my-service" \
--data-urlencode "startTime=2024-01-01T00:00:00Z" \
--data-urlencode "endTime=2024-01-01T01:00:00Z" \
"$GRAFANA_URL/api/plugins/grafana-asserts-app/resources/assertions"
#!/bin/bash
mkdir -p dashboards-backup
curl -H "$AUTH" "$GRAFANA_URL/api/search?type=dash-db" | \
jq -r '.[] | .uid' | \
while read uid; do
echo "Backing up: $uid"
curl -H "$AUTH" "$GRAFANA_URL/api/dashboards/uid/$uid" | \
jq '.dashboard' > "dashboards-backup/${uid}.json"
done
#!/bin/bash
echo "=== System Health ==="
# CPU usage
curl -sG -H "$AUTH" \
--data-urlencode 'query=100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)' \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/query" | \
jq -r '.data.result[0].value[1] | "CPU: \(.)%"'
# Memory usage
curl -sG -H "$AUTH" \
--data-urlencode 'query=100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)' \
"$GRAFANA_URL/api/datasources/proxy/$DATASOURCE_ID/api/v1/query" | \
jq -r '.data.result[0].value[1] | "Memory: \(.)%"'
#!/bin/bash
VERSION=$1
curl -X POST -H "$AUTH" -H "Content-Type: application/json" \
"$GRAFANA_URL/api/annotations" \
-d "{
\"time\": $(date +%s)000,
\"text\": \"Deployed version $VERSION\",
\"tags\": [\"deployment\", \"$VERSION\"]
}"
# CPU usage
rate(node_cpu_seconds_total{mode!="idle"}[5m])
# Memory usage
node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes
# HTTP request rate
rate(http_requests_total[5m])
# Error rate percentage
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) * 100
# Latency p95
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# Up/down status
up{job="my-service"}
# Errors in last hour
{job="app"} |= "error"
# JSON parsing
{job="app"} | json | level="error"
# Regex match
{job="app"} |~ "failed.*connection"
# Count by service
sum by (service) (count_over_time({job="app"}[1h]))
# Rate of errors
rate({job="app"} |= "error" [5m])
# Label filtering
{namespace="production", app=~"api-.*"}
Ask the user for clarification when:
Designs feature architectures by analyzing existing codebase patterns and conventions, then providing comprehensive implementation blueprints with specific files to create/modify, component designs, data flows, and build sequences