diff --git a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py index d0e9ad7b2a..f35aa30a7c 100644 --- a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py +++ b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py @@ -892,6 +892,7 @@ class MCPServerManager: is_byok=bool(getattr(mcp_server, "is_byok", False)), byok_description=getattr(mcp_server, "byok_description", None) or [], byok_api_key_help_url=getattr(mcp_server, "byok_api_key_help_url", None), + source_url=getattr(mcp_server, "source_url", None), # AWS SigV4 fields aws_access_key_id=aws_creds.get("aws_access_key_id"), aws_secret_access_key=aws_creds.get("aws_secret_access_key"), @@ -3750,6 +3751,7 @@ class MCPServerManager: is_byok=server.is_byok, byok_description=server.byok_description, byok_api_key_help_url=server.byok_api_key_help_url, + source_url=server.source_url, instructions=server.instructions, ) diff --git a/litellm/types/mcp_server/mcp_server_manager.py b/litellm/types/mcp_server/mcp_server_manager.py index 776c7fa67a..13e325838d 100644 --- a/litellm/types/mcp_server/mcp_server_manager.py +++ b/litellm/types/mcp_server/mcp_server_manager.py @@ -77,6 +77,7 @@ class MCPServer(BaseModel): is_byok: bool = False byok_description: List[str] = [] byok_api_key_help_url: Optional[str] = None + source_url: Optional[str] = None created_at: Optional[datetime] = None updated_at: Optional[datetime] = None # OAuth2 flow type. Defaults to None (interactive / authorization_code). diff --git a/tests/mcp_tests/test_mcp_server.py b/tests/mcp_tests/test_mcp_server.py index 27df05225e..d76ebb0072 100644 --- a/tests/mcp_tests/test_mcp_server.py +++ b/tests/mcp_tests/test_mcp_server.py @@ -1505,6 +1505,7 @@ async def test_add_update_server_with_alias(): mock_mcp_server.created_at = None mock_mcp_server.updated_at = None mock_mcp_server.instructions = None + mock_mcp_server.source_url = None mock_mcp_server.approval_status = "active" # Add server to manager @@ -1563,6 +1564,7 @@ async def test_add_update_server_without_alias(): mock_mcp_server.created_at = None mock_mcp_server.updated_at = None mock_mcp_server.instructions = None + mock_mcp_server.source_url = None mock_mcp_server.approval_status = "active" # Add server to manager @@ -1622,6 +1624,7 @@ async def test_add_update_server_fallback_to_server_id(): mock_mcp_server.created_at = None mock_mcp_server.updated_at = None mock_mcp_server.instructions = None + mock_mcp_server.source_url = None mock_mcp_server.approval_status = "active" # Add server to manager await test_manager.add_server(mock_mcp_server) diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server_manager.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server_manager.py index d7078412a4..2db9845c76 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server_manager.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server_manager.py @@ -2888,6 +2888,31 @@ class TestMCPServerTimestamps: assert rebuilt_table.created_at == created assert rebuilt_table.updated_at == updated + @pytest.mark.asyncio + async def test_round_trip_source_url_preserved(self): + """source_url survives the full round-trip: LiteLLM_MCPServerTable -> MCPServer -> LiteLLM_MCPServerTable. + + Regression test: the list endpoint (GET /v1/mcp/server) builds its + response from the registry via this round-trip, so a dropped field + here surfaces as a null source_url in the list response even though + the value is stored in the DB. + """ + manager = MCPServerManager() + + table_record = LiteLLM_MCPServerTable( + server_id="src-url-server", + server_name="src_url_server", + url="https://example.com/mcp", + transport=MCPTransport.http, + source_url="https://github.com/org/mcp-server", + ) + + mcp_server = await manager.build_mcp_server_from_table(table_record) + assert mcp_server.source_url == "https://github.com/org/mcp-server" + + rebuilt_table = manager._build_mcp_server_table(mcp_server) + assert rebuilt_table.source_url == "https://github.com/org/mcp-server" + class TestInternalDelegatePkceWarningLog: @pytest.mark.asyncio diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_sigv4_auth.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_sigv4_auth.py index 32b988ddb2..0c2a8bb808 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_sigv4_auth.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_sigv4_auth.py @@ -857,6 +857,7 @@ class TestSigV4BuildFromTable: table_record.byok_api_key_help_url = None table_record.oauth2_flow = None table_record.instructions = None + table_record.source_url = None manager = MCPServerManager() @@ -915,6 +916,7 @@ class TestSigV4BuildFromTable: table_record.byok_api_key_help_url = None table_record.oauth2_flow = None table_record.instructions = None + table_record.source_url = None manager = MCPServerManager()