gkneighb opened a new pull request, #40399:
URL: https://github.com/apache/superset/pull/40399
### SUMMARY
`generate_dashboard` previously accepted only `chart_ids`,
`dashboard_title`, `description`, and `published`. The layout was
auto-generated from chart ids; theme (`label_colors`, `color_scheme`,
`cross_filters_enabled`) and `css` were hardcoded defaults. As a result, LLMs
building dashboards through MCP could only produce auto-layout, default-styled
artifacts. Any brand styling, custom row composition, `MARKDOWN` / `HEADER`
components, or chrome-hiding CSS required falling back to raw REST.
There was also no `update_dashboard` tool, so once a dashboard existed via
MCP, the only way to change its layout or theme was again raw REST.
This PR exposes the REST-side composition primitives — `position_json`,
`json_metadata`, and `css` — through two MCP entry points.
### BEFORE/AFTER
**Before:**
```
generate_dashboard({chart_ids: [...], dashboard_title: "..."})
→ Dashboard with auto-generated layout, default theme, no slug, no CSS
To customize: fall back to raw REST PUT /api/v1/dashboard/{id}
```
**After:**
```
generate_dashboard({
chart_ids: [81, 80, 78, 79],
dashboard_title: "Q4 Executive Review",
slug: "q4-exec-review",
position_json: {"ROOT_ID": {...}, "GRID_ID": {...}, ...},
json_metadata_overrides: {
label_colors: {"Electronics": "#4C78A8", "Furniture": "#E45756"},
cross_filters_enabled: false
},
css: ".header-controls{display:none}",
})
→ Dashboard with the custom layout, theme, slug, and CSS all applied
```
Or patch an existing dashboard's theme later:
```
update_dashboard({
identifier: 42,
json_metadata_overrides: {label_colors: {"Office Supplies": "#54A24B"}},
css: ".chart-header{padding:8px}",
})
```
### CHANGES
**Two new entry points:**
1. **`generate_dashboard`** — four new optional fields:
- `position_json: dict | None` — explicit layout (replaces auto-gen)
- `json_metadata_overrides: dict | None` — shallow-merged on top of
default json_metadata (label_colors, color_scheme, cross_filters_enabled,
shared_label_colors, etc.)
- `css: str | None` — dashboard-level CSS
- `slug: str | None` — URL slug
All optional. Omit to get the existing auto-generated behavior. Fully
backward-compatible.
2. **`update_dashboard`** — new mutate tool. Accepts the same
layout/theme/CSS fields plus title, description, slug, published. Only the
fields explicitly passed are applied; `json_metadata_overrides` is
shallow-merged with the existing metadata. Empty string on slug/css explicitly
clears.
**File changes:**
| File | Change |
|---|---|
| `superset/mcp_service/dashboard/schemas.py` | `GenerateDashboardRequest`
adds 4 fields; new `UpdateDashboardRequest` schema |
| `superset/mcp_service/dashboard/tool/generate_dashboard.py` | Wires the 4
new fields through to the dashboard model write |
| `superset/mcp_service/dashboard/tool/update_dashboard.py` | NEW tool —
looks up by id/uuid/slug via `DashboardDAO.get_by_id_or_slug`, applies only
explicitly-passed fields, returns structured `DashboardError` on not-found |
| `superset/mcp_service/dashboard/tool/__init__.py` +
`superset/mcp_service/app.py` | Register `update_dashboard` |
### TESTING INSTRUCTIONS
```bash
pytest tests/unit_tests/mcp_service/dashboard/
```
Specifically:
-
`tests/unit_tests/mcp_service/dashboard/test_dashboard_schemas.py::TestGenerateDashboardRequestLayoutTheme`
— 6 tests covering the 4 new optional fields
-
`tests/unit_tests/mcp_service/dashboard/test_dashboard_schemas.py::TestUpdateDashboardRequest`
— 7 tests covering the new schema
- `tests/unit_tests/mcp_service/dashboard/tool/test_update_dashboard.py` — 5
async tests covering happy-path update, no-op behavior, not-found,
title/slug/published combo, empty-slug clears
**142 dashboard tests pass; zero regressions.**
End-to-end verified against a live Superset:
- `generate_dashboard` with custom `position_json` + `label_colors` +
`cross_filters_enabled` + `css` + `slug` → all four fields land in DB
- `update_dashboard` patches title + json_metadata + css on an existing
dashboard
- no-op update returns a clear warning
- not-found identifier returns structured `DashboardError`
### WHY THIS MATTERS
LLM-driven dashboard construction commonly needs to apply brand palettes,
hide chrome for print-ready exports, and place charts into specific row
arrangements (header rows with side legends, KPI rows, trend+map rows, etc.).
With the old `generate_dashboard`, none of those were reachable in one
round-trip — the LLM would build a dashboard, then have to fall back to raw
REST `PUT /api/v1/dashboard/{id}` to set `position_json`/`css`/`json_metadata`.
That defeats the typed-config story and forces every LLM agent to learn the raw
REST shape.
### ADDITIONAL INFORMATION
- [ ] Has associated issue: _(filing alongside, will link)_
- [ ] Required feature flags: _none_
- [x] Changes UI: _no_
- [x] Includes DB Migration: _no_
- [x] Includes packaged template files: _no_
- [x] Introduces new feature or API: _yes — adds 4 optional fields to
`GenerateDashboardRequest` and a new `update_dashboard` MCP tool_
- [x] Removes existing feature or API: _no_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]