Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
20d99ff
feat(mcp): add structured dashboard text component management
aminghadersohi Sep 23, 2026
f213a0f
test(mcp): verify dashboard text mutation failure boundaries
aminghadersohi Sep 23, 2026
2be8d92
Merge apache/master into aminghadersohi/mcp-dashboard-markdown-tool
aminghadersohi Sep 24, 2026
c06edd9
test(mcp): verify emoji ranges for CodeQL review
aminghadersohi Sep 25, 2026
5dd20ee
Merge remote-tracking branch 'origin/master' into sc-112946-mcp-dashb…
aminghadersohi Sep 27, 2026
8c853ed
test(mcp): budget dashboard markdown tool inventory
aminghadersohi Sep 27, 2026
77be8e1
fix(mcp): constrain markdown widths and resolve nested tabs
aminghadersohi Sep 27, 2026
2e8a633
fix(mcp): account for removals when resizing markdown
aminghadersohi Sep 27, 2026
2cb3e84
fix(mcp): reject empty dashboard component updates
aminghadersohi Sep 27, 2026
56f576d
refactor(mcp): expose shared dashboard layout helpers
aminghadersohi Sep 27, 2026
8849805
Merge branch 'master' into aminghadersohi/mcp-dashboard-markdown-tool
aminghadersohi Oct 1, 2026
e0405ec
fix(mcp): bound markdown height and reject duplicate removals
aminghadersohi Oct 2, 2026
2020711
Merge remote-tracking branch 'origin/master' into mdtool
aminghadersohi Oct 3, 2026
92d68e4
fix(import): drop duplicate config annotation flagged by mypy
aminghadersohi Oct 3, 2026
a335533
fix(mcp): classify manage_dashboard_markdown as scope-neutral
aminghadersohi Oct 3, 2026
0cd982c
fix(mcp): share duplicate-ID and header-text helpers in dashboard mar…
aminghadersohi Oct 3, 2026
04daf09
Merge master into dashboard markdown tool branch
aminghadersohi Oct 5, 2026
896996e
fix(mcp): address manage_dashboard_markdown review feedback
aminghadersohi Oct 6, 2026
e14744f
fix(mcp): flag managed_externally on markdown tool refusal
aminghadersohi Oct 6, 2026
e03c153
Merge branch 'master' into aminghadersohi/mcp-dashboard-markdown-tool
aminghadersohi Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions docs/docs/using-superset/using-ai-with-superset.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,53 @@ JSON, impact reporting still checks its saved form data and other accessible cha
| `delete_dashboard` | Delete a dashboard by ID, UUID, or slug; leaves its charts intact (soft-deletes to trash when `SOFT_DELETE` is enabled; fails if alerts/reports are still attached, checked before editorship; otherwise returns `permission_denied` if the caller isn't an editor of the dashboard — owners, Admins, and explicitly granted editors qualify) |
| `restore_dashboard` | Restore a soft-deleted dashboard from trash by ID or UUID (slug lookup does not cover trashed dashboards); not gated on `SOFT_DELETE`, so rows trashed while it was enabled stay recoverable, but only soft-deleted dashboards can be restored — permanently deleted dashboards are unrecoverable; returns `permission_denied` if the caller can see the dashboard but isn't an editor of it, or `NotFound` if the dashboard is outside the caller's RBAC visibility entirely |

### Dashboard text components

Use `manage_dashboard_markdown` to add, update, or remove markdown tiles,
section headers, and dividers without replacing the dashboard's raw layout.
The caller needs Dashboard write permission and editorship of the dashboard.

```json
{
"request": {
"dashboard_id": 42,
"add": [
{"component_type": "header", "text": "Sales overview"},
{"component_type": "markdown", "code": "**Updated daily**", "width": 12},
{"component_type": "divider"}
]
}
}
```

Markdown tiles are appended in their own rows; headers and dividers are appended
directly to the grid or tab. Each addition can specify `target_tab` by name or
component ID (available from `get_dashboard_layout`), including nested tabs.
Without it, additions use the first top-level tab, or the grid on dashboards
without top-level tabs. Markdown width is 1–12 columns (default 4); height is in
8-pixel grid units (default 50). Width updates
must fit the space remaining beside other components in the same 12-column row;
otherwise, the error reports the available width. Components removed in the same
request do not count toward that row width. If any operation is rejected, the
layout remains unchanged.

The response includes generated `added_component_ids` and a `components` summary.
Reuse those IDs in `update`, for example
`{"id": "MARKDOWN-…", "code": "Revised notes"}`, or in `remove`, for example
`["MARKDOWN-…"]`. Updates merge only supplied non-null fields and cannot change a
component's type or placement. Each update requires at least one non-null field
besides `id`; ID-only or all-null updates are rejected. The reserved dashboard-title `HEADER_ID` is not a
section header and cannot be changed through this tool.

Operations in one request are validated before saving. Existing charts, native
filters, and unrelated dashboard properties are preserved. Removing a tile prunes
empty row/column wrappers but retains tabs. Invalid component IDs, incompatible
fields, invalid layouts, and conflicting update/removal operations return errors
without saving partial changes. Markdown uses the dashboard's existing renderer
and HTML sanitization configuration. Concurrent layout edits are last-write-wins;
avoid simultaneous edits from the UI and MCP clients. This tool does not reorder
or move existing components; use the dashboard editor for those operations.

### SQL

| Tool | Description |
Expand Down
5 changes: 4 additions & 1 deletion superset/mcp_service/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ def get_default_instructions(
- add_chart_to_existing_dashboard: Add a chart to an existing dashboard (requires write access)
- delete_dashboard: Delete a dashboard by ID/UUID/slug (requires editor rights — owner or Admin; destructive; does not delete its charts; soft-deletes to trash when the SOFT_DELETE feature flag is on, permanent otherwise)
- manage_native_filters: Add, update, remove, or reorder native filters on a dashboard (requires write access; supports filter_select, filter_time, filter_range, and filter_timegrain)
- manage_dashboard_markdown: Add, update, or remove markdown/header/divider layout components on a dashboard (requires write access)
- apply_dashboard_filters: Apply values to a dashboard's existing native filters for the calling user and return a shareable permalink (read access; does NOT change the saved dashboard)
- remove_chart_from_dashboard: Remove a chart from an existing dashboard (requires write access)
- restore_dashboard: Restore a soft-deleted dashboard from trash by ID/UUID (requires editor rights — owner or Admin; only applies to dashboards trashed under the SOFT_DELETE feature flag)
Expand Down Expand Up @@ -531,7 +532,8 @@ def get_default_instructions(
create_dataset_metric, delete_dataset_metric, update_dataset_metric,
save_sql_query, add_chart_to_existing_dashboard, manage_native_filters,
remove_chart_from_dashboard, update_chart_preview, manage_dashboard_owners,
manage_dashboard_roles, manage_dashboard_certification) require write
manage_dashboard_roles, manage_dashboard_certification,
manage_dashboard_markdown) require write
permissions. These tools are only listed for users who have the necessary access.
If a write tool does not appear in the tool list, the current user lacks write access.
- execute_sql requires SQL Lab access (execute_sql_query permission), which is separate
Expand Down Expand Up @@ -839,6 +841,7 @@ def create_mcp_app(
get_dashboard_layout,
list_dashboards,
manage_dashboard_certification,
manage_dashboard_markdown,
manage_dashboard_owners,
manage_dashboard_roles,
manage_native_filters,
Expand Down
4 changes: 4 additions & 0 deletions superset/mcp_service/dashboard/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@

GRID_DEFAULT_CHART_WIDTH = 4
GRID_COLUMN_COUNT = 12
GRID_MIN_ROW_UNITS = 5
GRID_MAX_ROW_UNITS = 100
GRID_ID = "GRID_ID"
HEADER_ID = "HEADER_ID"


def generate_id(prefix: str) -> str:
Expand Down
Loading
Loading