From 4929f50b435bda81f7b1030d3e74c5f0ddcff5d8 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Fri, 5 Jun 2026 05:41:36 +0000 Subject: [PATCH] refactor(ui): route MCP env-var calls through shared http client The merge of litellm_internal_staging brought in the location-pinned fetch() lint rule from #29723, which bans raw fetch() outside src/lib/http/. The three MCP per-user env-var helpers (getMCPUserEnvVars, storeMCPUserEnvVars, listMCPUserEnvVarStatus) still called fetch() directly, pushing networking.tsx to 244 no-restricted-syntax violations against a grandfathered baseline of 241; because bulk suppressions are count-based, the overflow invalidated the whole file's suppression and turned the lint gate red. They now go through the shared apiClient, matching the rest of the file, which keeps the count at the 241 baseline with no new grandfathered suppressions. listMCPUserEnvVarStatus keeps its best-effort empty-list fallback so a failed status fetch still can't break the page --- .../src/components/networking.tsx | 51 ++++--------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 65eeb7d16b5..064db051ef5 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -9641,21 +9641,7 @@ export const listMCPUserCredentials = async (accessToken: string): Promise => { - const url = proxyBaseUrl - ? `${proxyBaseUrl}/v1/mcp/server/${serverId}/user-env-vars` - : `/v1/mcp/server/${serverId}/user-env-vars`; - const response = await fetch(url, { - method: "GET", - headers: { [globalLitellmHeaderName]: `Bearer ${accessToken}` }, - }); - if (!response.ok) { - const err = await response.json().catch(() => ({})); - const detail = (err as { detail?: unknown })?.detail; - const message = - typeof detail === "string" ? detail : (detail as { error?: string })?.error || "Failed to load env vars"; - throw new Error(message); - } - return response.json(); + return apiClient.get(`/v1/mcp/server/${serverId}/user-env-vars`, { accessToken }); }; export const storeMCPUserEnvVars = async ( @@ -9663,35 +9649,20 @@ export const storeMCPUserEnvVars = async ( serverId: string, values: Record, ): Promise => { - const url = proxyBaseUrl - ? `${proxyBaseUrl}/v1/mcp/server/${serverId}/user-env-vars` - : `/v1/mcp/server/${serverId}/user-env-vars`; - const response = await fetch(url, { - method: "POST", - headers: { - [globalLitellmHeaderName]: `Bearer ${accessToken}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ values }), + return apiClient.post(`/v1/mcp/server/${serverId}/user-env-vars`, { + accessToken, + body: { values }, }); - if (!response.ok) { - const err = await response.json().catch(() => ({})); - const detail = (err as { detail?: unknown })?.detail; - const message = - typeof detail === "string" ? detail : (detail as { error?: string })?.error || "Failed to save env vars"; - throw new Error(message); - } - return response.json(); }; export const listMCPUserEnvVarStatus = async (accessToken: string): Promise => { - const url = proxyBaseUrl ? `${proxyBaseUrl}/v1/mcp/user-env-vars/status` : `/v1/mcp/user-env-vars/status`; - const response = await fetch(url, { - method: "GET", - headers: { [globalLitellmHeaderName]: `Bearer ${accessToken}` }, - }); - if (!response.ok) return []; - return response.json(); + // Best-effort status badges: a failure here must not break the page, so fall + // back to an empty list rather than surfacing the error to the caller. + try { + return await apiClient.get("/v1/mcp/user-env-vars/status", { accessToken }); + } catch { + return []; + } }; // ============================================================