fix(mcp): narrow liveness failures and clarify health tooltip

This commit is contained in:
moe-berri 2026-09-24 15:53:38 -07:00
parent dca1d06065
commit ae25511430
3 changed files with 22 additions and 16 deletions

View file

@ -6917,14 +6917,16 @@ class MCPServerManager:
async def _check_mcp_liveness(url: str) -> tuple[Literal["healthy", "unhealthy", "unknown"], str | None]:
async def probe() -> None:
endpoint: Final = httpx.URL(url).copy_with(username="", password="")
async with httpx.AsyncClient(
verify=get_ssl_configuration(),
trust_env=False,
follow_redirects=False,
timeout=MCP_HEALTH_CHECK_TIMEOUT,
) as client:
async with client.stream("GET", endpoint, auth=None):
pass
async with (
httpx.AsyncClient(
verify=get_ssl_configuration(),
trust_env=False,
follow_redirects=False,
timeout=MCP_HEALTH_CHECK_TIMEOUT,
) as client,
client.stream("GET", endpoint, auth=None),
):
pass
try:
await asyncio.wait_for(probe(), timeout=MCP_HEALTH_CHECK_TIMEOUT)
@ -6933,7 +6935,7 @@ class MCPServerManager:
return "unhealthy", f"Health check timed out after {MCP_HEALTH_CHECK_TIMEOUT} seconds"
except asyncio.CancelledError:
return "unknown", "Health check was cancelled"
except Exception as exc:
except (httpx.HTTPError, httpx.InvalidURL, OSError, ValueError) as exc:
return "unhealthy", f"Liveness check failed ({type(exc).__name__})"
async def health_check_server(self, server_id: str, mcp_auth_header: str | None = None) -> LiteLLM_MCPServerTable:
@ -6994,12 +6996,14 @@ class MCPServerManager:
):
liveness_status, liveness_error = await self._check_mcp_liveness(server.url)
return self._build_mcp_server_table(server).model_copy(
update={
"status": liveness_status,
"health_check_error": liveness_error,
"health_check_type": "liveness",
"last_health_check": datetime.now(),
}
update=MappingProxyType(
{
"status": liveness_status,
"health_check_error": liveness_error,
"health_check_type": "liveness",
"last_health_check": datetime.now(),
}
)
)
if not should_skip_health_check:

View file

@ -725,6 +725,7 @@ class TestListMCPServers:
# Mock health check result as LiteLLM_MCPServerTable
mock_health_result = generate_mock_mcp_server_db_record(server_id="server-1", alias="Server 1")
mock_health_result.status = "healthy"
mock_health_result.health_check_type = "liveness"
mock_health_result.last_health_check = datetime.now()
mock_health_result.health_check_error = None
@ -762,6 +763,7 @@ class TestListMCPServers:
assert result.credentials is None
assert mock_server.credentials == {"auth_value": "top-secret"}
assert result.status == "healthy"
assert result.health_check_type == "liveness"
@pytest.mark.asyncio
async def test_fetch_single_mcp_server_preserves_upstream_resource_for_admin(self):

View file

@ -360,7 +360,7 @@ const HealthChip: FC<HealthChipProps> = ({
</Badge>
}
/>
<TooltipContent side="top" className="max-w-xs">
<TooltipContent side="top" className="block max-w-xs">
<div className="mb-1 font-semibold">Health: {label}</div>
{healthCheckType === "liveness" && (
<div className="mb-1 text-xs">Authentication and tools were not checked</div>