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:
parent
111e282386
commit
908d0ee36a
4 changed files with 53 additions and 7 deletions
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue