fix(mcp): add safeguards to ensure all MCP tools are wrapped with mcp_auth_hook#40412
Conversation
Code Review Agent Run #54e736Actionable Suggestions - 0Review Details
Bito Usage GuideCommands Type the following command in the pull request comment and save the comment.
Refer to the documentation for additional commands. Configuration This repository uses Documentation & Help |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #40412 +/- ##
==========================================
- Coverage 64.20% 64.19% -0.01%
==========================================
Files 2592 2592
Lines 139232 139245 +13
Branches 32327 32331 +4
==========================================
+ Hits 89390 89393 +3
- Misses 48307 48317 +10
Partials 1535 1535
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
SUMMARY
Fixes #39395. Implements the three structural safeguards @mistercrunch outlined in the issue body, plus a single allowlist for the one intentionally-public tool.
The race-condition fix in #39385 only protects tools that actually go through
mcp_auth_hook. This PR makes that invariant enforceable at startup rather than convention-based.Changes
1.
superset/mcp_service/auth.py— stamp a marker on the wrapper at the end ofmcp_auth_hook:2.
superset/core/mcp/core_mcp_injection.py— fail-fast increate_tool_decorator: the prior path silently returned the unwrapped function on error, which is exactly one of the bypass paths the issue calls out.3.
superset/mcp_service/app.py—assert_all_tools_protected(mcp)invoked at the end ofinit_fastmcp_server(). Iteratesmcp.local_provider._components, filters totool:entries (FastMCP 3.x keys all components in one dict), and raises aRuntimeErrorfor any tool whose.fnlacks the marker.The original spec used
mcp._tool_manager._tools— that attribute doesn't exist on FastMCP 3.x (the version pinned inpyproject.toml). The current iteration path is the closest stable equivalent.local_provider.remove_tool()is already used elsewhere in the codebase (MCP_DISABLED_TOOLSflow), so reaching intolocal_providermatches existing practice.4.
ALLOWED_UNPROTECTEDinapp.py— contains a single entry,generate_bug_report, which is the only tool in the codebase deliberately decorated with@tool(protect=False)(so users can collect diagnostics even when auth itself is broken).TESTING INSTRUCTIONS
Five new tests cover:
test_mcp_auth_hook_stamps_protection_marker— wrapper carries the markertest_assert_all_tools_protected_passes_when_every_tool_is_marked— happy pathtest_assert_all_tools_protected_raises_on_unprotected_tool— bypass paths blow uptest_assert_all_tools_protected_respects_allowlist— allowlist works as the only legitimate escape hatchtest_create_tool_decorator_fails_fast_on_registration_error— silent-fallback path is goneExisting
test_mcp_tool_registration.py(13 tests) continues to pass — the new assertion runs as part ofinit_fastmcp_server()against the real tool registry and validates that every shipped tool exceptgenerate_bug_reportis properly wrapped.ADDITIONAL INFORMATION