feat(mcp): add duplicate_dashboard tool - #40959
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #40959 +/- ##
==========================================
- Coverage 64.48% 64.45% -0.04%
==========================================
Files 2664 2665 +1
Lines 146083 146353 +270
Branches 33698 33729 +31
==========================================
+ Hits 94207 94329 +122
- Misses 50168 50305 +137
- Partials 1708 1719 +11
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Code Review Agent Run #e866e5Actionable Suggestions - 0Additional Suggestions - 2
Filtered by Review RulesBito filtered these suggestions based on rules created automatically for your feedback. Manage rules.
Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Code Review Agent Run #fe4939Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
Code Review Agent Run #9d6b93Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
5e9923e to
96fd06f
Compare
Code Review Agent Run #98b6beActionable Suggestions - 0Additional Suggestions - 1
Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
2c88975 to
05dabda
Compare
Adds a duplicate_dashboard MCP tool that clones an existing dashboard via CopyDashboardCommand. The source dashboard can be identified by numeric ID, UUID, or slug. By default the copy references the same charts; duplicate_slices=true deep-copies every chart into new objects owned by the caller. The tool builds the required json_metadata payload (source metadata plus a positions key from position_json), mirroring what the frontend "Save as" flow sends to the /copy/ endpoint. The new title is sanitized for XSS, and the tool is excluded from MCP response caching.
Address review feedback: emit ctx.warning on not-found / access-denied early returns for observability parity, and add dedicated schema unit tests for DuplicateDashboardRequest sanitization and DuplicateDashboardResponse error wrapping.
Address review feedback on duplicate_dashboard: - Route the new dashboard's response through _sanitize_dashboard_info_for_llm_context so user-controlled title, description, chart, and tag text are wrapped as untrusted before reaching LLM context, matching the standard dashboard serializers. - Fail fast when the source has charts but its layout maps none: an empty/invalid position_json would otherwise make set_dash_metadata rebuild the copy with zero slices, silently producing an empty copy. - Add tests for both paths and docstrings/type hints on new test code.
The post-copy re-fetch's SQLAlchemyError handler returned a minimal response without rolling back the failed transaction, leaving the shared db.session in an invalid state for the rest of the request lifecycle. Mirror the recovery pattern already used by generate_dashboard and add_chart_to_existing_dashboard. Add a regression test asserting the rollback runs and the fallback response is still produced.
CopyDashboardCommand re-parses the source's stored params/json_metadata via set_dash_metadata; on malformed JSON this raises ValueError/ JSONDecodeError, which the transaction handler does not wrap as DashboardCopyError (it only catches SQLAlchemyError). The error escaped as a hard tool failure instead of a structured response. Catch the parse error and return a normal DuplicateDashboardResponse error. Also extract _resolve_source / _refetch_and_serialize / _safe_rollback helpers to keep duplicate_dashboard under the C901 complexity limit, and add a regression test for the malformed-metadata path.
…ilure _resolve_source only caught DashboardNotFoundError/AccessDeniedError, so a transient SQLAlchemyError from get_by_id_or_slug propagated to the broad except Exception and re-raised as a hard tool failure. Catch SQLAlchemyError during lookup, roll back, log with traceback, and return a generic structured error (no DB-internal leak), matching generate_dashboard and update_dashboard. Add a regression test.
d36e38c to
594d264
Compare
Code Review Agent Run #2e5f2dActionable Suggestions - 0Additional Suggestions - 3
Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
When the source dashboard's json_metadata cannot be decoded or is not a
JSON object, surface a non-fatal warning in the response rather than
silently defaulting to {{}}, so callers know the duplicate's aesthetic
settings (colors, native filters, etc.) were reset to defaults while
chart content was preserved. Adds a regression test.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n duplicate_dashboard
- Replace _positions_reference_charts (bool) with _get_layout_chart_ids
(frozenset[int]) so callers can cross-reference against source.slices.
A layout that references chart IDs that don't exist on the source would
silently produce a copy with no charts; the tool now fails fast with a
structured error and directs the user to repair the source dashboard.
- Remove the try/except that silently defaulted malformed json_metadata
to {}. A dashboard with unparseable json_metadata would lose its
filter config, color scheme, and other settings in the copy; letting
JSONDecodeError (a ValueError subclass) propagate to the outer
(ValueError, TypeError) handler produces the same structured "metadata
is invalid" error as the CopyDashboardCommand parse-failure path.
- Update tests: rename test_malformed_json_metadata_warns_not_fails to
test_malformed_json_metadata_in_source_returns_structured_error and
flip expectations from warn-and-succeed to fail-fast; add new test
test_stale_layout_chart_ids_returns_structured_error.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
``set_dash_metadata`` can raise ``KeyError`` when a position layout node is missing expected keys (e.g. ``node['meta']['chartId']`` on a malformed CHART entry). Add ``KeyError`` to the ``(ValueError, TypeError)`` handler so a corrupted source layout produces a structured error response instead of an unhandled exception. Also add ``dashboard_id`` to the ctx.error log message in this handler for consistency with all other error branches. Add regression test ``test_key_error_in_copy_command_returns_structured_error``. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
These two guards (empty/stale layout) don't exist on the REST /copy/ endpoint, which would just produce the copy. Dashboards created via API or import can legitimately carry slices without position_json entries; for those this tool now hard-fails where "Save as" would succeed. I'm fine with the fail-fast, but please call out this intentional divergence in the docstring/PR description. |
Code Review Agent Run #c47b56Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
SUMMARY
Adds a new
duplicate_dashboardMCP tool to the Superset MCP service. The canonical AI workflow this enables: "create a regional/staging variant of this dashboard" — clone a template dashboard, then edit the copy.Design:
CopyDashboardCommand(the same backend used by the frontend "Save as" flow on/api/v1/dashboard/<id>/copy/).DashboardDAO.get_by_id_or_slug, which applies dashboard access filters).DashboardCopySchema's copy data contract requiresjson_metadata; the tool builds it server-side from the source dashboard's current state (json_metadataplus apositionskey fromposition_json), mirroring exactly what the frontend "Save as" sends.json_metadatais intentionally not exposed as a tool parameter.duplicate_slices: bool = false— when true, every chart on the source dashboard is deep-copied into a new chart object owned by the caller; when false the copy references the same charts.generate_dashboard(nh3-basedsanitize_user_input), with a warning surfaced when content is stripped and a hard error when the title sanitizes to nothing.DASHBOARD_RBAC), and copy failures; errors are wrapped for LLM-context safety.mutatetool (class_permission_name="Dashboard",method_permission_name="write") and added toMCP_CACHE_CONFIG["excluded_tools"]so responses are never cached.BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
N/A — MCP service tool, no UI changes.
TESTING INSTRUCTIONS
duplicate_dashboardwith{"dashboard_id": <existing id|uuid|slug>, "dashboard_title": "My Copy"}— verify a new dashboard is created referencing the same charts, and the returned URL opens it."duplicate_slices": true— verify the new dashboard contains new chart objects (different chart IDs) with the same layout.pytest tests/unit_tests/mcp_service/dashboard/tool/test_duplicate_dashboard.pyADDITIONAL INFORMATION