This is an automated email from the ASF dual-hosted git repository.
aminghadersohi pushed a commit to branch mcp-rbac-tool-visibility
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/mcp-rbac-tool-visibility by
this push:
new 9ca3f8ec01d fix(mcp): deny all tools on invalid credentials in search
filtering
9ca3f8ec01d is described below
commit 9ca3f8ec01d9a5062c347bbab433f68c957c2ced
Author: Amin Ghadersohi <[email protected]>
AuthorDate: Wed May 20 21:49:39 2026 +0000
fix(mcp): deny all tools on invalid credentials in search filtering
Split the combined except clause in _tool_allowed_for_current_user so
that PermissionError (bad API key) returns False for every tool,
matching RBACToolVisibilityMiddleware's fail-closed behaviour.
ValueError (no auth source configured) retains the existing public-tool
fallback. Adds a test to cover the new deny-all path.
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
---
superset/mcp_service/server.py | 10 ++++++---
.../mcp_service/test_tool_search_transform.py | 24 ++++++++++++++++++++++
2 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/superset/mcp_service/server.py b/superset/mcp_service/server.py
index 92166606e43..08d5d915996 100644
--- a/superset/mcp_service/server.py
+++ b/superset/mcp_service/server.py
@@ -410,9 +410,13 @@ def _tool_allowed_for_current_user(tool: Any) -> bool:
if not getattr(g, "user", None):
try:
g.user = get_user_from_request()
- except (ValueError, PermissionError):
- # Can't resolve user; only hide protected tools. Public tools
- # (no _class_permission_name) pass through regardless.
+ except PermissionError:
+ # Invalid credentials (bad API key) → deny all, matching
+ # RBACToolVisibilityMiddleware's fail-closed behaviour.
+ return False
+ except ValueError:
+ # No auth source configured → only pass public tools
+ # (those with no class-level permission requirement).
func = getattr(tool, "fn", tool)
return not getattr(func, "_class_permission_name", None)
diff --git a/tests/unit_tests/mcp_service/test_tool_search_transform.py
b/tests/unit_tests/mcp_service/test_tool_search_transform.py
index 3798166c601..b8f301c9692 100644
--- a/tests/unit_tests/mcp_service/test_tool_search_transform.py
+++ b/tests/unit_tests/mcp_service/test_tool_search_transform.py
@@ -901,6 +901,30 @@ def
test_tool_search_permission_filter_hides_protected_tools_without_user() -> N
assert result == [public]
+def test_tool_search_permission_filter_denies_all_on_invalid_credentials() ->
None:
+ """Invalid credentials (PermissionError) deny all tools, including public
ones."""
+ app = Flask(__name__)
+ app.config["MCP_RBAC_ENABLED"] = True
+
+ def protected_tool():
+ pass
+
+ setattr(protected_tool, CLASS_PERMISSION_ATTR, "Dataset")
+ setattr(protected_tool, METHOD_PERMISSION_ATTR, "read")
+
+ protected = SimpleNamespace(fn=protected_tool)
+ public = SimpleNamespace(fn=lambda: None)
+
+ with app.app_context():
+ with patch(
+ "superset.mcp_service.auth.get_user_from_request",
+ side_effect=PermissionError("Invalid API key"),
+ ):
+ result = _filter_tools_by_current_user_permission([protected,
public])
+
+ assert result == []
+
+
def test_tool_search_filter_hides_metadata_tools_without_access() -> None:
"""Privacy-marked tools are hidden even if broad Dataset read exists."""
app = Flask(__name__)