Skip to content

feat(mcp): expose current user identity in get_instance_info and add created_by_fk filter#37967

Open
aminghadersohi wants to merge 3 commits intoapache:masterfrom
aminghadersohi:amin/mcp-current-user-identity
Open

feat(mcp): expose current user identity in get_instance_info and add created_by_fk filter#37967
aminghadersohi wants to merge 3 commits intoapache:masterfrom
aminghadersohi:amin/mcp-current-user-identity

Conversation

@aminghadersohi
Copy link
Contributor

SUMMARY

The MCP chatbot didn't know who the current user was. When asked "what's the chart I created most recently?", it queried all charts and assumed the user was whoever created the top result (e.g., confused one user with another).

This PR adds:

  1. current_user field to get_instance_info response - exposes authenticated user identity (id, username, first_name, last_name, email) so the LLM knows who it's talking to
  2. created_by_fk filter column on list_charts and list_dashboards - lets the LLM filter assets by creator
  3. Updated LLM instructions - tells the chatbot to greet the user by name and documents the workflow for finding own assets
  4. Fixed parse_request decorator bug - was evaluating MCP_PARSE_REQUEST_ENABLED at decoration time instead of call time, causing string/dict parsing to silently fail when config was False

Architecture / Flow

Before (broken):

User: "What chart did I create most recently?"
  └─> LLM calls list_charts(order_by=created_on, desc)
      └─> Returns ALL charts (no user filtering)
          └─> LLM guesses user = whoever created the top result ❌

After (fixed):

User: "What chart did I create most recently?"
  └─> LLM calls get_instance_info()
      └─> Response includes current_user: {id: 5, username: "sophie", first_name: "Sophie", ...}
          └─> LLM calls list_charts(filters=[{col: "created_by_fk", opr: "eq", value: 5}])
              └─> Returns only Sophie's charts ✅

Data Flow Diagram:

┌──────────┐     ┌──────────────────┐     ┌─────────────────────┐
│ MCP      │────>│ get_instance_info │────>│ Response:           │
│ Client   │     │                  │     │  instance_summary   │
│ (LLM)    │     │ reads Flask g.user│    │  current_user: {    │
│          │     └──────────────────┘     │    id: 5,           │
│          │                              │    username: sophie  │
│          │     ┌──────────────────┐     │    first_name: ...  │
│          │────>│ list_charts      │     │  }                  │
│          │     │ filter:          │     └─────────────────────┘
│          │     │  created_by_fk=5 │────>│ Only Sophie's charts│
└──────────┘     └──────────────────┘     └─────────────────────┘

parse_request decorator fix:

BEFORE (bug):                          AFTER (fix):
┌─────────────────────┐                ┌─────────────────────┐
│ Module load time    │                │ Module load time    │
│ parse_enabled=False │ ← cached once  │ (nothing cached)    │
│                     │                │                     │
│ Request comes in    │                │ Request comes in    │
│ if parse_enabled:   │ ← always False │ if is_enabled():    │ ← checked live
│   parse(request)    │                │   parse(request)    │
│ # never parses! ❌   │                │ # works correctly ✅ │
└─────────────────────┘                └─────────────────────┘

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

N/A - backend/API only change

TESTING INSTRUCTIONS

Automated Tests (18 new tests):

pytest tests/unit_tests/mcp_service/system/tool/test_get_current_user.py -v

QA Steps:

  1. Verify current_user in get_instance_info:

    • Call get_instance_info via MCP client
    • Confirm response includes current_user with id, username, first_name, last_name, email
    • Verify the user info matches the authenticated user
  2. Verify created_by_fk filter on charts:

    • Get your user ID from get_instance_infocurrent_user.id
    • Call list_charts with filter: [{"col": "created_by_fk", "opr": "eq", "value": <your_id>}]
    • Confirm only your charts are returned
    • Try with a non-existent user ID → should return empty
  3. Verify created_by_fk filter on dashboards:

    • Same as step 2 but with list_dashboards
  4. Verify chatbot behavior (end-to-end):

    • Ask the chatbot: "What's the most recent chart I created?"
    • Verify it correctly identifies YOU (not another user)
    • Ask: "List my dashboards" → should filter by your user ID
  5. Verify parse_request fix:

    • Set MCP_PARSE_REQUEST_ENABLED = False in config
    • Call get_schema with a JSON string request
    • Should still work (decorator checks config at call time now)

ADDITIONAL INFORMATION

  • No new tool created - current_user is added to existing get_instance_info response
  • No list_users tool (privacy) - users can only discover their own identity
  • RBAC already limits results to accessible assets, created_by_fk is an additional convenience filter
  • parse_request fix is unrelated but was discovered during testing (decorator was caching config at decoration time)

…created_by_fk filter

Add current_user field to get_instance_info response so the LLM chatbot knows
who the authenticated user is. Add created_by_fk as a filter column to
list_charts and list_dashboards so users can find their own assets.

Also fixes parse_request decorator checking MCP_PARSE_REQUEST_ENABLED at
decoration time instead of call time, and always accepts str in annotations.
@bito-code-review
Copy link
Contributor

bito-code-review bot commented Feb 13, 2026

Code Review Agent Run #59c89a

Actionable Suggestions - 0
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset/mcp_service/system/tool/get_instance_info.py - 1
Review Details
  • Files reviewed - 9 · Commit Range: b2fc851..b2fc851
    • superset/mcp_service/app.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/dashboard/schemas.py
    • superset/mcp_service/system/schemas.py
    • superset/mcp_service/system/tool/get_instance_info.py
    • superset/mcp_service/utils/schema_utils.py
    • tests/unit_tests/mcp_service/system/tool/test_get_current_user.py
    • tests/unit_tests/mcp_service/system/tool/test_get_schema.py
    • tests/unit_tests/mcp_service/utils/test_schema_utils.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@dosubot dosubot bot added the api Related to the REST API label Feb 13, 2026
@netlify
Copy link

netlify bot commented Feb 13, 2026

Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit b2fc851
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/698fa3f8657d8a0008b72ef7
😎 Deploy Preview https://deploy-preview-37967--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Comment on lines 247 to 248
# Simulate no user on g
del mock_g.user
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: The test that simulates the absence of g.user uses del mock_g.user on a MagicMock, but getattr(mock_g, "user", None) will still return a new Mock instead of None, so the production code will think a user exists and try to build a UserInfo from a Mock, causing validation errors and making the test not actually cover the "no user" case. Replace the deletion with explicitly setting mock_g.user = None so getattr(g, "user", None) correctly returns None and current_user remains None as asserted. [logic error]

Severity Level: Major ⚠️
- ❌ Unit test fails with AttributeError in local and CI runs.
- ⚠️ Intended "no current user" behavior remains unverified.
Suggested change
# Simulate no user on g
del mock_g.user
# Simulate no user on g by explicitly setting user to None
mock_g.user = None
Steps of Reproduction ✅
1. Run the specific unit test with the PR code: `pytest
tests/unit_tests/mcp_service/system/tool/test_get_current_user.py::TestGetInstanceInfoCurrentUserViaMCP::test_get_instance_info_no_user_returns_null`.

2. The test enters
`TestGetInstanceInfoCurrentUserViaMCP.test_get_instance_info_no_user_returns_null` at
`tests/unit_tests/mcp_service/system/tool/test_get_current_user.py:239`, where
`InstanceInfoCore.run_tool` is patched and `with patch("flask.g") as mock_g:` is executed
at line 246.

3. At line 248, `del mock_g.user` is executed on the `MagicMock` instance returned by
`patch("flask.g")`. Since `mock_g.user` has never been set on this `MagicMock`, its
`__delattr__` implementation raises `AttributeError: Mock object has no attribute 'user'`.

4. The test fails with an error before the MCP `Client` call at lines 250–251 can execute,
so the code path that should handle "no user on g" (the behavior this test claims to
verify) is never reached. The suggested change to `mock_g.user = None` avoids the
`AttributeError` and allows the test to run while still causing `getattr(g, "user",
None)`-style access in the production code to return `None`.
Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** tests/unit_tests/mcp_service/system/tool/test_get_current_user.py
**Line:** 247:248
**Comment:**
	*Logic Error: The test that simulates the absence of `g.user` uses `del mock_g.user` on a MagicMock, but `getattr(mock_g, "user", None)` will still return a new Mock instead of `None`, so the production code will think a user exists and try to build a `UserInfo` from a Mock, causing validation errors and making the test not actually cover the "no user" case. Replace the deletion with explicitly setting `mock_g.user = None` so `getattr(g, "user", None)` correctly returns `None` and `current_user` remains `None` as asserted.

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.
👍 | 👎

Address code review feedback: use mock_g.user = None instead of
del mock_g.user for clearer intent in test_get_instance_info_no_user_returns_null.
@codecov
Copy link

codecov bot commented Feb 13, 2026

Codecov Report

❌ Patch coverage is 0% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.42%. Comparing base (a65f73a) to head (084452f).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...erset/mcp_service/system/tool/get_instance_info.py 0.00% 6 Missing ⚠️
superset/mcp_service/system/schemas.py 0.00% 2 Missing ⚠️
superset/mcp_service/utils/schema_utils.py 0.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master   #37967       +/-   ##
===========================================
+ Coverage        0   66.42%   +66.42%     
===========================================
  Files           0      668      +668     
  Lines           0    51328    +51328     
  Branches        0     5777     +5777     
===========================================
+ Hits            0    34096    +34096     
- Misses          0    15846    +15846     
- Partials        0     1386     +1386     
Flag Coverage Δ
hive 41.47% <0.00%> (?)
mysql 64.53% <0.00%> (?)
postgres 64.60% <0.00%> (?)
presto 41.48% <0.00%> (?)
python 66.40% <0.00%> (?)
sqlite 64.20% <0.00%> (?)
unit 100.00% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions github-actions bot removed the api Related to the REST API label Feb 13, 2026
The MCP client integration tests used a dotted string path to patch
InstanceInfoCore.run_tool, but __init__.py re-exports get_instance_info
as a function, which shadows the submodule name and breaks mock
resolution on Python 3.10. Switch to patch.object(InstanceInfoCore, ...)
which patches the method on the class and works across all versions.
Copy link
Contributor Author

@aminghadersohi aminghadersohi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — applied the fix in 35f2f3b. Using mock_g.user = None is clearer and avoids any MagicMock __delattr__ subtlety. Thanks!

(Responding on behalf of @aminghadersohi)

@bito-code-review
Copy link
Contributor

bito-code-review bot commented Feb 13, 2026

Code Review Agent Run #56dcd2

Actionable Suggestions - 0
Review Details
  • Files reviewed - 9 · Commit Range: b2fc851..084452f
    • superset/mcp_service/app.py
    • superset/mcp_service/chart/schemas.py
    • superset/mcp_service/dashboard/schemas.py
    • superset/mcp_service/system/schemas.py
    • superset/mcp_service/system/tool/get_instance_info.py
    • superset/mcp_service/utils/schema_utils.py
    • tests/unit_tests/mcp_service/system/tool/test_get_current_user.py
    • tests/unit_tests/mcp_service/system/tool/test_get_schema.py
    • tests/unit_tests/mcp_service/utils/test_schema_utils.py
  • Files skipped - 0
  • Tools
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant