mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
fix(mcp): preserve env_vars in registry to table conversion
The GET /v1/mcp/server list and health endpoints build LiteLLM_MCPServerTable
from the in-memory registry via _build_mcp_server_table and health_check_server.
Both copied static_headers but dropped env_vars, so the list always returned
env_vars: null. The admin edit form is populated from that list data, so it
loaded an empty env-var list; saving any edit then persisted env_vars: [],
silently wiping the stored variables. With nothing left to interpolate, the
${VAR} static headers were forwarded upstream verbatim as literal text.
Carry env_vars through both conversions, mirroring static_headers. Add
regression tests asserting both paths round-trip name, scope, value, and
description.
This commit is contained in:
parent
ba20078c05
commit
8852c0df95
2 changed files with 62 additions and 0 deletions
|
|
@ -3957,6 +3957,7 @@ class MCPServerManager:
|
|||
extra_headers=server.extra_headers or [],
|
||||
mcp_info=server.mcp_info,
|
||||
static_headers=server.static_headers,
|
||||
env_vars=server.env_vars,
|
||||
status=status,
|
||||
last_health_check=datetime.now(),
|
||||
health_check_error=health_check_error,
|
||||
|
|
@ -4049,6 +4050,7 @@ class MCPServerManager:
|
|||
extra_headers=server.extra_headers or [],
|
||||
mcp_info=server.mcp_info,
|
||||
static_headers=server.static_headers,
|
||||
env_vars=server.env_vars,
|
||||
status=None, # No health check performed
|
||||
last_health_check=None, # No health check performed
|
||||
health_check_error=None,
|
||||
|
|
|
|||
|
|
@ -4038,5 +4038,65 @@ class TestApprovalStatusGate:
|
|||
assert "never-seen" not in manager.registry
|
||||
|
||||
|
||||
class TestRegistryTableConversionPreservesEnvVars:
|
||||
"""The registry ``MCPServer`` -> ``LiteLLM_MCPServerTable`` conversions back
|
||||
the GET /v1/mcp/server list and health responses, which populate the admin
|
||||
edit form. When they dropped ``env_vars`` the form loaded an empty list and
|
||||
saving any edit silently wiped the stored vars, so ``${VAR}`` static headers
|
||||
were forwarded upstream un-interpolated.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def _server_with_env_vars() -> MCPServer:
|
||||
return MCPServer(
|
||||
server_id="env-vars-server",
|
||||
name="env_vars_server",
|
||||
url="https://example.com/mcp",
|
||||
transport=MCPTransport.http,
|
||||
auth_type=MCPAuth.oauth2,
|
||||
static_headers={"X-Db-Url": "${DB_PROTOCOL}://${CORP_USER}@${DB_HOST}"},
|
||||
env_vars=[
|
||||
{
|
||||
"name": "DB_PROTOCOL",
|
||||
"value": "postgresql",
|
||||
"scope": "global",
|
||||
"description": None,
|
||||
},
|
||||
{
|
||||
"name": "CORP_USER",
|
||||
"value": "",
|
||||
"scope": "user",
|
||||
"description": "Your DB username",
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _assert_env_vars_round_tripped(table: LiteLLM_MCPServerTable) -> None:
|
||||
assert table.env_vars is not None
|
||||
by_name = {entry.name: entry for entry in table.env_vars}
|
||||
assert set(by_name) == {"DB_PROTOCOL", "CORP_USER"}
|
||||
assert by_name["DB_PROTOCOL"].scope == MCPEnvVarScope.global_
|
||||
assert by_name["DB_PROTOCOL"].value == "postgresql"
|
||||
assert by_name["CORP_USER"].scope == MCPEnvVarScope.user
|
||||
assert by_name["CORP_USER"].description == "Your DB username"
|
||||
|
||||
def test_build_mcp_server_table_preserves_env_vars(self):
|
||||
manager = MCPServerManager()
|
||||
table = manager._build_mcp_server_table(self._server_with_env_vars())
|
||||
self._assert_env_vars_round_tripped(table)
|
||||
|
||||
async def test_health_check_server_preserves_env_vars(self):
|
||||
# OAuth2 without client credentials needs a per-user token, so the
|
||||
# health check is skipped (no network) and we exercise the table
|
||||
# construction path directly.
|
||||
manager = MCPServerManager()
|
||||
server = self._server_with_env_vars()
|
||||
assert server.requires_per_user_auth is True
|
||||
manager.registry[server.server_id] = server
|
||||
table = await manager.health_check_server(server.server_id)
|
||||
self._assert_env_vars_round_tripped(table)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__])
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue