feat(mcp): add list and get tools for annotation layers and annotations#40303
feat(mcp): add list and get tools for annotation layers and annotations#40303aminghadersohi wants to merge 3 commits into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #40303 +/- ##
==========================================
- Coverage 64.14% 63.83% -0.32%
==========================================
Files 2592 2598 +6
Lines 138846 140183 +1337
Branches 32201 32492 +291
==========================================
+ Hits 89069 89488 +419
- Misses 48245 49131 +886
- Partials 1532 1564 +32
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
32ffe2c to
7df5804
Compare
Co-Authored-By: kasiazjc <noreply@github.com>
- Use ModelGetInfoCore in get_annotation_layer_info (DRY, matches other get_info tools) - Expand search_columns to include descr and long_descr (align with docstrings) - Simplify layer_id assignment in list_layer_annotations (direct attribute set vs rebuild) - Fix AnnotationList.layer_id default to 0 (ModelListCore cannot inject domain fields) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- AnnotationList.filters_applied used list[AnnotationFilter] which only allows col="short_descr", but ModelListCore injects a col="layer_id" ColumnOperator that fails Pydantic validation, causing KeyError on layer_id in the JSON response. Changed to list[ColumnOperator]. - test_get_annotation_layer_info_found: ModelGetInfoCore._find_object calls find_by_id(id, query_options=None), not find_by_id(id); updated assertion to assert_called_once_with(5, query_options=None).
7df5804 to
6e71872
Compare
|
Superseded by #40342 (branch renamed to follow |
There was a problem hiding this comment.
Code Review Agent Run #f2741b
Actionable Suggestions - 3
-
superset/mcp_service/annotation_layer/tool/list_layer_annotations.py - 1
- Exception swallows middleware error handling · Line 140-149
-
tests/unit_tests/mcp_service/annotation_layer/tool/test_annotation_layer_tools.py - 1
- Weak test assertion · Line 330-347
-
superset/mcp_service/annotation_layer/tool/get_layer_annotation_info.py - 1
- Avoid catching blind Exception · Line 120-120
Additional Suggestions - 2
-
superset/mcp_service/annotation_layer/tool/list_layer_annotations.py - 1
-
Unused function parameter dead code · Line 100-101The `_serialize` function accepts a `cols` parameter but never uses it. This is dead code that creates maintenance confusion. Compare with `list_annotation_layers.py` which uses a local function without the unused parameter.
Code suggestion
--- superset/mcp_service/annotation_layer/tool/list_layer_annotations.py +++ superset/mcp_service/annotation_layer/tool/list_layer_annotations.py @@ -97,7 +97,7 @@ async def list_layer_annotations( ) combined_filters: list[ColumnOperator] = [layer_filter] + list(request.filters) - def _serialize(obj: object, cols: list[str] | None) -> AnnotationInfo | None: + def _serialize(obj: object) -> AnnotationInfo | None: return serialize_annotation(obj)
-
-
superset/mcp_service/annotation_layer/tool/get_annotation_layer_info.py - 1
-
Inconsistent error factory method · Line 93-96Inconsistent error construction pattern: lines 93-96 manually construct AnnotationLayerError with a manual timestamp, while get_layer_annotation_info.py uses AnnotationLayerError.create() which handles timestamp automatically. Use AnnotationLayerError.create(error='...', error_type='InternalError') for consistency.
Code suggestion
--- superset/mcp_service/annotation_layer/tool/get_annotation_layer_info.py +++ superset/mcp_service/annotation_layer/tool/get_annotation_layer_info.py @@ -90,8 +90,6 @@ async def get_annotation_layer_info( % (request.id, str(e), type(e).__name__) ) - return AnnotationLayerError( - error=f"Failed to get annotation layer info: {str(e)}", - error_type="InternalError", - timestamp=datetime.now(timezone.utc), - ) + return AnnotationLayerError.create( + error=f"Failed to get annotation layer info: {str(e)}", + error_type="InternalError", + )
-
Filtered by Review Rules
Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.
-
superset/mcp_service/annotation_layer/tool/list_annotation_layers.py - 1
- Missing humanized timestamp fields · Line 77-80
-
tests/unit_tests/mcp_service/annotation_layer/tool/test_annotation_layer_tools.py - 1
- Incorrect mock assertion · Line 234-234
Review Details
-
Files reviewed - 11 · Commit Range:
de1a231..6e71872- superset/mcp_service/annotation_layer/__init__.py
- superset/mcp_service/annotation_layer/schemas.py
- superset/mcp_service/annotation_layer/tool/__init__.py
- superset/mcp_service/annotation_layer/tool/get_annotation_layer_info.py
- superset/mcp_service/annotation_layer/tool/get_layer_annotation_info.py
- superset/mcp_service/annotation_layer/tool/list_annotation_layers.py
- superset/mcp_service/annotation_layer/tool/list_layer_annotations.py
- superset/mcp_service/app.py
- tests/unit_tests/mcp_service/annotation_layer/__init__.py
- tests/unit_tests/mcp_service/annotation_layer/tool/__init__.py
- tests/unit_tests/mcp_service/annotation_layer/tool/test_annotation_layer_tools.py
-
Files skipped - 0
-
Tools
- Whispers (Secret Scanner) - ✔︎ Successful
- Detect-secrets (Secret Scanner) - ✔︎ Successful
- MyPy (Static Code Analysis) - ✔︎ Successful
- Astral Ruff (Static Code Analysis) - ✔︎ Successful
Bito Usage Guide
Commands
Type the following command in the pull request comment and save the comment.
-
/review- Manually triggers a full AI review. -
/pause- Pauses automatic reviews on this pull request. -
/resume- Resumes automatic reviews. -
/resolve- Marks all Bito-posted review comments as resolved. -
/abort- Cancels all in-progress reviews.
Refer to the documentation for additional commands.
Configuration
This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.
Documentation & Help
SUMMARY
Adds 4 new MCP tools in a new
superset/mcp_service/annotation_layer/domain:list_annotation_layers— list annotation layers with filtering, search, and 1-based paginationget_annotation_layer_info— get annotation layer details by IDlist_layer_annotations— list annotations within a layer (requireslayer_idto scope results)get_layer_annotation_info— get a single annotation bylayer_id+annotation_id, with layer-membership verificationThe annotation tools mirror the pattern used by
database/,dashboard/, anddataset/domains: Pydantic request/response schemas,ModelListCorefor listings, DAO-based lookups,ToolAnnotations, andevent_loggerinstrumentation.For annotations,
layer_idis a required parameter that scopes all results to the parent layer — mirroring the Superset REST API structure (GET /annotation_layer/{layer_pk}/annotation/).BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
N/A (backend-only MCP tool additions)
TESTING INSTRUCTIONS
list_annotation_layers({})— lists all annotation layersget_annotation_layer_info({"id": <id>})— retrieves a specific layerlist_layer_annotations({"layer_id": <id>})— lists annotations in a layerget_layer_annotation_info({"layer_id": <id>, "annotation_id": <id>})— retrieves a specific annotationADDITIONAL INFORMATION