fix(mcp): reject unparseable time_range instead of silently matching full table#42283
Draft
aminghadersohi wants to merge 1 commit into
Draft
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #42283 +/- ##
==========================================
- Coverage 65.15% 65.14% -0.01%
==========================================
Files 2789 2790 +1
Lines 157543 157584 +41
Branches 35864 35872 +8
==========================================
+ Hits 102644 102662 +18
- Misses 52931 52953 +22
- Partials 1968 1969 +1
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:
|
aminghadersohi
marked this pull request as ready for review
July 22, 2026 03:31
…the full table MCP tools that accept a free-form time_range string (query_dataset, get_table, manage_native_filters) forward it straight into a TEMPORAL_RANGE filter or native filter default with no validation. superset.utils.date_parser.get_since_until() only rewrites a separator-less time_range into a bounded range when it recognizes one of a handful of prefixes (Last, Next, previous calendar ..., Current ..., first ... of ...). Anything else -- banana, this month, lowercase last week, [decade] -- silently falls through to an unbounded (None, today) result: no error, no warning, and the query returns the entire table with success: true. Add a shared validator (superset.mcp_service.common.time_range_validation) that normalizes bracket shorthands (e.g. [year] -> Last year, following the pattern from apache#42144) and rejects any other separator-less value that get_since_until() would silently discard, with a ValidationError listing the accepted forms so an LLM caller can self-correct. Wired into QueryDatasetRequest.time_range, GetTableRequest.time_range, FilterTimeSpec.default_time_range, and NativeFilterUpdateSpec.default_time_range. The guard lives in the MCP schema layer rather than in get_since_until() itself: that function is also called from jinja_context.py and semantic_layers/mapper.py across the whole chart/dashboard query path, where making it raise is a separate, larger-blast-radius discussion. The MCP tools are the surface that accepts free-form, model-generated strings. BREAKING CHANGE: values like 'this month' or lowercase 'last week' that previously silently returned an unfiltered, full-table result now raise a ValidationError. This is the intended fix -- callers previously had no signal that their filter was ignored.
aminghadersohi
force-pushed
the
aminghadersohi/mcp-time-range-validation
branch
from
July 22, 2026 03:39
4559795 to
188876f
Compare
aminghadersohi
marked this pull request as draft
July 22, 2026 03:40
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SUMMARY
MCP tools that accept a free-form
time_rangestring (query_dataset,get_table,manage_native_filters) forward it straight into aTEMPORAL_RANGEfilter or native filter default with no validation.superset.utils.date_parser.get_since_until()only rewrites a separator-lesstime_rangeinto a bounded range when it recognizes one of a handful of prefixes (Last,Next,previous calendar ...,Current ...,first ... of ...). Anything else —banana,this month, lowercaselast week,[decade]— silently falls through to an unbounded(None, today)result: no error, no warning, and the query returns the entire table withsuccess: true.Verified live against a local Superset MCP server (Postgres metadata DB,
examplesdata, dataset 28cleaned_sales_data, 2823 rows total):This PR adds a shared validator (
superset.mcp_service.common.time_range_validation) that:[second]through[year]) to a formget_since_until()resolves correctly, following the pattern from fix(mcp): normalize bracket-shorthand time ranges in query_dataset #42144 (which scoped this normalization toquery_datasetonly).get_since_until()would silently discard, with aValidationErrorlisting the accepted forms so an LLM caller can self-correct instead of receiving a full-table result with no error signal.Wired into
QueryDatasetRequest.time_range,GetTableRequest.time_range,FilterTimeSpec.default_time_range, andNativeFilterUpdateSpec.default_time_range— closing the gap left open by #42144, which explicitly scopedget_tableandmanage_native_filtersout (see discussion).Why the guard lives in the MCP schema layer, not in
get_since_until()itself: that function is also called fromjinja_context.pyandsemantic_layers/mapper.pyacross the whole chart/dashboard query path. Making it raise there is a much larger blast radius and a separate discussion about whether silently-ignored time ranges are load-bearing anywhere. The MCP tools are the surface that accepts free-form, model-generated strings.BREAKING CHANGE
Values like
this monthor lowercaselast weekthat previously silently returned an unfiltered, full-table result now raise aValidationError. This is the intended fix — callers previously had no signal that their filter was ignored, which is worse than a loud error for an LLM caller that could otherwise self-correct.TESTING INSTRUCTIONS
pytest tests/unit_tests/mcp_service/common/test_time_range_validation.pypytest tests/unit_tests/mcp_service/dataset/tool/test_query_dataset.pypytest tests/unit_tests/mcp_service/semantic_layer/tool/test_get_table.pypytest tests/unit_tests/mcp_service/dashboard/tool/test_manage_native_filters.pypytest tests/unit_tests/utils/date_parser_tests.py— confirms the shared validator's accepted-prefix grammar doesn't regress the existingget_since_until()test suite (this PR does not modifydate_parser.py)get_table/query_datasetwithtime_rangeset tobanana,this month,last week(lowercase), and[decade]against a dataset with a temporal column, and confirm each now returns aValidationErrorinstead of an unfiltered result.ADDITIONAL INFORMATION