mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-25 01:02:15 +00:00
fix(mcp): respect client ip for delegated auth
This commit is contained in:
parent
b4df1a9bde
commit
eae390b16d
2 changed files with 16 additions and 10 deletions
|
|
@ -179,7 +179,9 @@ class MCPRequestHandler:
|
|||
elif (
|
||||
not litellm_api_key
|
||||
and MCPRequestHandler._target_servers_delegate_auth_to_upstream( # noqa: E501
|
||||
path=request.url.path, mcp_servers=mcp_servers
|
||||
path=request.url.path,
|
||||
mcp_servers=mcp_servers,
|
||||
client_ip=IPAddressUtils.get_mcp_client_ip(request),
|
||||
)
|
||||
):
|
||||
# Operator opted this oauth2 server into upstream-delegated auth
|
||||
|
|
@ -379,7 +381,7 @@ class MCPRequestHandler:
|
|||
|
||||
@staticmethod
|
||||
def _target_servers_delegate_auth_to_upstream(
|
||||
path: str, mcp_servers: Optional[List[str]]
|
||||
path: str, mcp_servers: Optional[List[str]], client_ip: Optional[str]
|
||||
) -> bool:
|
||||
"""
|
||||
True only when EVERY MCP server the request targets is configured for
|
||||
|
|
@ -409,7 +411,9 @@ class MCPRequestHandler:
|
|||
return False
|
||||
|
||||
for name in target_names:
|
||||
server = global_mcp_server_manager.get_mcp_server_by_name(name)
|
||||
server = global_mcp_server_manager.get_mcp_server_by_name(
|
||||
name, client_ip=client_ip
|
||||
)
|
||||
if server is None or server.auth_type != MCPAuth.oauth2:
|
||||
return False
|
||||
# `is True` is intentional: opt-in must be an explicit boolean
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import json
|
||||
import os
|
||||
import sys
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
from unittest.mock import AsyncMock, MagicMock, call as mock_call, patch
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
|
@ -918,7 +918,9 @@ class TestMCPPassthroughColdStartAdmission:
|
|||
await MCPRequestHandler.process_mcp_request(scope)
|
||||
|
||||
assert exc_info.value.status_code == 401
|
||||
mock_mgr.get_mcp_server_by_name.assert_not_called()
|
||||
mock_mgr.get_mcp_server_by_name.assert_called_once_with(
|
||||
"passthrough_server", client_ip=""
|
||||
)
|
||||
|
||||
async def test_cold_start_rejects_server_specific_authorization_header(self):
|
||||
from fastapi import HTTPException
|
||||
|
|
@ -1016,7 +1018,7 @@ class TestMCPPassthroughColdStartAdmission:
|
|||
await MCPRequestHandler.process_mcp_request(scope)
|
||||
|
||||
assert exc_info.value.status_code == 401
|
||||
mock_mgr.get_mcp_server_by_name.assert_called_once_with(
|
||||
assert mock_mgr.get_mcp_server_by_name.call_args_list[-1] == mock_call(
|
||||
"passthrough_server", client_ip="203.0.113.10"
|
||||
)
|
||||
|
||||
|
|
@ -1111,7 +1113,7 @@ class TestMCPPassthroughColdStartAdmission:
|
|||
(auth_result, *_rest) = await MCPRequestHandler.process_mcp_request(scope)
|
||||
|
||||
assert isinstance(auth_result, UserAPIKeyAuth)
|
||||
mock_mgr.get_mcp_server_by_name.assert_called_once_with(
|
||||
assert mock_mgr.get_mcp_server_by_name.call_args_list[-1] == mock_call(
|
||||
"passthrough_server", client_ip=""
|
||||
)
|
||||
|
||||
|
|
@ -1148,7 +1150,7 @@ class TestMCPPassthroughColdStartAdmission:
|
|||
(auth_result, *_rest) = await MCPRequestHandler.process_mcp_request(scope)
|
||||
|
||||
assert isinstance(auth_result, UserAPIKeyAuth)
|
||||
mock_mgr.get_mcp_server_by_name.assert_called_once_with(
|
||||
assert mock_mgr.get_mcp_server_by_name.call_args_list[-1] == mock_call(
|
||||
"passthrough_server", client_ip=""
|
||||
)
|
||||
|
||||
|
|
@ -1996,7 +1998,7 @@ class TestMCPDelegateAuthToUpstream:
|
|||
delegate_auth_to_upstream=True,
|
||||
)
|
||||
|
||||
def lookup_by_name(name):
|
||||
def lookup_by_name(name, **_kwargs):
|
||||
# Only the *exact* delegated name resolves. Anything else (e.g.
|
||||
# ``delegated_server/extra``) returns None so the bypass fails.
|
||||
if name == "delegated_server":
|
||||
|
|
@ -2059,7 +2061,7 @@ class TestMCPDelegateAuthToUpstream:
|
|||
auth_type=MCPAuth.api_key,
|
||||
)
|
||||
|
||||
def lookup_by_name(name):
|
||||
def lookup_by_name(name, **_kwargs):
|
||||
return {
|
||||
"delegated_server": delegate_server,
|
||||
"non_delegate_server": non_delegate,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue