Commit Graph

213 Commits

Author SHA1 Message Date
Amin Ghadersohi
ec178b862c fix(mcp): fix saved-metric name normalization across all chart plugins
Add _get_canonical_metric_name() to DatasetValidator that searches only
available_metrics, preventing a column with matching case-insensitive name
from shadowing a saved metric's canonical casing.

Update all 7 chart plugins (xy, table, pie, big_number, handlebars,
mixed_timeseries, pivot_table) to branch on saved_metric flag: saved
metrics now go through _get_canonical_metric_name while regular column
refs continue to use _get_canonical_column_name.

Fix pre_validate alias handling in xy and mixed_timeseries plugins to
accept Pydantic AliasChoices keys (metrics/x_axis/metrics_b) so payloads
using canonical Superset field names are not incorrectly rejected.

Add TestGetCanonicalMetricName, TestSavedMetricNormalizationCorrectness,
and TestPreValidateAliasHandling test classes covering the collision case
and alias acceptance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 23:04:53 +00:00
Amin Ghadersohi
4e0eb3a395 feat(mcp): add runtime chart plugin enable/disable via _PluginFilterConfig
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>
2026-06-10 23:04:53 +00:00
Amin Ghadersohi
c1d4b454e4 fix(mcp): fix E501 in update_chart.py and update_chart test mocks for column validation
Split an 89-char comment line and an over-limit condition in update_chart.py
to satisfy the ruff E501 rule. Also applied ruff format.

Two TestUpdateChartValidationGate tests expected CHART_VALIDATION_FAILED but
received CHART_DATASET_NOT_FOUND because _validate_update_against_dataset calls
DatasetValidator.validate_against_dataset before validate_and_compile, and the
existing mocks provided a Mock() object for chart.datasource whose .id attribute
is an auto-generated MagicMock (not a real int). Added a patch for
DatasetValidator.validate_against_dataset returning (True, None) so the
column-validation tier is bypassed and the test reaches the mocked
validate_and_compile response as intended.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 23:04:09 +00:00
Amin Ghadersohi
760a973c76 refactor(mcp): address Codex review — fix registry bug, DRY schema hints, remove column regex
P1.1 registry.py: move _plugins_loaded=True to after successful import so a
failed load doesn't permanently poison the registry.

P1.3 schemas.py: remove overly restrictive ColumnRef.name / FilterClause.column
/ BigNumberChartConfig.temporal_column regex that blocked valid column names
containing parentheses, slashes, and other SQL-common characters.

P2.3 (DRY): eliminate _CHART_TYPE_ERROR_HINTS second-registry in
schema_validator.py by adding schema_error_hint() to ChartTypePlugin protocol,
BaseChartPlugin default, and all 7 plugin classes. SchemaValidator now delegates
to the plugin registry instead of maintaining a parallel dict.

P3.3 test_registry.py: add full registry unit-test coverage (register, get,
all_types, is_registered, display_name_for_viz_type, proxy methods, duplicate
warning, empty chart_type validation, insertion-order guarantee).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 23:04:09 +00:00
Amin Ghadersohi
77dc099da7 fix(mcp): resolve ruff E501 and formatting issues to pass pre-commit
- Split long string literal in schema_validator.py line 202 (E501, 94 > 88 chars)
- Apply ruff format auto-fixes to big_number.py, handlebars.py, and test_get_chart_data.py
2026-06-10 23:04:09 +00:00
Amin Ghadersohi
487f8afc72 refactor(mcp): complete plugin protocol — registry bootstrap, mypy fixes, test repairs
On top of the dead-code elimination in the previous commit:
- Add lazy _ensure_plugins_loaded() bootstrap to ChartTypeRegistry so the
  registry is populated even without importing app.py (fixes isolated test runs)
- Delegate _RegistryProxy methods to module-level functions so bootstrap runs
- Guard register() against empty chart_type strings
- Add generate_name + resolve_viz_type to ChartTypePlugin Protocol and
  BaseChartPlugin; delegate generate_chart_name/_resolve_viz_type in
  chart_utils to the plugin registry
- Add _with_context static helper to BaseChartPlugin (shared by all plugins)
- Fix stale 'five methods' → 'eight methods' docstring in plugin.py
- Add TypeVar _C to normalize_column_names so mypy infers correct return type
- Fix broken tests: update _pre_validate_big_number_config → _pre_validate_chart_type,
  remove deleted TestNormalizeXYConfig/TestNormalizeTableConfig classes,
  update runtime validator tests for removed _validate_format_compatibility /
  _validate_cardinality methods, add x is not None narrowing guards

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 23:04:09 +00:00
Evan Rusackas
568f34d6d8 fix(mcp): enforce audience, algorithm, issuer binding, and token scopes (strict mode) (#40653)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-06-09 11:08:20 -07:00
Evan Rusackas
0133ebc9f2 feat(mcp): log successful JWT authentication events (#40864)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-06-09 09:34:52 -07:00
Evan Rusackas
b64dd4af4a fix(mcp): handle JWKS fetch network errors during token verification (#40869)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-06-09 09:34:33 -07:00
Evan Rusackas
9105adc67b fix(mcp): return a generic message when a request is unauthenticated (#40861)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-06-09 09:19:15 -07:00
Amin Ghadersohi
ef7379c47e chore(mcp): remove low-value list/info tools that fail agent-native policy (#40690) 2026-06-06 14:57:41 -04:00
Amin Ghadersohi
84aaaaa6b0 fix(mcp): filter sensitive database columns from list_databases loaded-metadata (#40771) 2026-06-06 14:57:21 -04:00
Amin Ghadersohi
aa4092ba68 fix(mcp): add select_columns lean defaults to get_dashboard_info, get_chart_info, get_dataset_info (#40473)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Richard Fogaça <richardfogaca@gmail.com>
2026-06-05 11:10:13 -03:00
Amin Ghadersohi
7d69f76127 fix(mcp): API key authentication for MCP — transport, validation, and RBAC (#39604) 2026-06-04 15:04:43 -04:00
Amin Ghadersohi
f4dfb7f026 fix(mcp): fall back to form_data spatial query for Deck.gl charts (#40339) 2026-06-03 13:30:52 -04:00
Evan Rusackas
0b9764aed5 fix(mcp): honor AUTH_ROLE_ADMIN and warn on permission-less protected tools (#40659)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-06-02 21:20:11 -07:00
Amin Ghadersohi
616c243278 fix(deps): revert joserfc JWT error migration — fastmcp still uses authlib (#40688) 2026-06-02 12:02:17 -07:00
Evan Rusackas
ca8855dc03 fix(mcp): generic auth errors, required token expiry, and safer auth logging (#40646)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-06-02 08:31:05 -07:00
Evan Rusackas
817a35f445 fix(mcp): deny deactivated user accounts in MCP authentication (#40631)
Co-authored-by: Claude Code <noreply@anthropic.com>
2026-06-01 22:08:29 -07:00
Amin Ghadersohi
a6d2c95480 chore(deps): migrate MCP service JWT errors from authlib.jose to joserfc (#40582) 2026-06-02 00:41:17 -04:00
Amin Ghadersohi
5312d0adf8 feat(mcp): add list_reports and get_report_info tools (#40348)
Co-authored-by: Richard Fogaça <richardfogaca@gmail.com>
2026-06-01 14:23:53 -04:00
Amin Ghadersohi
87be424f9c feat(mcp): add list and get tools for row level security and plugins (#40347) 2026-05-30 10:41:12 -04:00
Amin Ghadersohi
d350792d43 feat(mcp): add list and get tools for CSS templates and themes (#40343) 2026-05-30 00:20:48 -04:00
Amin Ghadersohi
62b4ee3d9e feat(mcp): add list and get tools for users and roles (#40345)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 23:46:30 -04:00
Amin Ghadersohi
40de44f6de feat(mcp): add list and get tools for action log and tasks (#40344) 2026-05-29 23:16:10 -04:00
Amin Ghadersohi
8d8eeb3505 feat(mcp): add list_tags and get_tag_info MCP tools (#40349)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 22:16:59 -04:00
Amin Ghadersohi
a69bbcb044 feat(mcp): add list and get tools for saved queries and query history (#40346)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 22:16:11 -04:00
Amin Ghadersohi
f614863ed7 feat(mcp): add list and get tools for annotation layers and annotations (#40342) 2026-05-29 22:14:28 -04:00
Mehmet Salih Yavuz
8853ab5c75 feat(mcp): add get_dashboard_layout companion tool (#40328) 2026-05-29 14:31:16 +03:00
Gabriel Torres Ruiz
e68251fa70 feat(mcp): support custom SQL metrics in generate_chart and update_chart (#40448) 2026-05-28 14:52:43 -03:00
Amin Ghadersohi
0dc58d1042 feat(mcp): browser hello page with working middleware and config-driven content (#40471)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 11:47:38 -04:00
Amin Ghadersohi
e041f25385 fix(mcp): return error when target_tab not found in add_chart_to_existing_dashboard (#40124) 2026-05-27 14:29:43 -04:00
Amin Ghadersohi
fb60662353 chore(mcp): revert browser-friendly hello page for GET /mcp from browsers (#40467) 2026-05-27 11:43:01 -04:00
Amin Ghadersohi
09a94fa26b feat(mcp): return browser-friendly hello page for GET /mcp from browsers (#40309)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 18:52:37 -07:00
Maxime Beauchemin
b6f545e61e feat(mcp): resolve call_tool proxy name and capture error_type in logging (#38915)
Co-authored-by: Amin Ghadersohi <amin.ghadersohi@gmail.com>
2026-05-26 14:37:37 -04:00
Amin Ghadersohi
952a6f3a23 fix(mcp): prevent encoding error on tools/list when middleware raises (#40446) 2026-05-26 12:50:31 -04:00
Alexandru Soare
33585b0480 feat(mcp): make form_data_key optional in update_chart_preview (#39680) 2026-05-25 15:09:36 +03:00
Alexandru Soare
b64561f3a3 chore(mcp): Simplify chart preview response (#40020) 2026-05-25 13:16:27 +03:00
Mehmet Salih Yavuz
8ab4695ba3 fix(mcp): use name URL param so AI-generated SQL Lab titles render (#40288) 2026-05-22 17:35:08 +03:00
Alexandru Soare
558ff4452b fix(preview): fix chart preview bugs (#40063) 2026-05-22 13:42:59 +03:00
Amin Ghadersohi
5966bb1c1e feat(mcp): add series_limit to generate_chart XY config (#40307)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 20:36:30 -04:00
Amin Ghadersohi
e25d708197 fix(mcp): hide write tools from users without write permissions (#40098)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 19:11:46 -04:00
Mehmet Salih Yavuz
4c3f65ef0b feat(mcp): make config optional in generate_explore_link (#39559) 2026-05-21 18:01:59 +03:00
Mehmet Salih Yavuz
53d8e5bdfa feat(mcp): include applied dashboard filters in get_chart_info (#39620)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 17:48:21 +03:00
Mehmet Salih Yavuz
2f95d288dd fix(mcp): eager-load dataset.metrics to prevent Excel export DetachedInstanceError (#39483)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 16:34:38 +03:00
Mehmet Salih Yavuz
d1d07112aa feat(mcp): add find_users tool and owner filter columns for listings (#39679)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 15:59:09 +03:00
Alexandru Soare
e3711bec39 fix(recommandation): Fix chart recommandation (#39886) 2026-05-21 15:16:16 +03:00
Mehmet Salih Yavuz
ce9cab098f feat(mcp): chart formatting options across all supported chart types (#39887) 2026-05-21 15:00:32 +03:00
Alexandru Soare
fb276b08dd fix(mcp): Skip misleading trend analysis for categorical ASCII charts (#39761) 2026-05-20 18:04:21 +03:00
Alexandru Soare
6e8b3bf976 fix(mcp): raise right error (#39964) 2026-05-20 14:32:45 +03:00