codeant-ai-for-open-source[bot] commented on code in PR #41611:
URL: https://github.com/apache/superset/pull/41611#discussion_r3533487844


##########
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_dimensions.py:
##########
@@ -0,0 +1,232 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the get_compatible_dimensions MCP tool."""
+
+from __future__ import annotations
+
+import importlib
+from collections.abc import Generator
+from types import ModuleType
+from unittest.mock import MagicMock, Mock, patch
+
+import pytest
+from fastmcp import Client, FastMCP
+
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetSecurityException
+from superset.mcp_service.app import mcp
+from superset.utils import json
+
+get_compatible_dimensions_module: ModuleType = importlib.import_module(
+    "superset.mcp_service.semantic_layer.tool.get_compatible_dimensions"
+)
+
+
[email protected]
+def mcp_server() -> FastMCP:
+    return mcp
+
+
[email protected](autouse=True)
+def mock_auth() -> Generator[MagicMock, None, None]:
+    with (
+        patch("superset.mcp_service.auth.get_user_from_request") as 
mock_get_user,
+        patch.object(
+            get_compatible_dimensions_module,
+            "user_can_view_data_model_metadata",
+            return_value=True,
+        ),
+    ):
+        mock_user = Mock()
+        mock_user.id = 1
+        mock_user.username = "admin"
+        mock_get_user.return_value = mock_user
+        yield mock_get_user
+
+
+def _make_column(name: str, groupby: bool = True) -> MagicMock:
+    col = MagicMock()
+    col.column_name = name
+    col.verbose_name = None
+    col.description = None
+    col.type = "VARCHAR"
+    col.is_dttm = False
+    col.groupby = groupby
+    col.filterable = True
+    return col
+
+
+def _make_dataset(dataset_id: int = 42) -> MagicMock:
+    ds = MagicMock()
+    ds.id = dataset_id
+    ds.table_name = f"table_{dataset_id}"
+    ds.metrics = []
+    ds.columns = [
+        _make_column("region"),
+        _make_column("category"),
+        _make_column("internal_only", groupby=False),
+    ]
+    return ds
+
+
+def _make_view(view_id: int = 5) -> MagicMock:
+    view = MagicMock()

Review Comment:
   **Suggestion:** Provide an explicit type annotation for this view mock 
variable to satisfy the rule requiring type hints on relevant variables. 
[custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   The variable is a locally assigned Python object in a new file and can be 
annotated. Since it lacks a type hint, the suggestion is a valid match for the 
rule.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=e663bb1acb1d4853abb8c9ffcf6ac06a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=e663bb1acb1d4853abb8c9ffcf6ac06a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_dimensions.py
   **Line:** 88:88
   **Comment:**
        *Custom Rule: Provide an explicit type annotation for this view mock 
variable to satisfy the rule requiring type hints on relevant variables.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=f5de0e51c85158fa789f1b60463fd0a3f107dde4fb8f12017a53cb3b7ddfcb69&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=f5de0e51c85158fa789f1b60463fd0a3f107dde4fb8f12017a53cb3b7ddfcb69&reaction=dislike'>👎</a>



##########
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_dimensions.py:
##########
@@ -0,0 +1,232 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the get_compatible_dimensions MCP tool."""
+
+from __future__ import annotations
+
+import importlib
+from collections.abc import Generator
+from types import ModuleType
+from unittest.mock import MagicMock, Mock, patch
+
+import pytest
+from fastmcp import Client, FastMCP
+
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetSecurityException
+from superset.mcp_service.app import mcp
+from superset.utils import json
+
+get_compatible_dimensions_module: ModuleType = importlib.import_module(
+    "superset.mcp_service.semantic_layer.tool.get_compatible_dimensions"
+)
+
+
[email protected]
+def mcp_server() -> FastMCP:
+    return mcp
+
+
[email protected](autouse=True)
+def mock_auth() -> Generator[MagicMock, None, None]:
+    with (
+        patch("superset.mcp_service.auth.get_user_from_request") as 
mock_get_user,
+        patch.object(
+            get_compatible_dimensions_module,
+            "user_can_view_data_model_metadata",
+            return_value=True,
+        ),
+    ):
+        mock_user = Mock()
+        mock_user.id = 1
+        mock_user.username = "admin"
+        mock_get_user.return_value = mock_user
+        yield mock_get_user
+
+
+def _make_column(name: str, groupby: bool = True) -> MagicMock:
+    col = MagicMock()

Review Comment:
   **Suggestion:** Add an explicit type annotation to this local mock variable 
