mirror of
https://github.com/apache/superset.git
synced 2026-05-21 15:55:10 +00:00
Introduces a dynamic filter layer in the chart type registry so operators can disable individual plugins (e.g. `handlebars`) without a code deploy: - `MCP_DISABLED_CHART_PLUGINS: frozenset[str]` — static deny-list in mcp_config.py - `MCP_CHART_PLUGIN_ENABLED_FUNC: Callable[[str], bool] | None` — dynamic hook for Harness/Split/per-user targeting; takes precedence over the deny-list - Both keys are propagated through `get_mcp_config()` defaults registry.py changes: - `_PluginFilterConfig` frozen dataclass replaces two bare globals so configure() replaces them atomically (no torn reads under concurrency) - `configure(disabled, enabled_func)` — called at app init; accepts any iterable for `disabled`; validates `enabled_func` is callable - `_is_plugin_enabled()` — reads config once, fails closed on callable exception - `get()` / `all_types()` / `is_enabled()` apply the filter at lookup time; `is_registered()` and `display_name_for_viz_type()` intentionally bypass it so callers can distinguish "unknown" vs "disabled" and existing charts still resolve display names for disabled viz types schema_validator.py: two-step pre-check — `is_registered()` for unknown types, `is_enabled()` for disabled ones, with distinct `DISABLED_CHART_TYPE` error code. Wiring: - `SupersetAppInitializer.configure_mcp_chart_registry()` called after `configure_feature_flags()` in `init_app()` - `flask_singleton.py` re-calls `registry.configure()` after the MCP config overlay so MCP-specific overrides in `superset_config.py` take effect in standalone MCP mode Tests: 28 cases in test_registry_filters.py covering deny-list, callable hook, fail-closed on exception, all_types() filtering, display_name bypass, atomic reconfigure, and configure() with list/tuple/frozenset inputs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>