diff --git a/client/src/lib/configurationTypes.ts b/client/src/lib/configurationTypes.ts index 7c74bb71..c2024e51 100644 --- a/client/src/lib/configurationTypes.ts +++ b/client/src/lib/configurationTypes.ts @@ -33,4 +33,9 @@ export type InspectorConfig = { * The full address of the MCP Proxy Server, in case it is running on a non-default address. Example: http://10.1.1.22:5577 */ MCP_PROXY_FULL_ADDRESS: ConfigItem; + + /** + * Session token for authenticating with the MCP Proxy Server. This token is displayed in the proxy server console on startup. + */ + MCP_PROXY_AUTH_TOKEN: ConfigItem; }; diff --git a/client/src/lib/constants.ts b/client/src/lib/constants.ts index 3acbda91..d1ca972a 100644 --- a/client/src/lib/constants.ts +++ b/client/src/lib/constants.ts @@ -54,4 +54,10 @@ export const DEFAULT_INSPECTOR_CONFIG: InspectorConfig = { "Set this if you are running the MCP Inspector Proxy on a non-default address. Example: http://10.1.1.22:5577", value: "", }, + MCP_PROXY_AUTH_TOKEN: { + label: "Proxy Session Token", + description: + "Session token for authenticating with the MCP Proxy Server (displayed in proxy console on startup)", + value: "", + }, } as const; diff --git a/client/src/lib/hooks/useConnection.ts b/client/src/lib/hooks/useConnection.ts index d42b8d38..c2eccb72 100644 --- a/client/src/lib/hooks/useConnection.ts +++ b/client/src/lib/hooks/useConnection.ts @@ -42,6 +42,7 @@ import { getMCPProxyAddress, getMCPServerRequestMaxTotalTimeout, resetRequestTimeoutOnProgress, + getMCPProxyAuthToken, } from "@/utils/configUtils"; import { getMCPServerRequestTimeout } from "@/utils/configUtils"; import { InspectorConfig } from "../configurationTypes"; @@ -242,7 +243,12 @@ export function useConnection({ const checkProxyHealth = async () => { try { const proxyHealthUrl = new URL(`${getMCPProxyAddress(config)}/health`); - const proxyHealthResponse = await fetch(proxyHealthUrl); + const proxyAuthToken = getMCPProxyAuthToken(config); + const headers: HeadersInit = {}; + if (proxyAuthToken) { + headers['Authorization'] = `Bearer ${proxyAuthToken}`; + } + const proxyHealthResponse = await fetch(proxyHealthUrl, { headers }); const proxyHealth = await proxyHealthResponse.json(); if (proxyHealth?.status !== "ok") { throw new Error("MCP Proxy Server is not healthy"); @@ -261,6 +267,13 @@ export function useConnection({ ); }; + const isProxyAuthError = (error: unknown): boolean => { + return ( + error instanceof Error && + error.message.includes("Authentication required. Use the session token") + ); + }; + const handleAuthError = async (error: unknown) => { if (is401Error(error)) { const serverAuthProvider = new InspectorOAuthClientProvider(sseUrl); @@ -318,6 +331,13 @@ export function useConnection({ } } + // Add proxy authentication + const proxyAuthToken = getMCPProxyAuthToken(config); + const proxyHeaders: HeadersInit = {}; + if (proxyAuthToken) { + proxyHeaders['Authorization'] = `Bearer ${proxyAuthToken}`; + } + // Create appropriate transport let transportOptions: | StreamableHTTPClientTransportOptions @@ -336,10 +356,10 @@ export function useConnection({ fetch: ( url: string | URL | globalThis.Request, init: RequestInit | undefined, - ) => fetch(url, { ...init, headers }), + ) => fetch(url, { ...init, headers: { ...headers, ...proxyHeaders } }), }, requestInit: { - headers, + headers: { ...headers, ...proxyHeaders }, }, }; break; @@ -352,10 +372,10 @@ export function useConnection({ fetch: ( url: string | URL | globalThis.Request, init: RequestInit | undefined, - ) => fetch(url, { ...init, headers }), + ) => fetch(url, { ...init, headers: { ...headers, ...proxyHeaders } }), }, requestInit: { - headers, + headers: { ...headers, ...proxyHeaders }, }, }; break; @@ -368,10 +388,10 @@ export function useConnection({ fetch: ( url: string | URL | globalThis.Request, init: RequestInit | undefined, - ) => fetch(url, { ...init, headers }), + ) => fetch(url, { ...init, headers: { ...headers, ...proxyHeaders } }), }, requestInit: { - headers, + headers: { ...headers, ...proxyHeaders }, }, // TODO these should be configurable... reconnectionOptions: { @@ -447,6 +467,17 @@ export function useConnection({ error, ); + // Check if it's a proxy auth error + if (isProxyAuthError(error)) { + toast({ + title: "Proxy Authentication Required", + description: "Please enter the session token from the proxy server console in the Configuration settings.", + variant: "destructive", + }); + setConnectionStatus("error"); + return; + } + const shouldRetry = await handleAuthError(error); if (shouldRetry) { return connect(undefined, retryCount + 1); diff --git a/client/src/utils/configUtils.ts b/client/src/utils/configUtils.ts index ae404d65..55b29a17 100644 --- a/client/src/utils/configUtils.ts +++ b/client/src/utils/configUtils.ts @@ -28,6 +28,10 @@ export const getMCPServerRequestMaxTotalTimeout = ( return config.MCP_REQUEST_MAX_TOTAL_TIMEOUT.value as number; }; +export const getMCPProxyAuthToken = (config: InspectorConfig): string => { + return config.MCP_PROXY_AUTH_TOKEN.value as string; +}; + const getSearchParam = (key: string): string | null => { try { const url = new URL(window.location.href);