to comply with the type-hint requirement for relevant variables. [custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   The rule requires type hints for relevant variables that can be annotated. 
This local variable is created in a helper function and could be explicitly 
typed, so the suggestion correctly identifies a real omission.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=2c113dc881b341f1991fd46c3d9a4daf&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=2c113dc881b341f1991fd46c3d9a4daf&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_dimensions.py
   **Line:** 63:63
   **Comment:**
        *Custom Rule: Add an explicit type annotation to this local mock 
variable to comply with the type-hint requirement for relevant variables.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=8ebf90ba1d4c7b46ce97a9ceac83be31ef1be2cdf0a5bea3388750c8e992f425&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=8ebf90ba1d4c7b46ce97a9ceac83be31ef1be2cdf0a5bea3388750c8e992f425&reaction=dislike'>👎</a>



##########
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_dimensions.py:
##########
@@ -0,0 +1,232 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the get_compatible_dimensions MCP tool."""
+
+from __future__ import annotations
+
+import importlib
+from collections.abc import Generator
+from types import ModuleType
+from unittest.mock import MagicMock, Mock, patch
+
+import pytest
+from fastmcp import Client, FastMCP
+
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetSecurityException
+from superset.mcp_service.app import mcp
+from superset.utils import json
+
+get_compatible_dimensions_module: ModuleType = importlib.import_module(
+    "superset.mcp_service.semantic_layer.tool.get_compatible_dimensions"
+)
+
+
[email protected]
+def mcp_server() -> FastMCP:
+    return mcp
+
+
[email protected](autouse=True)
+def mock_auth() -> Generator[MagicMock, None, None]:
+    with (
+        patch("superset.mcp_service.auth.get_user_from_request") as 
mock_get_user,
+        patch.object(
+            get_compatible_dimensions_module,
+            "user_can_view_data_model_metadata",
+            return_value=True,
+        ),
+    ):
+        mock_user = Mock()
+        mock_user.id = 1
+        mock_user.username = "admin"
+        mock_get_user.return_value = mock_user
+        yield mock_get_user
+
+
+def _make_column(name: str, groupby: bool = True) -> MagicMock:
+    col = MagicMock()
+    col.column_name = name
+    col.verbose_name = None
+    col.description = None
+    col.type = "VARCHAR"
+    col.is_dttm = False
+    col.groupby = groupby
+    col.filterable = True
+    return col
+
+
+def _make_dataset(dataset_id: int = 42) -> MagicMock:
+    ds = MagicMock()

Review Comment:
   **Suggestion:** Add a concrete type annotation to this dataset mock variable 
so the helper function remains fully type-hinted. [custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   This is a new local variable in modified Python code that can be annotated 
but is not. That matches the type-hint rule for relevant variables.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=119927b445ba47f39ab7a6834907320d&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=119927b445ba47f39ab7a6834907320d&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_dimensions.py
   **Line:** 75:75
   **Comment:**
        *Custom Rule: Add a concrete type annotation to this dataset mock 
variable so the helper function remains fully type-hinted.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=ccf086e5022b58393d71f7e798b967b78e8e448abeab7b21e21a8bac3f86cede&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=ccf086e5022b58393d71f7e798b967b78e8e448abeab7b21e21a8bac3f86cede&reaction=dislike'>👎</a>



##########
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_metrics.py:
##########
@@ -0,0 +1,247 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the get_compatible_metrics MCP tool."""
+
+from __future__ import annotations
+
+import importlib
+from collections.abc import Generator
+from types import ModuleType
+from unittest.mock import MagicMock, Mock, patch
+
+import pytest
+from fastmcp import Client, FastMCP
+
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetSecurityException
+from superset.mcp_service.app import mcp
+from superset.utils import json
+
+get_compatible_metrics_module: ModuleType = importlib.import_module(
+    "superset.mcp_service.semantic_layer.tool.get_compatible_metrics"
+)
+
+
[email protected]
+def mcp_server() -> FastMCP:
+    return mcp
+
+
[email protected](autouse=True)
+def mock_auth() -> Generator[MagicMock, None, None]:
+    with (
+        patch("superset.mcp_service.auth.get_user_from_request") as 
mock_get_user,
+        patch.object(
+            get_compatible_metrics_module,
+            "user_can_view_data_model_metadata",
+            return_value=True,
+        ),
+    ):
+        mock_user = Mock()
+        mock_user.id = 1
+        mock_user.username = "admin"
+        mock_get_user.return_value = mock_user
+        yield mock_get_user
+
+
+def _make_metric(name: str, expression: str = "COUNT(*)") -> MagicMock:
+    m = MagicMock()

Review Comment:
   **Suggestion:** Add a type annotation for this local metric mock variable so 
relevant variables are explicitly typed. [custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   This local helper variable is introduced without a type hint, and it is 
clearly annotatable. The custom rule requires type hints for relevant variables 
in new Python code, so this is a real violation.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=2f5b7efa08f94e5c8f8aa0fc0755b5c8&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=2f5b7efa08f94e5c8f8aa0fc0755b5c8&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_metrics.py
   **Line:** 63:63
   **Comment:**
        *Custom Rule: Add a type annotation for this local metric mock variable 
so relevant variables are explicitly typed.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=8ba5b6364f98a83da800b5057ffe870a3f5dc7d0ac6c822b44e0cc5dad8bb2be&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=8ba5b6364f98a83da800b5057ffe870a3f5dc7d0ac6c822b44e0cc5dad8bb2be&reaction=dislike'>👎</a>



##########
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_metrics.py:
##########
@@ -0,0 +1,247 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the get_compatible_metrics MCP tool."""
+
+from __future__ import annotations
+
+import importlib
+from collections.abc import Generator
+from types import ModuleType
+from unittest.mock import MagicMock, Mock, patch
+
+import pytest
+from fastmcp import Client, FastMCP
+
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetSecurityException
+from superset.mcp_service.app import mcp
+from superset.utils import json
+
+get_compatible_metrics_module: ModuleType = importlib.import_module(
+    "superset.mcp_service.semantic_layer.tool.get_compatible_metrics"
+)
+
+
[email protected]
+def mcp_server() -> FastMCP:
+    return mcp
+
+
[email protected](autouse=True)
+def mock_auth() -> Generator[MagicMock, None, None]:
+    with (
+        patch("superset.mcp_service.auth.get_user_from_request") as 
mock_get_user,
+        patch.object(
+            get_compatible_metrics_module,
+            "user_can_view_data_model_metadata",
+            return_value=True,
+        ),
+    ):
+        mock_user = Mock()

Review Comment:
   **Suggestion:** Add an explicit type annotation for this mock user variable 
to satisfy the requirement for annotating relevant variables. [custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   This is a new Python variable assignment without a type annotation in a file 
that adds new code. Since the variable is a meaningful local object and can be 
annotated, it matches the type-hint rule violation.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=f825630673a746cd866730e5ab6c25d5&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=f825630673a746cd866730e5ab6c25d5&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_metrics.py
   **Line:** 55:55
   **Comment:**
        *Custom Rule: Add an explicit type annotation for this mock user 
variable to satisfy the requirement for annotating relevant variables.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=95d64e12b3c045fc414018edf5731bbf3f3ee6455ff04956b77f2834c5af5171&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=95d64e12b3c045fc414018edf5731bbf3f3ee6455ff04956b77f2834c5af5171&reaction=dislike'>👎</a>



##########
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_metrics.py:
##########
@@ -0,0 +1,247 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the get_compatible_metrics MCP tool."""
+
+from __future__ import annotations
+
+import importlib
+from collections.abc import Generator
+from types import ModuleType
+from unittest.mock import MagicMock, Mock, patch
+
+import pytest
+from fastmcp import Client, FastMCP
+
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetSecurityException
+from superset.mcp_service.app import mcp
+from superset.utils import json
+
+get_compatible_metrics_module: ModuleType = importlib.import_module(
+    "superset.mcp_service.semantic_layer.tool.get_compatible_metrics"
+)
+
+
[email protected]
+def mcp_server() -> FastMCP:
+    return mcp
+
+
[email protected](autouse=True)
+def mock_auth() -> Generator[MagicMock, None, None]:
+    with (
+        patch("superset.mcp_service.auth.get_user_from_request") as 
mock_get_user,
+        patch.object(
+            get_compatible_metrics_module,
+            "user_can_view_data_model_metadata",
+            return_value=True,
+        ),
+    ):
+        mock_user = Mock()
+        mock_user.id = 1
+        mock_user.username = "admin"
+        mock_get_user.return_value = mock_user
+        yield mock_get_user
+
+
+def _make_metric(name: str, expression: str = "COUNT(*)") -> MagicMock:
+    m = MagicMock()
+    m.metric_name = name
+    m.verbose_name = None
+    m.expression = expression
+    m.description = None
+    m.d3format = None
+    m.warning_text = None
+    return m
+
+
+def _make_dataset(dataset_id: int = 42) -> MagicMock:
+    ds = MagicMock()
+    ds.id = dataset_id
+    ds.table_name = f"table_{dataset_id}"
+    ds.columns = []
+    ds.metrics = [_make_metric("count"), _make_metric("revenue", 
"SUM(revenue)")]
+    return ds
+
+
+def _make_view(view_id: int = 5) -> MagicMock:
+    view = MagicMock()

Review Comment:
   **Suggestion:** Annotate this local view mock variable with its type to 
align with mandatory type hints on relevant variables. [custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   This variable is a new local Python assignment without an explicit type 
hint. It is a relevant annotatable variable in new code, so it falls under the 
type-hint requirement.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=4299adc283cb4eacbb5fa7af3c587dec&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=4299adc283cb4eacbb5fa7af3c587dec&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_metrics.py
   **Line:** 83:83
   **Comment:**
        *Custom Rule: Annotate this local view mock variable with its type to 
align with mandatory type hints on relevant variables.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=c4ba83257cda0f57a7fda8869ff98c75b07f973f4e1b73d621df7135dceae246&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=c4ba83257cda0f57a7fda8869ff98c75b07f973f4e1b73d621df7135dceae246&reaction=dislike'>👎</a>



##########
tests/unit_tests/mcp_service/semantic_layer/tool/test_list_metrics.py:
##########
@@ -0,0 +1,305 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the list_metrics MCP tool."""
+
+from __future__ import annotations
+
+import importlib
+from collections.abc import Generator
+from types import ModuleType
+from unittest.mock import call, MagicMock, Mock, patch
+
+import pytest
+from fastmcp import Client, FastMCP
+
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetSecurityException
+from superset.mcp_service.app import mcp
+from superset.utils import json
+
+list_metrics_module: ModuleType = importlib.import_module(
+    "superset.mcp_service.semantic_layer.tool.list_metrics"
+)
+
+
[email protected]
+def mcp_server() -> FastMCP:
+    return mcp
+
+
[email protected](autouse=True)
+def mock_auth() -> Generator[MagicMock, None, None]:
+    with (
+        patch("superset.mcp_service.auth.get_user_from_request") as 
mock_get_user,
+        patch.object(
+            list_metrics_module,
+            "user_can_view_data_model_metadata",
+            return_value=True,
+        ),
+    ):
+        mock_user = Mock()

Review Comment:
   **Suggestion:** Add an explicit type annotation to this fixture-local mock 
variable to comply with the type-hint requirement for relevant variables. 
[custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   This new Python local variable is created without a type annotation, and it 
is a relevant mock object that can be annotated, so it matches the type-hint 
rule.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=53fd80a8f2434ec5a2a540c5064bfe57&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=53fd80a8f2434ec5a2a540c5064bfe57&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
tests/unit_tests/mcp_service/semantic_layer/tool/test_list_metrics.py
   **Line:** 55:55
   **Comment:**
        *Custom Rule: Add an explicit type annotation to this fixture-local 
mock variable to comply with the type-hint requirement for relevant variables.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=d147e567848384a964f4b69f578c003adc338f3d358535aec481bf84f28c38e3&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=d147e567848384a964f4b69f578c003adc338f3d358535aec481bf84f28c38e3&reaction=dislike'>👎</a>



##########
tests/unit_tests/mcp_service/semantic_layer/tool/test_list_metrics.py:
##########
@@ -0,0 +1,305 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the list_metrics MCP tool."""
+
+from __future__ import annotations
+
+import importlib
+from collections.abc import Generator
+from types import ModuleType
+from unittest.mock import call, MagicMock, Mock, patch
+
+import pytest
+from fastmcp import Client, FastMCP
+
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetSecurityException
+from superset.mcp_service.app import mcp
+from superset.utils import json
+
+list_metrics_module: ModuleType = importlib.import_module(
+    "superset.mcp_service.semantic_layer.tool.list_metrics"
+)
+
+
[email protected]
+def mcp_server() -> FastMCP:
+    return mcp
+
+
[email protected](autouse=True)
+def mock_auth() -> Generator[MagicMock, None, None]:
+    with (
+        patch("superset.mcp_service.auth.get_user_from_request") as 
mock_get_user,
+        patch.object(
+            list_metrics_module,
+            "user_can_view_data_model_metadata",
+            return_value=True,
+        ),
+    ):
+        mock_user = Mock()
+        mock_user.id = 1
+        mock_user.username = "admin"
+        mock_get_user.return_value = mock_user
+        yield mock_get_user
+
+
+def _make_metric(name: str, expression: str = "COUNT(*)") -> MagicMock:
+    m = MagicMock()
+    m.metric_name = name
+    m.verbose_name = None
+    m.expression = expression
+    m.description = None
+    m.d3format = None
+    m.warning_text = None
+    return m
+
+
+def _make_column(name: str) -> MagicMock:
+    col = MagicMock()
+    col.column_name = name
+    col.verbose_name = None
+    col.description = None
+    col.type = "VARCHAR"
+    col.is_dttm = False
+    col.groupby = True
+    col.filterable = True
+    return col
+
+
+def _make_dataset(dataset_id: int = 1) -> MagicMock:
+    ds = MagicMock()
+    ds.id = dataset_id
+    ds.table_name = f"table_{dataset_id}"
+    ds.metrics = [_make_metric("count"), _make_metric("revenue", 
"SUM(revenue)")]
+    ds.columns = [_make_column("region"), _make_column("category")]
+    return ds
+
+
+def _make_view(view_id: int = 5) -> MagicMock:
+    view = MagicMock()
+    view.id = view_id
+    view.name = f"view_{view_id}"
+    view.raise_for_access = MagicMock(return_value=None)
+    view.metrics = [_make_metric("bookings"), _make_metric("revenue", 
"SUM(revenue)")]
+    view.columns = [_make_column("listing__country_name"), 
_make_column("channel")]
+    view.get_compatible_dimensions = 
MagicMock(return_value=["listing__country_name"])
+    return view
+
+
+def _access_denied_exc(message: str = "Access denied") -> 
SupersetSecurityException:
+    return SupersetSecurityException(
+        SupersetError(
+            message=message,
+            error_type=SupersetErrorType.DATASOURCE_SECURITY_ACCESS_ERROR,
+            level=ErrorLevel.ERROR,
+        )
+    )
+
+
[email protected]
+async def test_list_metrics_builtin_happy_path(mcp_server: FastMCP) -> None:
+    """list_metrics returns builtin metrics when only datasets exist."""
+    mock_ds = _make_dataset(42)
+
+    with (
+        patch(
+            "superset.mcp_service.semantic_layer.tool.list_metrics.DatasetDAO"
+        ) as mock_dao,
+        patch(
+            
"superset.mcp_service.semantic_layer.tool.list_metrics.SemanticViewDAO"
+        ) as mock_view_dao,
+    ):
+        mock_dao.find_by_id.return_value = mock_ds
+        mock_view_dao.find_accessible.return_value = []
+
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "list_metrics",
+                {"request": {"dataset_id": 42, 
"include_compatible_dimensions": False}},
+            )
+        data = json.loads(result.content[0].text)
+
+    assert data["success"] is True
+    assert data["total_count"] == 2
+    metrics = data["metrics"]
+    assert {m["name"] for m in metrics} == {"count", "revenue"}
+    assert all(m["source"] == "builtin" for m in metrics)
+    assert all(m["dataset_id"] == 42 for m in metrics)
+
+
[email protected]
+async def test_list_metrics_mutual_exclusion_validation(mcp_server: FastMCP) 
-> None:
+    """list_metrics returns a validation error when dataset_id and view_id 
coexist."""
+    async with Client(mcp_server) as client:
+        result = await client.call_tool(
+            "list_metrics",
+            {"request": {"dataset_id": 1, "view_id": 2}},
+        )
+    data = json.loads(result.content[0].text)
+
+    assert data["success"] is False
+    assert data["error_type"] == "ValidationError"
+
+
[email protected]
+async def test_list_metrics_privacy_check(mcp_server: FastMCP) -> None:
+    """list_metrics returns an error when the user lacks data-model metadata 
access."""
+    with patch.object(
+        list_metrics_module,
+        "user_can_view_data_model_metadata",
+        return_value=False,
+    ):
+        async with Client(mcp_server) as client:
+            result = await client.call_tool("list_metrics", {})
+        data = json.loads(result.content[0].text)
+
+    assert data["success"] is False
+    assert data["error_type"] == "DataModelMetadataRestricted"
+
+
[email protected]
+async def test_list_metrics_search_filter(mcp_server: FastMCP) -> None:
+    """list_metrics filters metrics by search term."""
+    mock_ds = _make_dataset(1)

Review Comment:
   **Suggestion:** Add an explicit type annotation for this dataset mock 
variable to satisfy the rule requiring type hints on relevant variables. 
[custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   The local dataset mock variable is introduced without a type annotation in 
new Python code, so this is a real omission covered by the type-hint rule.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=b0d35f78cedc41a88ee62c0187b6cfa3&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=b0d35f78cedc41a88ee62c0187b6cfa3&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
tests/unit_tests/mcp_service/semantic_layer/tool/test_list_metrics.py
   **Line:** 179:179
   **Comment:**
        *Custom Rule: Add an explicit type annotation for this dataset mock 
variable to satisfy the rule requiring type hints on relevant variables.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=bd25455714ba57a35845bd9f9345e128c600eea1fb41eac9ce4c83f32cb5e445&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=bd25455714ba57a35845bd9f9345e128c600eea1fb41eac9ce4c83f32cb5e445&reaction=dislike'>👎</a>



##########
tests/unit_tests/mcp_service/semantic_layer/tool/test_list_metrics.py:
##########
@@ -0,0 +1,305 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the list_metrics MCP tool."""
+
+from __future__ import annotations
+
+import importlib
+from collections.abc import Generator
+from types import ModuleType
+from unittest.mock import call, MagicMock, Mock, patch
+
+import pytest
+from fastmcp import Client, FastMCP
+
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetSecurityException
+from superset.mcp_service.app import mcp
+from superset.utils import json
+
+list_metrics_module: ModuleType = importlib.import_module(
+    "superset.mcp_service.semantic_layer.tool.list_metrics"
+)
+
+
[email protected]
+def mcp_server() -> FastMCP:
+    return mcp
+
+
[email protected](autouse=True)
+def mock_auth() -> Generator[MagicMock, None, None]:
+    with (
+        patch("superset.mcp_service.auth.get_user_from_request") as 
mock_get_user,
+        patch.object(
+            list_metrics_module,
+            "user_can_view_data_model_metadata",
+            return_value=True,
+        ),
+    ):
+        mock_user = Mock()
+        mock_user.id = 1
+        mock_user.username = "admin"
+        mock_get_user.return_value = mock_user
+        yield mock_get_user
+
+
+def _make_metric(name: str, expression: str = "COUNT(*)") -> MagicMock:
+    m = MagicMock()
+    m.metric_name = name
+    m.verbose_name = None
+    m.expression = expression
+    m.description = None
+    m.d3format = None
+    m.warning_text = None
+    return m
+
+
+def _make_column(name: str) -> MagicMock:
+    col = MagicMock()
+    col.column_name = name
+    col.verbose_name = None
+    col.description = None
+    col.type = "VARCHAR"
+    col.is_dttm = False
+    col.groupby = True
+    col.filterable = True
+    return col
+
+
+def _make_dataset(dataset_id: int = 1) -> MagicMock:
+    ds = MagicMock()
+    ds.id = dataset_id
+    ds.table_name = f"table_{dataset_id}"
+    ds.metrics = [_make_metric("count"), _make_metric("revenue", 
"SUM(revenue)")]
+    ds.columns = [_make_column("region"), _make_column("category")]
+    return ds
+
+
+def _make_view(view_id: int = 5) -> MagicMock:
+    view = MagicMock()
+    view.id = view_id
+    view.name = f"view_{view_id}"
+    view.raise_for_access = MagicMock(return_value=None)
+    view.metrics = [_make_metric("bookings"), _make_metric("revenue", 
"SUM(revenue)")]
+    view.columns = [_make_column("listing__country_name"), 
_make_column("channel")]
+    view.get_compatible_dimensions = 
MagicMock(return_value=["listing__country_name"])
+    return view
+
+
+def _access_denied_exc(message: str = "Access denied") -> 
SupersetSecurityException:
+    return SupersetSecurityException(
+        SupersetError(
+            message=message,
+            error_type=SupersetErrorType.DATASOURCE_SECURITY_ACCESS_ERROR,
+            level=ErrorLevel.ERROR,
+        )
+    )
+
+
[email protected]
+async def test_list_metrics_builtin_happy_path(mcp_server: FastMCP) -> None:
+    """list_metrics returns builtin metrics when only datasets exist."""
+    mock_ds = _make_dataset(42)
+
+    with (
+        patch(
+            "superset.mcp_service.semantic_layer.tool.list_metrics.DatasetDAO"
+        ) as mock_dao,
+        patch(
+            
"superset.mcp_service.semantic_layer.tool.list_metrics.SemanticViewDAO"
+        ) as mock_view_dao,
+    ):
+        mock_dao.find_by_id.return_value = mock_ds
+        mock_view_dao.find_accessible.return_value = []
+
+        async with Client(mcp_server) as client:
+            result = await client.call_tool(
+                "list_metrics",
+                {"request": {"dataset_id": 42, 
"include_compatible_dimensions": False}},
+            )
+        data = json.loads(result.content[0].text)
+
+    assert data["success"] is True
+    assert data["total_count"] == 2
+    metrics = data["metrics"]
+    assert {m["name"] for m in metrics} == {"count", "revenue"}
+    assert all(m["source"] == "builtin" for m in metrics)
+    assert all(m["dataset_id"] == 42 for m in metrics)
+
+
[email protected]
+async def test_list_metrics_mutual_exclusion_validation(mcp_server: FastMCP) 
-> None:
+    """list_metrics returns a validation error when dataset_id and view_id 
coexist."""
+    async with Client(mcp_server) as client:
+        result = await client.call_tool(
+            "list_metrics",
+            {"request": {"dataset_id": 1, "view_id": 2}},
+        )
+    data = json.loads(result.content[0].text)
+
+    assert data["success"] is False
+    assert data["error_type"] == "ValidationError"
+
+
[email protected]
+async def test_list_metrics_privacy_check(mcp_server: FastMCP) -> None:
+    """list_metrics returns an error when the user lacks data-model metadata 
access."""
+    with patch.object(
+        list_metrics_module,
+        "user_can_view_data_model_metadata",
+        return_value=False,
+    ):
+        async with Client(mcp_server) as client:
+            result = await client.call_tool("list_metrics", {})
+        data = json.loads(result.content[0].text)
+
+    assert data["success"] is False
+    assert data["error_type"] == "DataModelMetadataRestricted"
+
+
[email protected]
+async def test_list_metrics_search_filter(mcp_server: FastMCP) -> None:
+    """list_metrics filters metrics by search term."""
+    mock_ds = _make_dataset(1)
+
+    with (
+        patch(
+            "superset.mcp_service.semantic_layer.tool.list_metrics.DatasetDAO"
+        ) as mock_dao,
+        patch(
+            
"superset.mcp_service.semantic_layer.tool.list_metrics.SemanticViewDAO"
+        ) as mock_view_dao,
+        patch("superset.mcp_service.semantic_layer.tool.list_metrics.db") as 
mock_db,
+    ):
+        mock_view_dao.find_accessible.return_value = []
+        mock_query = MagicMock()

Review Comment:
   **Suggestion:** Add a concrete type annotation to this query mock variable 
so the new test code does not leave relevant variables untyped. [custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   This variable is introduced in new Python code without any type annotation, 
and it is a relevant intermediate object that can be annotated under the rule.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=727fde7be9334349940ec3ecf9557493&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=727fde7be9334349940ec3ecf9557493&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
tests/unit_tests/mcp_service/semantic_layer/tool/test_list_metrics.py
   **Line:** 191:191
   **Comment:**
        *Custom Rule: Add a concrete type annotation to this query mock 
variable so the new test code does not leave relevant variables untyped.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=f8bee4fe80c538857e0e6abcb086a9da247987990e581f0e5ce3331733edf407&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=f8bee4fe80c538857e0e6abcb086a9da247987990e581f0e5ce3331733edf407&reaction=dislike'>👎</a>



##########
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_metrics.py:
##########
@@ -0,0 +1,247 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Unit tests for the get_compatible_metrics MCP tool."""
+
+from __future__ import annotations
+
+import importlib
+from collections.abc import Generator
+from types import ModuleType
+from unittest.mock import MagicMock, Mock, patch
+
+import pytest
+from fastmcp import Client, FastMCP
+
+from superset.errors import ErrorLevel, SupersetError, SupersetErrorType
+from superset.exceptions import SupersetSecurityException
+from superset.mcp_service.app import mcp
+from superset.utils import json
+
+get_compatible_metrics_module: ModuleType = importlib.import_module(
+    "superset.mcp_service.semantic_layer.tool.get_compatible_metrics"
+)
+
+
[email protected]
+def mcp_server() -> FastMCP:
+    return mcp
+
+
[email protected](autouse=True)
+def mock_auth() -> Generator[MagicMock, None, None]:
+    with (
+        patch("superset.mcp_service.auth.get_user_from_request") as 
mock_get_user,
+        patch.object(
+            get_compatible_metrics_module,
+            "user_can_view_data_model_metadata",
+            return_value=True,
+        ),
+    ):
+        mock_user = Mock()
+        mock_user.id = 1
+        mock_user.username = "admin"
+        mock_get_user.return_value = mock_user
+        yield mock_get_user
+
+
+def _make_metric(name: str, expression: str = "COUNT(*)") -> MagicMock:
+    m = MagicMock()
+    m.metric_name = name
+    m.verbose_name = None
+    m.expression = expression
+    m.description = None
+    m.d3format = None
+    m.warning_text = None
+    return m
+
+
+def _make_dataset(dataset_id: int = 42) -> MagicMock:
+    ds = MagicMock()

Review Comment:
   **Suggestion:** Add an explicit type annotation for this dataset mock 
variable to comply with the type-hint rule for relevant variables. [custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   This is a new unannotated local variable in Python code. Given the rule to 
annotate relevant variables when possible, the missing type hint is a genuine 
violation.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=4450d44ec4b44f118a1dffbd17162d87&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=4450d44ec4b44f118a1dffbd17162d87&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
tests/unit_tests/mcp_service/semantic_layer/tool/test_get_compatible_metrics.py
   **Line:** 74:74
   **Comment:**
        *Custom Rule: Add an explicit type annotation for this dataset mock 
variable to comply with the type-hint rule for relevant variables.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=b233b2440bfe0feb46cf6ad5612b097fb6e274b012869975de45e7bea16a15e1&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=b233b2440bfe0feb46cf6ad5612b097fb6e274b012869975de45e7bea16a15e1&reaction=dislike'>👎</a>



##########
superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py:
##########
@@ -0,0 +1,230 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""MCP tool: get_compatible_dimensions
+
+Returns dimensions compatible with the current metric/dimension selection.
+"""
+
+import logging
+
+from fastmcp import Context
+from superset_core.mcp.decorators import tool, ToolAnnotations
+
+from superset.extensions import event_logger
+from superset.mcp_service.privacy import (
+    DATA_MODEL_METADATA_ERROR_TYPE,
+    requires_data_model_metadata_access,
+    user_can_view_data_model_metadata,
+)
+from superset.mcp_service.semantic_layer.schemas import (
+    CompatibleDimensionsResponse,
+    DimensionInfo,
+    GetCompatibleDimensionsRequest,
+    SemanticLayerError,
+)
+
+logger = logging.getLogger(__name__)
+
+
+@tool(
+    tags=["data", "semantic"],
+    class_permission_name="Dataset",
+    annotations=ToolAnnotations(
+        title="Get compatible dimensions",
+        readOnlyHint=True,
+        destructiveHint=False,
+    ),
+)
+@requires_data_model_metadata_access
+async def get_compatible_dimensions(
+    request: GetCompatibleDimensionsRequest,
+    ctx: Context,
+) -> CompatibleDimensionsResponse | SemanticLayerError:
+    """Return dimensions compatible with the current metric/dimension 
selection.
+
+    Used to drive progressive disclosure in query builders: after the user
+    selects one or more metrics (and optionally some dimensions), this tool
+    returns the dimensions that can validly be added without breaking the
+    underlying query.
+
+    Provide exactly one of ``dataset_id`` (built-in) or ``view_id`` (external).
+
+    For built-in datasets, returns all groupby-enabled columns from the 
dataset.
+    SQL datasets have no semantic compatibility constraints between metrics and
+    dimensions, so all groupby columns are always returned regardless of the
+    selected metrics.
+
+    For external semantic views, delegates to the view's
+    ``get_compatible_dimensions`` implementation.
+
+    Example:
+    ```json
+    {
+        "selected_metrics": ["revenue"],
+        "selected_dimensions": [],
+        "view_id": 5
+    }
+    ```
+    """
+    await ctx.info(
+        "Getting compatible dimensions: dataset_id=%s, view_id=%s, "
+        "metrics=%s, dims=%s"
+        % (
+            request.dataset_id,
+            request.view_id,
+            request.selected_metrics,
+            request.selected_dimensions,
+        )
+    )
+
+    if not user_can_view_data_model_metadata():
+        return SemanticLayerError.create(
+            error="You don't have permission to access dataset details for 
your role.",
+            error_type=DATA_MODEL_METADATA_ERROR_TYPE,
+        )
+
+    if request.dataset_id is None and request.view_id is None:
+        return SemanticLayerError.create(
+            error="Provide either dataset_id (built-in) or view_id 
(external).",
+            error_type="ValidationError",
+        )
+    if request.dataset_id is not None and request.view_id is not None:
+        return SemanticLayerError.create(
+            error="Provide only one of dataset_id or view_id, not both.",
+            error_type="ValidationError",
+        )
+
+    try:
+        # ------------------------------------------------------------------
+        # Built-in dataset path
+        # ------------------------------------------------------------------
+        if request.dataset_id is not None:
+            from sqlalchemy.orm import subqueryload
+
+            from superset.connectors.sqla.models import SqlaTable
+            from superset.daos.dataset import DatasetDAO
+
+            dataset_id: int = request.dataset_id
+            with event_logger.log_context(
+                action="mcp.get_compatible_dimensions.builtin"
+            ):
+                dataset = DatasetDAO.find_by_id(
+                    dataset_id,
+                    query_options=[
+                        subqueryload(SqlaTable.columns),
+                        subqueryload(SqlaTable.metrics),
+                    ],
+                )

Review Comment:
   **Suggestion:** Add an explicit type annotation to this DAO result variable 
(including its optionality) to satisfy the requirement for annotating relevant 
local variables. [custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   The code assigns the DAO result to a local variable without any type 
annotation, and this local value can reasonably be annotated as required by the 
Python type-hints rule.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=66f20852b7cf42848053ad58d22db89a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=66f20852b7cf42848053ad58d22db89a&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py
   **Line:** 126:132
   **Comment:**
        *Custom Rule: Add an explicit type annotation to this DAO result 
variable (including its optionality) to satisfy the requirement for annotating 
relevant local variables.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=e68864c35e30627dd5c551c500162b58a29e3747071977ba4a31d470a10a16ec&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=e68864c35e30627dd5c551c500162b58a29e3747071977ba4a31d470a10a16ec&reaction=dislike'>👎</a>



##########
superset/daos/semantic_layer.py:
##########
@@ -201,6 +201,40 @@ def validate_update_uniqueness(
             for c in candidates
         )
 
+    @classmethod
+    def find_accessible(cls) -> list[SemanticView]:

Review Comment:
   **Suggestion:** Add an explicit type annotation for the classmethod receiver 
to fully satisfy the type-hint requirement for method parameters. [custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   The new classmethod omits a type hint for the `cls` receiver, which is a 
parameter that can be annotated. This matches the Python type-hint requirement 
rule for newly added code.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=32ec01b4c3ee4162a432c525de94f531&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=32ec01b4c3ee4162a432c525de94f531&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/daos/semantic_layer.py
   **Line:** 204:205
   **Comment:**
        *Custom Rule: Add an explicit type annotation for the classmethod 
receiver to fully satisfy the type-hint requirement for method parameters.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=c255bb99924e301bb2a4b982254c085fc4189aa2b76a30f701ed136641339d4a&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=c255bb99924e301bb2a4b982254c085fc4189aa2b76a30f701ed136641339d4a&reaction=dislike'>👎</a>



##########
superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py:
##########
@@ -0,0 +1,230 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""MCP tool: get_compatible_dimensions
+
+Returns dimensions compatible with the current metric/dimension selection.
+"""
+
+import logging
+
+from fastmcp import Context
+from superset_core.mcp.decorators import tool, ToolAnnotations
+
+from superset.extensions import event_logger
+from superset.mcp_service.privacy import (
+    DATA_MODEL_METADATA_ERROR_TYPE,
+    requires_data_model_metadata_access,
+    user_can_view_data_model_metadata,
+)
+from superset.mcp_service.semantic_layer.schemas import (
+    CompatibleDimensionsResponse,
+    DimensionInfo,
+    GetCompatibleDimensionsRequest,
+    SemanticLayerError,
+)
+
+logger = logging.getLogger(__name__)
+
+
+@tool(
+    tags=["data", "semantic"],
+    class_permission_name="Dataset",
+    annotations=ToolAnnotations(
+        title="Get compatible dimensions",
+        readOnlyHint=True,
+        destructiveHint=False,
+    ),
+)
+@requires_data_model_metadata_access
+async def get_compatible_dimensions(
+    request: GetCompatibleDimensionsRequest,
+    ctx: Context,
+) -> CompatibleDimensionsResponse | SemanticLayerError:
+    """Return dimensions compatible with the current metric/dimension 
selection.
+
+    Used to drive progressive disclosure in query builders: after the user
+    selects one or more metrics (and optionally some dimensions), this tool
+    returns the dimensions that can validly be added without breaking the
+    underlying query.
+
+    Provide exactly one of ``dataset_id`` (built-in) or ``view_id`` (external).
+
+    For built-in datasets, returns all groupby-enabled columns from the 
dataset.
+    SQL datasets have no semantic compatibility constraints between metrics and
+    dimensions, so all groupby columns are always returned regardless of the
+    selected metrics.
+
+    For external semantic views, delegates to the view's
+    ``get_compatible_dimensions`` implementation.
+
+    Example:
+    ```json
+    {
+        "selected_metrics": ["revenue"],
+        "selected_dimensions": [],
+        "view_id": 5
+    }
+    ```
+    """
+    await ctx.info(
+        "Getting compatible dimensions: dataset_id=%s, view_id=%s, "
+        "metrics=%s, dims=%s"
+        % (
+            request.dataset_id,
+            request.view_id,
+            request.selected_metrics,
+            request.selected_dimensions,
+        )
+    )
+
+    if not user_can_view_data_model_metadata():
+        return SemanticLayerError.create(
+            error="You don't have permission to access dataset details for 
your role.",
+            error_type=DATA_MODEL_METADATA_ERROR_TYPE,
+        )
+
+    if request.dataset_id is None and request.view_id is None:
+        return SemanticLayerError.create(
+            error="Provide either dataset_id (built-in) or view_id 
(external).",
+            error_type="ValidationError",
+        )
+    if request.dataset_id is not None and request.view_id is not None:
+        return SemanticLayerError.create(
+            error="Provide only one of dataset_id or view_id, not both.",
+            error_type="ValidationError",
+        )
+
+    try:
+        # ------------------------------------------------------------------
+        # Built-in dataset path
+        # ------------------------------------------------------------------
+        if request.dataset_id is not None:
+            from sqlalchemy.orm import subqueryload
+
+            from superset.connectors.sqla.models import SqlaTable
+            from superset.daos.dataset import DatasetDAO
+
+            dataset_id: int = request.dataset_id
+            with event_logger.log_context(
+                action="mcp.get_compatible_dimensions.builtin"
+            ):
+                dataset = DatasetDAO.find_by_id(
+                    dataset_id,
+                    query_options=[
+                        subqueryload(SqlaTable.columns),
+                        subqueryload(SqlaTable.metrics),
+                    ],
+                )
+
+            if dataset is None:
+                return SemanticLayerError.create(
+                    error=f"No dataset found with id: {request.dataset_id}.",
+                    error_type="NotFound",
+                )
+
+            # For built-in datasets all groupby columns are always compatible;
+            # there's no per-metric compatibility constraint at the SQL level.
+            dims: list[DimensionInfo] = [
+                DimensionInfo(
+                    name=col.column_name,
+                    verbose_name=col.verbose_name or None,
+                    description=col.description or None,
+                    type=col.type or None,
+                    is_dttm=bool(col.is_dttm),
+                    groupby=bool(col.groupby),
+                    filterable=bool(col.filterable),
+                    source="builtin",
+                )
+                for col in dataset.columns
+                if col.groupby
+            ]
+
+            await ctx.info("Compatible dimensions (builtin): count=%d" % 
len(dims))
+            return CompatibleDimensionsResponse(
+                compatible_dimensions=dims,
+                source="builtin",
+            )
+
+        # ------------------------------------------------------------------
+        # External semantic view path
+        # ------------------------------------------------------------------
+        from superset.daos.semantic_layer import SemanticViewDAO
+        from superset.exceptions import SupersetSecurityException
+        from superset.semantic_layers.models import ColumnMetadata
+
+        view_id: int = request.view_id  # type: ignore[assignment]
+        with 
event_logger.log_context(action="mcp.get_compatible_dimensions.external"):
+            view = SemanticViewDAO.find_by_id(view_id)

Review Comment:
   **Suggestion:** Add a type annotation to the semantic view lookup variable 
so this relevant local value is explicitly typed. [custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   The semantic view lookup result is stored in a local variable without a type 
annotation, and the rule requires annotating relevant variables that can be 
typed.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=ed80cb75f10742db931f32125c02da0c&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=ed80cb75f10742db931f32125c02da0c&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py
   **Line:** 171:172
   **Comment:**
        *Custom Rule: Add a type annotation to the semantic view lookup 
variable so this relevant local value is explicitly typed.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=d835c5ee43bfb943e628d7c12cc52b8270ef02e5a32e05f3579a68b931532831&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=d835c5ee43bfb943e628d7c12cc52b8270ef02e5a32e05f3579a68b931532831&reaction=dislike'>👎</a>



##########
superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py:
##########
@@ -0,0 +1,230 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""MCP tool: get_compatible_dimensions
+
+Returns dimensions compatible with the current metric/dimension selection.
+"""
+
+import logging
+
+from fastmcp import Context
+from superset_core.mcp.decorators import tool, ToolAnnotations
+
+from superset.extensions import event_logger
+from superset.mcp_service.privacy import (
+    DATA_MODEL_METADATA_ERROR_TYPE,
+    requires_data_model_metadata_access,
+    user_can_view_data_model_metadata,
+)
+from superset.mcp_service.semantic_layer.schemas import (
+    CompatibleDimensionsResponse,
+    DimensionInfo,
+    GetCompatibleDimensionsRequest,
+    SemanticLayerError,
+)
+
+logger = logging.getLogger(__name__)
+
+
+@tool(
+    tags=["data", "semantic"],
+    class_permission_name="Dataset",
+    annotations=ToolAnnotations(
+        title="Get compatible dimensions",
+        readOnlyHint=True,
+        destructiveHint=False,
+    ),
+)
+@requires_data_model_metadata_access
+async def get_compatible_dimensions(
+    request: GetCompatibleDimensionsRequest,
+    ctx: Context,
+) -> CompatibleDimensionsResponse | SemanticLayerError:
+    """Return dimensions compatible with the current metric/dimension 
selection.
+
+    Used to drive progressive disclosure in query builders: after the user
+    selects one or more metrics (and optionally some dimensions), this tool
+    returns the dimensions that can validly be added without breaking the
+    underlying query.
+
+    Provide exactly one of ``dataset_id`` (built-in) or ``view_id`` (external).
+
+    For built-in datasets, returns all groupby-enabled columns from the 
dataset.
+    SQL datasets have no semantic compatibility constraints between metrics and
+    dimensions, so all groupby columns are always returned regardless of the
+    selected metrics.
+
+    For external semantic views, delegates to the view's
+    ``get_compatible_dimensions`` implementation.
+
+    Example:
+    ```json
+    {
+        "selected_metrics": ["revenue"],
+        "selected_dimensions": [],
+        "view_id": 5
+    }
+    ```
+    """
+    await ctx.info(
+        "Getting compatible dimensions: dataset_id=%s, view_id=%s, "
+        "metrics=%s, dims=%s"
+        % (
+            request.dataset_id,
+            request.view_id,
+            request.selected_metrics,
+            request.selected_dimensions,
+        )
+    )
+
+    if not user_can_view_data_model_metadata():
+        return SemanticLayerError.create(
+            error="You don't have permission to access dataset details for 
your role.",
+            error_type=DATA_MODEL_METADATA_ERROR_TYPE,
+        )
+
+    if request.dataset_id is None and request.view_id is None:
+        return SemanticLayerError.create(
+            error="Provide either dataset_id (built-in) or view_id 
(external).",
+            error_type="ValidationError",
+        )
+    if request.dataset_id is not None and request.view_id is not None:
+        return SemanticLayerError.create(
+            error="Provide only one of dataset_id or view_id, not both.",
+            error_type="ValidationError",
+        )
+
+    try:
+        # ------------------------------------------------------------------
+        # Built-in dataset path
+        # ------------------------------------------------------------------
+        if request.dataset_id is not None:
+            from sqlalchemy.orm import subqueryload
+
+            from superset.connectors.sqla.models import SqlaTable
+            from superset.daos.dataset import DatasetDAO
+
+            dataset_id: int = request.dataset_id
+            with event_logger.log_context(
+                action="mcp.get_compatible_dimensions.builtin"
+            ):
+                dataset = DatasetDAO.find_by_id(
+                    dataset_id,
+                    query_options=[
+                        subqueryload(SqlaTable.columns),
+                        subqueryload(SqlaTable.metrics),
+                    ],
+                )
+
+            if dataset is None:
+                return SemanticLayerError.create(
+                    error=f"No dataset found with id: {request.dataset_id}.",
+                    error_type="NotFound",
+                )
+
+            # For built-in datasets all groupby columns are always compatible;
+            # there's no per-metric compatibility constraint at the SQL level.
+            dims: list[DimensionInfo] = [
+                DimensionInfo(
+                    name=col.column_name,
+                    verbose_name=col.verbose_name or None,
+                    description=col.description or None,
+                    type=col.type or None,
+                    is_dttm=bool(col.is_dttm),
+                    groupby=bool(col.groupby),
+                    filterable=bool(col.filterable),
+                    source="builtin",
+                )
+                for col in dataset.columns
+                if col.groupby
+            ]
+
+            await ctx.info("Compatible dimensions (builtin): count=%d" % 
len(dims))
+            return CompatibleDimensionsResponse(
+                compatible_dimensions=dims,
+                source="builtin",
+            )
+
+        # ------------------------------------------------------------------
+        # External semantic view path
+        # ------------------------------------------------------------------
+        from superset.daos.semantic_layer import SemanticViewDAO
+        from superset.exceptions import SupersetSecurityException
+        from superset.semantic_layers.models import ColumnMetadata
+
+        view_id: int = request.view_id  # type: ignore[assignment]
+        with 
event_logger.log_context(action="mcp.get_compatible_dimensions.external"):
+            view = SemanticViewDAO.find_by_id(view_id)
+
+        if view is None:
+            return SemanticLayerError.create(
+                error=f"No semantic view found with id: {view_id}.",
+                error_type="NotFound",
+            )
+
+        try:
+            view.raise_for_access()
+        except SupersetSecurityException as ex:
+            return SemanticLayerError.create(
+                error=str(ex.error.message),
+                error_type="AccessDenied",
+            )
+
+        compatible_names: list[str] = view.get_compatible_dimensions(
+            request.selected_metrics,
+            request.selected_dimensions,
+        )
+
+        # Enrich with full column metadata
+        all_cols: dict[str, ColumnMetadata] = {
+            col.column_name: col for col in view.columns
+        }
+        dims = [

Review Comment:
   **Suggestion:** Add an explicit type annotation to this dimensions 
collection assignment to keep relevant local variables fully typed. 
[custom_rule]
   
   **Severity Level:** Minor ⚠️
   <details>
   <summary><b>Why it matters? 🤔 </b></summary>
   
   The dimensions collection is assigned without an explicit local variable 
type annotation, which matches the rule requiring type hints for relevant 
variables that can be annotated.
   </details>
   
   [![Fix in 
Cursor](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-cursor-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=41d1232cdecc4c91a7272f2d2b88a2a9&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 [![Fix in VSCode 
Claude](https://new-codeant-butcket.s3.us-west-1.amazonaws.com/badges/fix-in-vscode-claude-flat.svg)](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=41d1232cdecc4c91a7272f2d2b88a2a9&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** 
superset/mcp_service/semantic_layer/tool/get_compatible_dimensions.py
   **Line:** 197:197
   **Comment:**
        *Custom Rule: Add an explicit type annotation to this dimensions 
collection assignment to keep relevant local variables fully typed.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=56386bba6c1821c4a28865772ebc63a1ccc7e7d92270515d2d69f2b48ee46a2c&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F41611&comment_hash=56386bba6c1821c4a28865772ebc63a1ccc7e7d92270515d2d69f2b48ee46a2c&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to