fix(mcp): preserve source_url in GET /v1/mcp/server list responses (#29249)
* fix(mcp): preserve source_url in GET /v1/mcp/server list responses
The list endpoint builds responses from the in-memory registry, but
source_url was dropped during the DB-to-registry roundtrip even though
GET /v1/mcp/server/{id} returned it correctly from the database.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(tests/mcp): set source_url on MagicMock table records
MagicMock auto-creates source_url as a mock object, which fails MCPServer
Pydantic validation after source_url was wired through build_mcp_server_from_table.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
f11c12d157
commit
ace3c65ab3
@ -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,
|
||||
)
|
||||
|
||||
|
||||
@ -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).
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user