Skip to content

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

@gargshantnu

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions