diff --git a/superset/mcp_service/app.py b/superset/mcp_service/app.py index e094a4e9ec7..f518aa41fbe 100644 --- a/superset/mcp_service/app.py +++ b/superset/mcp_service/app.py @@ -222,10 +222,14 @@ Time grain for temporal x-axis (time_grain parameter): - PT1H (hourly), P1D (daily), P1W (weekly), P1M (monthly), P1Y (yearly) Chart Types in Existing Charts (viewable via list_charts/get_chart_info): -- pie, big_number, big_number_total, funnel, gauge_chart -- echarts_timeseries_line, echarts_timeseries_bar, echarts_timeseries_area -- pivot_table_v2, heatmap_v2, sankey_v2, sunburst_v2, treemap_v2 -- word_cloud, world_map, box_plot, bubble, mixed_timeseries +Each chart returned by list_charts / get_chart_info includes a +chart_type_display_name field with a human-readable name. Use that name +when referring to chart types — do NOT expose raw viz_type identifiers. +Common display names: Line Chart, Bar Chart, Area Chart, Scatter Plot, +Pie Chart, Table, Interactive Table, Pivot Table, Big Number, +Big Number with Trendline, Mixed Timeseries Chart, Custom Template Chart, +Funnel Chart, Gauge Chart, Heatmap, Sankey Chart, Sunburst, Treemap, +Word Cloud, World Map, Box Plot, Bubble Chart. Query Examples: - List all tables: diff --git a/superset/mcp_service/chart/plugin.py b/superset/mcp_service/chart/plugin.py index 10c35f1ae84..0221c079032 100644 --- a/superset/mcp_service/chart/plugin.py +++ b/superset/mcp_service/chart/plugin.py @@ -46,6 +46,15 @@ class ChartTypePlugin(Protocol): #: Discriminator value matching ChartConfig's chart_type field. chart_type: str + #: Human-readable name shown to users (e.g. "Line / Bar / Area / Scatter"). + display_name: str + + #: Maps every Superset-internal viz_type this plugin can produce to a + #: user-facing display name, e.g. {"echarts_timeseries_line": "Line Chart"}. + #: Used by the registry to resolve display names for existing charts without + #: needing a separate JSON mapping file. + native_viz_types: dict[str, str] + def pre_validate( self, config: dict[str, Any], @@ -148,6 +157,8 @@ class BaseChartPlugin: """ chart_type: str = "" + display_name: str = "" + native_viz_types: dict[str, str] = {} def pre_validate( self, diff --git a/superset/mcp_service/chart/plugins/big_number.py b/superset/mcp_service/chart/plugins/big_number.py index 00284d58393..6c7fc199f28 100644 --- a/superset/mcp_service/chart/plugins/big_number.py +++ b/superset/mcp_service/chart/plugins/big_number.py @@ -30,6 +30,11 @@ class BigNumberChartPlugin(BaseChartPlugin): """Plugin for big_number chart type.""" chart_type = "big_number" + display_name = "Big Number" + native_viz_types = { + "big_number": "Big Number with Trendline", + "big_number_total": "Big Number", + } def pre_validate( self, diff --git a/superset/mcp_service/chart/plugins/handlebars.py b/superset/mcp_service/chart/plugins/handlebars.py index d03e3a82231..918110a0c37 100644 --- a/superset/mcp_service/chart/plugins/handlebars.py +++ b/superset/mcp_service/chart/plugins/handlebars.py @@ -30,6 +30,10 @@ class HandlebarsChartPlugin(BaseChartPlugin): """Plugin for handlebars chart type (custom HTML template charts).""" chart_type = "handlebars" + display_name = "Handlebars (Custom Template)" + native_viz_types = { + "handlebars": "Custom Template Chart", + } def pre_validate( self, diff --git a/superset/mcp_service/chart/plugins/mixed_timeseries.py b/superset/mcp_service/chart/plugins/mixed_timeseries.py index 0f3dccb340d..1560948701e 100644 --- a/superset/mcp_service/chart/plugins/mixed_timeseries.py +++ b/superset/mcp_service/chart/plugins/mixed_timeseries.py @@ -30,6 +30,10 @@ class MixedTimeseriesChartPlugin(BaseChartPlugin): """Plugin for mixed_timeseries chart type.""" chart_type = "mixed_timeseries" + display_name = "Mixed Timeseries" + native_viz_types = { + "mixed_timeseries": "Mixed Timeseries Chart", + } def pre_validate( self, diff --git a/superset/mcp_service/chart/plugins/pie.py b/superset/mcp_service/chart/plugins/pie.py index fce37567117..132e169b66d 100644 --- a/superset/mcp_service/chart/plugins/pie.py +++ b/superset/mcp_service/chart/plugins/pie.py @@ -30,6 +30,10 @@ class PieChartPlugin(BaseChartPlugin): """Plugin for pie chart type.""" chart_type = "pie" + display_name = "Pie / Donut Chart" + native_viz_types = { + "pie": "Pie Chart", + } def pre_validate( self, diff --git a/superset/mcp_service/chart/plugins/pivot_table.py b/superset/mcp_service/chart/plugins/pivot_table.py index 598de7fa086..c9b55c59115 100644 --- a/superset/mcp_service/chart/plugins/pivot_table.py +++ b/superset/mcp_service/chart/plugins/pivot_table.py @@ -30,6 +30,10 @@ class PivotTableChartPlugin(BaseChartPlugin): """Plugin for pivot_table chart type.""" chart_type = "pivot_table" + display_name = "Pivot Table" + native_viz_types = { + "pivot_table_v2": "Pivot Table", + } def pre_validate( self, diff --git a/superset/mcp_service/chart/plugins/table.py b/superset/mcp_service/chart/plugins/table.py index 87ca1ff0124..16152ef9baf 100644 --- a/superset/mcp_service/chart/plugins/table.py +++ b/superset/mcp_service/chart/plugins/table.py @@ -30,6 +30,11 @@ class TableChartPlugin(BaseChartPlugin): """Plugin for table chart type.""" chart_type = "table" + display_name = "Table" + native_viz_types = { + "table": "Table", + "ag-grid-table": "Interactive Table", + } def pre_validate( self, diff --git a/superset/mcp_service/chart/plugins/xy.py b/superset/mcp_service/chart/plugins/xy.py index 16bdc44a3f7..75eea3f124d 100644 --- a/superset/mcp_service/chart/plugins/xy.py +++ b/superset/mcp_service/chart/plugins/xy.py @@ -30,6 +30,13 @@ class XYChartPlugin(BaseChartPlugin): """Plugin for xy chart type (line, bar, area, scatter).""" chart_type = "xy" + display_name = "Line / Bar / Area / Scatter Chart" + native_viz_types = { + "echarts_timeseries_line": "Line Chart", + "echarts_timeseries_bar": "Bar Chart", + "echarts_area": "Area Chart", + "echarts_timeseries_scatter": "Scatter Plot", + } def pre_validate( self, diff --git a/superset/mcp_service/chart/registry.py b/superset/mcp_service/chart/registry.py index b2f27049482..872a2578e1c 100644 --- a/superset/mcp_service/chart/registry.py +++ b/superset/mcp_service/chart/registry.py @@ -72,6 +72,25 @@ def is_registered(chart_type: str) -> bool: return chart_type in _REGISTRY +def display_name_for_viz_type(viz_type: str) -> str | None: + """Return the user-facing display name for a Superset-internal viz_type. + + Searches every registered plugin's ``native_viz_types`` mapping. + Returns None if no plugin recognises the viz_type. + + Example:: + + display_name_for_viz_type("echarts_timeseries_line") # "Line Chart" + display_name_for_viz_type("pivot_table_v2") # "Pivot Table" + display_name_for_viz_type("unknown_type") # None + """ + for plugin in _REGISTRY.values(): + name = plugin.native_viz_types.get(viz_type) + if name is not None: + return name + return None + + def get_registry() -> "_RegistryProxy": """Return a proxy object for registry access (convenience wrapper).""" return _RegistryProxy() @@ -88,3 +107,6 @@ class _RegistryProxy: def is_registered(self, chart_type: str) -> bool: return chart_type in _REGISTRY + + def display_name_for_viz_type(self, viz_type: str) -> str | None: + return display_name_for_viz_type(viz_type) diff --git a/superset/mcp_service/chart/schemas.py b/superset/mcp_service/chart/schemas.py index 1fdb4f43ab6..05eb858739f 100644 --- a/superset/mcp_service/chart/schemas.py +++ b/superset/mcp_service/chart/schemas.py @@ -101,7 +101,14 @@ class ChartInfo(BaseModel): id: int | None = Field(None, description="Chart ID") slice_name: str | None = Field(None, description="Chart name") - viz_type: str | None = Field(None, description="Visualization type") + viz_type: str | None = Field(None, description="Visualization type (internal ID)") + chart_type_display_name: str | None = Field( + None, + description=( + "User-friendly chart type name (e.g. 'Line Chart', 'Pivot Table'). " + "Use this field when referring to chart types — never expose viz_type." + ), + ) datasource_name: str | None = Field(None, description="Datasource name") datasource_type: str | None = Field(None, description="Datasource type") url: str | None = Field(None, description="Chart explore page URL") @@ -488,11 +495,20 @@ def serialize_chart_object(chart: ChartLike | None) -> ChartInfo | None: # Extract structured filter information filters_info = extract_filters_from_form_data(chart_form_data) + _viz_type = getattr(chart, "viz_type", None) + try: + from superset.mcp_service.chart.registry import display_name_for_viz_type + + _display_name = display_name_for_viz_type(_viz_type) if _viz_type else None + except Exception: + _display_name = None + return sanitize_chart_info_for_llm_context( ChartInfo( id=chart_id, slice_name=getattr(chart, "slice_name", None), - viz_type=getattr(chart, "viz_type", None), + viz_type=_viz_type, + chart_type_display_name=_display_name, datasource_name=getattr(chart, "datasource_name", None), datasource_type=getattr(chart, "datasource_type", None), url=chart_url,