Skip to content

Feature Request: Support Grafana 12 Schema v2 Dashboards (TabsLayout / Dynamic Dashboards) #712

Description

@gargshantnu

Feature Request: Support Grafana 12 Schema v2 Dashboards (TabsLayout / Dynamic Dashboards)

Problem

Grafana 12 introduced a new dashboard schema (v2) with a layout property that supports TabsLayout, RowsLayout, GridLayout, and AutoGridLayout. When a user converts a dashboard from the legacy row-based layout to TabsLayout in the Grafana UI, the layout is stored in the dashboard JSON under spec.layout with panels referenced from spec.elements.

The current mcp-grafana tools have two issues with this:

1. Read-side helpers hardcode $.panels[]

The following functions assume the legacy flat panels[] array and return empty/incorrect results for schema v2 dashboards:

  • collectAllPanels (tools/dashboard_helpers.go) — uses safeArray(db, "panels")
  • findPanelByID (tools/dashboard_helpers.go) — uses safeArray(db, "panels")
  • getDashboardSummary (tools/dashboard.go) — uses safeArray(db, "panels")
  • extractPanelSummary (tools/dashboard.go) — looks for type == "row" panels

For a schema v2 dashboard, these return zero panels since panels live in the elements map, not in a top-level panels array.

2. Patch operation examples assume legacy paths

The update_dashboard tool description references paths like $.panels[0].targets[0].expr. For schema v2, the equivalent paths would be $.elements.<element-id>.spec.targets[0].expr or $.layout.spec.tabs[0].spec.layout.spec.items[0]. The existing JSONPath engine would work on these paths, but users have no guidance.

What works today

  • Full JSON pass-through: The update_dashboard tool's full-JSON mode (dashboard parameter) uses interface{} / map[string]interface{} throughout the pipeline, so it passes the layout property to Grafana's API without stripping it.
  • The JSONPath patch engine can operate on any map[string]interface{}, so $.layout.spec.tabs[0] would technically work today — but users don't know this.

Schema v2 structure (for reference)

Legacy (v1):

{
  "panels": [
    {"id": 1, "type": "row", "title": "Tab Name", ...},
    {"id": 2, "type": "timeseries", "targets": [...], ...}
  ]
}

Schema v2 (with TabsLayout):

{
  "elements": {
    "panel-1": {
      "kind": "Panel",
      "spec": {
        "title": "My Panel",
        "vizConfig": { "kind": "timeseries", ... },
        "data": { "spec": { "queries": [...] } }
      }
    }
  },
  "layout": {
    "kind": "TabsLayout",
    "spec": {
      "tabs": [
        {
          "kind": "TabsLayoutTab",
          "spec": {
            "title": "Tab Name",
            "layout": {
              "kind": "GridLayout",
              "spec": {
                "items": [
                  { "kind": "GridLayoutItem", "spec": { "element": { "kind": "ref", "name": "panel-1" }, "x": 0, "y": 0, "width": 12, "height": 8 } }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

Reproduction

  1. Create a dashboard via update_dashboard with row panels (schema v1)
  2. In Grafana 12 UI, switch the dashboard layout from "Rows" to "Tabs" and save
  3. Call get_dashboard_summary or get_dashboard_panel_queries — returns zero panels
  4. Call update_dashboard with operations using $.panels[0] paths — fails since panels array no longer exists

Proposed solution

Minimal (small PR, high value):

Detect schema version by checking for the layout property, then branch in read-side helpers:

  • collectAllPanels: if layout exists, iterate elements map instead of panels[]
  • findPanelByID: search elements map by key
  • getDashboardSummary: traverse layout tree to build panel list with tab/section context
  • extractPanelSummary: handle v2 panel structure (vizConfig.kind instead of type, data.spec.queries instead of targets)

Update update_dashboard tool description with v2 path examples.

Full (larger effort):

Add optional support for the v2beta1 k8s-style API (/apis/dashboard.grafana.app/v2beta1/namespaces/{ns}/dashboards) using the existing KubernetesClient in k8s_client.go. Auto-detect which API to use based on Grafana instance capabilities.

Environment

  • Grafana version: 12.4.2
  • mcp-grafana version: v0.11.4 (also reproduced on commit 9971fcaf from 2026-02-19)
  • Feature toggles: dynamicDashboards enabled

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions