feat: add client support for proxy authentication

- Add MCP_PROXY_AUTH_TOKEN configuration field to store session token
- Update useConnection hook to include proxy auth token in all requests
- Add separate proxy auth headers to avoid conflicts with MCP server auth
- Add specific error handling for proxy authentication failures
- Show helpful toast message directing users to Configuration settings
- Update README with instructions for configuring token in UI

The client now properly authenticates with the proxy server using the
session token displayed in the proxy console.
This commit is contained in:
Felix Weinberger 2025-06-10 14:12:54 +01:00
commit 908d0ee36a
No known key found for this signature in database
4 changed files with 53 additions and 7 deletions

View file

@ -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;
};

View file

@ -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;

View file

@ -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);

View file

@ -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);