mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
feat(mcp): add user roles to MCP response and permission-aware instructions (#38367)
This commit is contained in:
@@ -159,6 +159,23 @@ Feature Availability:
|
||||
- Call get_instance_info to discover accessible menus for the current user.
|
||||
- Do NOT assume features exist; always check get_instance_info first.
|
||||
|
||||
Permission Awareness:
|
||||
- get_instance_info returns current_user.roles (e.g., ["Admin"], ["Alpha"], ["Viewer"]).
|
||||
- ALWAYS check the user's roles BEFORE suggesting write operations (creating datasets,
|
||||
charts, dashboards, or running SQL).
|
||||
- Common roles and their typical capabilities:
|
||||
- Admin: Full access to all features
|
||||
- Alpha: Can create and modify charts, dashboards, datasets, and run SQL
|
||||
- Gamma: Can view charts and dashboards they have been granted access to
|
||||
- Viewer: Read-only access to shared dashboards and charts
|
||||
- If a user has a read-only role (Viewer, Gamma) and a listing tool returns 0 results,
|
||||
do NOT suggest they create resources. Instead:
|
||||
1. Explain that they may not have access to the requested resources
|
||||
2. Suggest they ask a workspace admin to grant them access or share content with them
|
||||
3. Offer to help with what they CAN do (e.g., viewing dashboards they have access to)
|
||||
- If you are unsure about a user's capabilities, check their accessible_menus in
|
||||
feature_availability from get_instance_info.
|
||||
|
||||
If you are unsure which tool to use, start with get_instance_info
|
||||
or use the quickstart prompt for an interactive guide.
|
||||
|
||||
|
||||
@@ -161,6 +161,13 @@ class UserInfo(BaseModel):
|
||||
last_name: str | None = None
|
||||
email: str | None = None
|
||||
active: bool | None = None
|
||||
roles: List[str] = Field(
|
||||
default_factory=list,
|
||||
description=(
|
||||
"Role names assigned to the user (e.g., Admin, Alpha, Gamma, Viewer). "
|
||||
"Use this to determine what actions the user can perform."
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class TagInfo(BaseModel):
|
||||
|
||||
@@ -110,12 +110,23 @@ def get_instance_info(
|
||||
# Attach the authenticated user's identity to the response
|
||||
user = getattr(g, "user", None)
|
||||
if user is not None:
|
||||
raw_roles = getattr(user, "roles", None)
|
||||
user_roles = []
|
||||
if raw_roles is not None:
|
||||
try:
|
||||
user_roles = [
|
||||
role.name for role in raw_roles if hasattr(role, "name")
|
||||
]
|
||||
except TypeError:
|
||||
logger.debug("Could not iterate user.roles: %s", type(raw_roles))
|
||||
user_roles = []
|
||||
result.current_user = UserInfo(
|
||||
id=getattr(user, "id", None),
|
||||
username=getattr(user, "username", None),
|
||||
first_name=getattr(user, "first_name", None),
|
||||
last_name=getattr(user, "last_name", None),
|
||||
email=getattr(user, "email", None),
|
||||
roles=user_roles,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
@@ -213,12 +213,15 @@ class TestGetInstanceInfoCurrentUserViaMCP:
|
||||
# and breaks mock resolution on Python 3.10.
|
||||
from superset.mcp_service.mcp_core import InstanceInfoCore
|
||||
|
||||
mock_role = Mock()
|
||||
mock_role.name = "Alpha"
|
||||
mock_g_user = Mock()
|
||||
mock_g_user.id = 5
|
||||
mock_g_user.username = "sophie"
|
||||
mock_g_user.first_name = "Sophie"
|
||||
mock_g_user.last_name = "Beaumont"
|
||||
mock_g_user.email = "sophie@preset.io"
|
||||
mock_g_user.roles = [mock_role]
|
||||
|
||||
with (
|
||||
patch.object(
|
||||
@@ -241,6 +244,7 @@ class TestGetInstanceInfoCurrentUserViaMCP:
|
||||
assert cu["first_name"] == "Sophie"
|
||||
assert cu["last_name"] == "Beaumont"
|
||||
assert cu["email"] == "sophie@preset.io"
|
||||
assert cu["roles"] == ["Alpha"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_instance_info_no_user_returns_null(self, mcp_server):
|
||||
@@ -295,6 +299,7 @@ class TestGetInstanceInfoCurrentUserViaMCP:
|
||||
assert cu["first_name"] is None
|
||||
assert cu["last_name"] is None
|
||||
assert cu["email"] is None
|
||||
assert cu["roles"] == []
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user