You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
mcpgateway/main.py contains roughly 22 near-identical inline copies of the Layer-1 admin-bypass + public-only-secure-default derivation across REST endpoint handlers (list_tools, list_resources, list_prompts, list_a2a_agents, list_tags, get_entities_by_tag, several JSON-RPC dispatcher branches, etc.). Each call site looks roughly like:
user_email, token_teams, is_admin=get_rpc_filter_context(request, user)
ifis_adminandtoken_teamsisNone:
user_email=Nonetoken_teams=None# Admin unrestrictedeliftoken_teamsisNone:
token_teams= [] # Non-admin without teams = public-only (secure default)
mcpgateway/auth_context.py already provides get_scoped_resource_access_context(request, user) that encapsulates exactly this rule (and get_request_identity for the auditor-identity portion).
PR #4080 commit a1acd3691 ("refactor(main): centralize Layer-1 visibility filter via auth_context helpers") replaced the 22 inline copies with calls to get_scoped_resource_access_context / get_request_identity. That commit has been reverted because:
Test churn: 14+ tests had to switch their @patch targets, several broke in subtle ways during rebases.
Latent behavior change: get_scoped_resource_access_context correctly enables Layer-1 admin bypass for basic-auth/dev-mode admins (which the inline rule missed). This is technically a bug-fix bundled with the refactor — separating the two would be cleaner.
Acceptance criteria
All 22 inline Layer-1 derivations in main.py replaced with calls to get_scoped_resource_access_context(request, user) (and get_request_identity where the audit-identity values are also needed).
4 known exceptions retained: a2a get_agent and invoke_agent (preserve user_email for federation user_id construction), _get_internal_a2a_scope_context (custom return contract), and the internal MCP tools/invoke handler that captures run_owner_email / run_owner_team_ids before applying the rule.
Tests updated to mock get_scoped_resource_access_context (post-rule 2-tuple) instead of the lower-level get_rpc_filter_context (pre-rule 3-tuple).
The basic-auth/dev-mode admin behavior change is documented in the commit message and covered by a regression test.
Out of scope for this issue
Anything in streamablehttp_transport.py — see the companion issue.
Background
mcpgateway/main.pycontains roughly 22 near-identical inline copies of the Layer-1 admin-bypass + public-only-secure-default derivation across REST endpoint handlers (list_tools,list_resources,list_prompts,list_a2a_agents,list_tags,get_entities_by_tag, several JSON-RPC dispatcher branches, etc.). Each call site looks roughly like:mcpgateway/auth_context.pyalready providesget_scoped_resource_access_context(request, user)that encapsulates exactly this rule (andget_request_identityfor the auditor-identity portion).Why this matters
token_teams = Nonefor admin, mixed audit-context capture patterns).routers/teams.py: the team router was migrated tois_admin_bypass_grantedin PR SSO (Entra ID) users cannot edit gateways/servers in admin UI — 'invalid team name' error despite ["*"] effective permissions #4070-related work; main.py REST endpoints should follow.What was attempted
PR #4080 commit
a1acd3691("refactor(main): centralize Layer-1 visibility filter via auth_context helpers") replaced the 22 inline copies with calls toget_scoped_resource_access_context/get_request_identity. That commit has been reverted because:@patchtargets, several broke in subtle ways during rebases.get_scoped_resource_access_contextcorrectly enables Layer-1 admin bypass for basic-auth/dev-mode admins (which the inline rule missed). This is technically a bug-fix bundled with the refactor — separating the two would be cleaner.Acceptance criteria
main.pyreplaced with calls toget_scoped_resource_access_context(request, user)(andget_request_identitywhere the audit-identity values are also needed).a2a get_agentandinvoke_agent(preserveuser_emailfor federationuser_idconstruction),_get_internal_a2a_scope_context(custom return contract), and the internal MCPtools/invokehandler that capturesrun_owner_email/run_owner_team_idsbefore applying the rule.get_scoped_resource_access_context(post-rule 2-tuple) instead of the lower-levelget_rpc_filter_context(pre-rule 3-tuple).Out of scope for this issue
streamablehttp_transport.py— see the companion issue.routers/teams.py(already migrated).References