mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
fix(jwt-mcp): Add mcp_routes to default team_allowed_routes
This fixes the issue where JWT auth was not selecting teams for MCP routes because MCP routes were not in the default team_allowed_routes. The flow was: 1. JWT auth calls find_team_with_model_access() 2. find_team_with_model_access checks allowed_routes_check() for the route 3. For MCP routes like /mcp/tools/list, this check FAILED because team_allowed_routes only included 'openai_routes' and 'info_routes' 4. Team was NOT selected, team_id was None 5. MCP permission lookup returned empty because team_id was None The fix adds 'mcp_routes' to the default team_allowed_routes so that: - Teams can be selected when accessing MCP endpoints - Team MCP permissions (from object_permission.mcp_servers) are enforced This is the second part of the fix for JWT + MCP permission enforcement. The first part (allowing teams with models=None) was in the previous commit. Changes: - LiteLLM_JWTAuth.team_allowed_routes: Added 'mcp_routes' to default list - allowed_routes_check: Updated fallback to also include 'mcp_routes' - Added test_jwt_auth_allows_mcp_routes_for_teams to verify the fix Co-authored-by: ishaan <ishaan@berri.ai>
This commit is contained in:
parent
adbe869385
commit
e3e037c927
3 changed files with 61 additions and 3 deletions
|
|
@ -3672,7 +3672,7 @@ class LiteLLM_JWTAuth(LiteLLMPydanticObjectBase):
|
|||
team_id_upsert: bool = False
|
||||
team_ids_jwt_field: Optional[str] = None
|
||||
upsert_sso_user_to_team: bool = False
|
||||
team_allowed_routes: List[str] = ["openai_routes", "info_routes"]
|
||||
team_allowed_routes: List[str] = ["openai_routes", "info_routes", "mcp_routes"]
|
||||
team_id_default: Optional[str] = Field(
|
||||
default=None,
|
||||
description="If no team_id given, default permissions/spend-tracking to this team.s",
|
||||
|
|
|
|||
|
|
@ -459,10 +459,11 @@ def allowed_routes_check(
|
|||
elif user_role == LitellmUserRoles.TEAM:
|
||||
if litellm_proxy_roles.team_allowed_routes is None:
|
||||
"""
|
||||
By default allow a team to call openai + info routes
|
||||
By default allow a team to call openai + info + mcp routes
|
||||
"""
|
||||
is_allowed = _allowed_routes_check(
|
||||
user_route=user_route, allowed_routes=["openai_routes", "info_routes"]
|
||||
user_route=user_route,
|
||||
allowed_routes=["openai_routes", "info_routes", "mcp_routes"],
|
||||
)
|
||||
return is_allowed
|
||||
elif litellm_proxy_roles.team_allowed_routes is not None:
|
||||
|
|
|
|||
|
|
@ -962,6 +962,63 @@ async def test_jwt_auth_sets_team_id_for_mcp_permission_lookup(monkeypatch):
|
|||
"Team should have object_permission_id for MCP permissions"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_jwt_auth_allows_mcp_routes_for_teams(monkeypatch):
|
||||
"""
|
||||
Test that JWT auth properly selects a team when accessing MCP routes.
|
||||
|
||||
This tests the fix for the issue where MCP routes were not in the default
|
||||
team_allowed_routes, causing teams to not be selected for MCP requests,
|
||||
which meant team MCP permissions were not enforced.
|
||||
"""
|
||||
from litellm.caching import DualCache
|
||||
from litellm.proxy.utils import ProxyLogging
|
||||
import sys
|
||||
import types
|
||||
|
||||
proxy_server_module = types.ModuleType("proxy_server")
|
||||
proxy_server_module.llm_router = None
|
||||
monkeypatch.setitem(sys.modules, "litellm.proxy.proxy_server", proxy_server_module)
|
||||
|
||||
# Team with models (standard team with model access)
|
||||
team = LiteLLM_TeamTable(
|
||||
team_id="team-with-models",
|
||||
models=["gpt-4", "claude-sonnet"],
|
||||
object_permission_id="obj-perm-456",
|
||||
)
|
||||
|
||||
async def mock_get_team_object(*args, **kwargs):
|
||||
return team
|
||||
|
||||
monkeypatch.setattr(
|
||||
"litellm.proxy.auth.handle_jwt.get_team_object", mock_get_team_object
|
||||
)
|
||||
|
||||
jwt_handler = JWTHandler()
|
||||
jwt_handler.litellm_jwtauth = LiteLLM_JWTAuth()
|
||||
|
||||
user_api_key_cache = DualCache()
|
||||
proxy_logging_obj = ProxyLogging(user_api_key_cache=user_api_key_cache)
|
||||
|
||||
# Test with MCP route - this should now work with the fix
|
||||
team_id, team_obj = await JWTAuthManager.find_team_with_model_access(
|
||||
team_ids={"team-with-models"},
|
||||
requested_model=None, # MCP requests don't specify a model
|
||||
route="/mcp/tools/list", # MCP route - now allowed for teams
|
||||
jwt_handler=jwt_handler,
|
||||
prisma_client=None,
|
||||
user_api_key_cache=user_api_key_cache,
|
||||
parent_otel_span=None,
|
||||
proxy_logging_obj=proxy_logging_obj,
|
||||
)
|
||||
|
||||
# Team should be selected for MCP routes
|
||||
assert team_id == "team-with-models", \
|
||||
"Team should be selected for MCP routes (mcp_routes now in team_allowed_routes)"
|
||||
assert team_obj.team_id == "team-with-models"
|
||||
assert team_obj.object_permission_id == "obj-perm-456"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_auth_builder_returns_team_membership_object():
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue