mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-24 10:27:13 +00:00
fix: added RFC RECOMMENDED property(scopes_supported) to protected resource and authorization server metadata
This commit is contained in:
@@ -398,8 +398,14 @@ async def callback(code: str, state: str):
|
||||
async def oauth_protected_resource_mcp(
|
||||
request: Request, mcp_server_name: Optional[str] = None
|
||||
):
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
|
||||
global_mcp_server_manager,
|
||||
)
|
||||
# Get the correct base URL considering X-Forwarded-* headers
|
||||
request_base_url = get_request_base_url(request)
|
||||
mcp_server: Optional[MCPServer] = None
|
||||
if mcp_server_name:
|
||||
mcp_server = global_mcp_server_manager.get_mcp_server_by_name(mcp_server_name)
|
||||
return {
|
||||
"authorization_servers": [
|
||||
(
|
||||
@@ -413,6 +419,7 @@ async def oauth_protected_resource_mcp(
|
||||
if mcp_server_name
|
||||
else f"{request_base_url}/mcp"
|
||||
), # this is what Claude will call
|
||||
"scopes_supported": mcp_server.scopes if mcp_server else [],
|
||||
}
|
||||
|
||||
"""
|
||||
@@ -428,6 +435,9 @@ async def oauth_protected_resource_mcp(
|
||||
async def oauth_authorization_server_mcp(
|
||||
request: Request, mcp_server_name: Optional[str] = None
|
||||
):
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
|
||||
global_mcp_server_manager,
|
||||
)
|
||||
# Get the correct base URL considering X-Forwarded-* headers
|
||||
request_base_url = get_request_base_url(request)
|
||||
|
||||
@@ -442,16 +452,21 @@ async def oauth_authorization_server_mcp(
|
||||
else f"{request_base_url}/token"
|
||||
)
|
||||
|
||||
mcp_server: Optional[MCPServer] = None
|
||||
if mcp_server_name:
|
||||
mcp_server = global_mcp_server_manager.get_mcp_server_by_name(mcp_server_name)
|
||||
|
||||
return {
|
||||
"issuer": request_base_url, # point to your proxy
|
||||
"authorization_endpoint": authorization_endpoint,
|
||||
"token_endpoint": token_endpoint,
|
||||
"response_types_supported": ["code"],
|
||||
"scopes_supported": mcp_server.scopes if mcp_server else [],
|
||||
"grant_types_supported": ["authorization_code", "refresh_token"],
|
||||
"code_challenge_methods_supported": ["S256"],
|
||||
"token_endpoint_auth_methods_supported": ["client_secret_post"],
|
||||
# Claude expects a registration endpoint, even if we just fake it
|
||||
"registration_endpoint": f"{request_base_url}/{mcp_server_name}/register",
|
||||
"registration_endpoint": f"{request_base_url}/{mcp_server_name}/register" if mcp_server_name else f"{request_base_url}/register",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -556,9 +556,33 @@ async def test_oauth_protected_resource_respects_x_forwarded_proto():
|
||||
from litellm.proxy._experimental.mcp_server.discoverable_endpoints import (
|
||||
oauth_protected_resource_mcp,
|
||||
)
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
|
||||
global_mcp_server_manager,
|
||||
)
|
||||
from litellm.types.mcp import MCPAuth
|
||||
from litellm.types.mcp_server.mcp_server_manager import MCPServer
|
||||
from litellm.proxy._types import MCPTransport
|
||||
from fastapi import Request
|
||||
except ImportError:
|
||||
pytest.skip("MCP discoverable endpoints not available")
|
||||
# Clear registry
|
||||
global_mcp_server_manager.registry.clear()
|
||||
|
||||
# Create mock OAuth2 server
|
||||
oauth2_server = MCPServer(
|
||||
server_id="test_oauth_server",
|
||||
name="test_oauth",
|
||||
server_name="test_oauth",
|
||||
alias="test_oauth",
|
||||
transport=MCPTransport.http,
|
||||
auth_type=MCPAuth.oauth2,
|
||||
client_id="test_client_id",
|
||||
client_secret="test_client_secret",
|
||||
authorization_url="https://provider.com/oauth/authorize",
|
||||
token_url="https://provider.com/oauth/token",
|
||||
scopes=["read", "write"],
|
||||
)
|
||||
global_mcp_server_manager.registry[oauth2_server.server_id] = oauth2_server
|
||||
|
||||
# Mock request with http base_url but X-Forwarded-Proto: https
|
||||
mock_request = MagicMock(spec=Request)
|
||||
@@ -568,13 +592,14 @@ async def test_oauth_protected_resource_respects_x_forwarded_proto():
|
||||
# Call the endpoint
|
||||
response = await oauth_protected_resource_mcp(
|
||||
request=mock_request,
|
||||
mcp_server_name="test_server",
|
||||
mcp_server_name="test_oauth",
|
||||
)
|
||||
|
||||
# Verify response uses HTTPS URLs
|
||||
assert response["authorization_servers"][0].startswith(
|
||||
"https://litellm.example.com/"
|
||||
)
|
||||
assert response["scopes_supported"] == oauth2_server.scopes
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -584,9 +609,33 @@ async def test_oauth_authorization_server_respects_x_forwarded_proto():
|
||||
from litellm.proxy._experimental.mcp_server.discoverable_endpoints import (
|
||||
oauth_authorization_server_mcp,
|
||||
)
|
||||
from litellm.proxy._experimental.mcp_server.mcp_server_manager import (
|
||||
global_mcp_server_manager,
|
||||
)
|
||||
from litellm.types.mcp import MCPAuth
|
||||
from litellm.types.mcp_server.mcp_server_manager import MCPServer
|
||||
from litellm.proxy._types import MCPTransport
|
||||
from fastapi import Request
|
||||
except ImportError:
|
||||
pytest.skip("MCP discoverable endpoints not available")
|
||||
# Clear registry
|
||||
global_mcp_server_manager.registry.clear()
|
||||
|
||||
# Create mock OAuth2 server
|
||||
oauth2_server = MCPServer(
|
||||
server_id="test_oauth_server",
|
||||
name="test_oauth",
|
||||
server_name="test_oauth",
|
||||
alias="test_oauth",
|
||||
transport=MCPTransport.http,
|
||||
auth_type=MCPAuth.oauth2,
|
||||
client_id="test_client_id",
|
||||
client_secret="test_client_secret",
|
||||
authorization_url="https://provider.com/oauth/authorize",
|
||||
token_url="https://provider.com/oauth/token",
|
||||
scopes=["read", "write"],
|
||||
)
|
||||
global_mcp_server_manager.registry[oauth2_server.server_id] = oauth2_server
|
||||
|
||||
# Mock request with http base_url but X-Forwarded-Proto: https
|
||||
mock_request = MagicMock(spec=Request)
|
||||
@@ -596,7 +645,7 @@ async def test_oauth_authorization_server_respects_x_forwarded_proto():
|
||||
# Call the endpoint
|
||||
response = await oauth_authorization_server_mcp(
|
||||
request=mock_request,
|
||||
mcp_server_name="test_server",
|
||||
mcp_server_name="test_oauth",
|
||||
)
|
||||
|
||||
# Verify response uses HTTPS URLs
|
||||
@@ -604,6 +653,7 @@ async def test_oauth_authorization_server_respects_x_forwarded_proto():
|
||||
assert response["token_endpoint"].startswith("https://litellm.example.com/")
|
||||
assert response["registration_endpoint"].startswith("https://litellm.example.com/")
|
||||
assert response["grant_types_supported"] == ["authorization_code", "refresh_token"]
|
||||
assert response["scopes_supported"] == oauth2_server.scopes
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
Reference in New Issue
Block a user