Merge branch 'main' into completion-support-default
This commit is contained in:
commit
e106194b40
1 changed files with 5383 additions and 929 deletions
|
|
@ -42,9 +42,11 @@ import {
|
|||
getMCPProxyAddress,
|
||||
getMCPServerRequestMaxTotalTimeout,
|
||||
resetRequestTimeoutOnProgress,
|
||||
getMCPProxyAuthToken,
|
||||
} from "@/utils/configUtils";
|
||||
import { getMCPServerRequestTimeout } from "@/utils/configUtils";
|
||||
import { InspectorConfig } from "../configurationTypes";
|
||||
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
||||
|
||||
interface UseConnectionOptions {
|
||||
transportType: "stdio" | "sse" | "streamable-http";
|
||||
|
|
@ -83,6 +85,9 @@ export function useConnection({
|
|||
const [serverCapabilities, setServerCapabilities] =
|
||||
useState<ServerCapabilities | null>(null);
|
||||
const [mcpClient, setMcpClient] = useState<Client | null>(null);
|
||||
const [clientTransport, setClientTransport] = useState<Transport | null>(
|
||||
null,
|
||||
);
|
||||
const [requestHistory, setRequestHistory] = useState<
|
||||
{ request: string; response?: string }[]
|
||||
>([]);
|
||||
|
|
@ -238,7 +243,13 @@ export function useConnection({
|
|||
const checkProxyHealth = async () => {
|
||||
try {
|
||||
const proxyHealthUrl = new URL(`${getMCPProxyAddress(config)}/health`);
|
||||
const proxyHealthResponse = await fetch(proxyHealthUrl);
|
||||
const { token: proxyAuthToken, header: proxyAuthTokenHeader } =
|
||||
getMCPProxyAuthToken(config);
|
||||
const headers: HeadersInit = {};
|
||||
if (proxyAuthToken) {
|
||||
headers[proxyAuthTokenHeader] = `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");
|
||||
|
|
@ -257,6 +268,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);
|
||||
|
|
@ -304,7 +322,22 @@ export function useConnection({
|
|||
bearerToken || (await serverAuthProvider.tokens())?.access_token;
|
||||
if (token) {
|
||||
const authHeaderName = headerName || "Authorization";
|
||||
headers[authHeaderName] = `Bearer ${token}`;
|
||||
|
||||
// Add custom header name as a special request header to let the server know which header to pass through
|
||||
if (authHeaderName.toLowerCase() !== "authorization") {
|
||||
headers[authHeaderName] = token;
|
||||
headers["x-custom-auth-header"] = authHeaderName;
|
||||
} else {
|
||||
headers[authHeaderName] = `Bearer ${token}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Add proxy authentication
|
||||
const { token: proxyAuthToken, header: proxyAuthTokenHeader } =
|
||||
getMCPProxyAuthToken(config);
|
||||
const proxyHeaders: HeadersInit = {};
|
||||
if (proxyAuthToken) {
|
||||
proxyHeaders[proxyAuthTokenHeader] = `Bearer ${proxyAuthToken}`;
|
||||
}
|
||||
|
||||
// Create appropriate transport
|
||||
|
|
@ -324,11 +357,15 @@ export function useConnection({
|
|||
eventSourceInit: {
|
||||
fetch: (
|
||||
url: string | URL | globalThis.Request,
|
||||
init: RequestInit | undefined,
|
||||
) => fetch(url, { ...init, headers }),
|
||||
init?: RequestInit,
|
||||
) =>
|
||||
fetch(url, {
|
||||
...init,
|
||||
headers: { ...headers, ...proxyHeaders },
|
||||
}),
|
||||
},
|
||||
requestInit: {
|
||||
headers,
|
||||
headers: { ...headers, ...proxyHeaders },
|
||||
},
|
||||
};
|
||||
break;
|
||||
|
|
@ -340,11 +377,15 @@ export function useConnection({
|
|||
eventSourceInit: {
|
||||
fetch: (
|
||||
url: string | URL | globalThis.Request,
|
||||
init: RequestInit | undefined,
|
||||
) => fetch(url, { ...init, headers }),
|
||||
init?: RequestInit,
|
||||
) =>
|
||||
fetch(url, {
|
||||
...init,
|
||||
headers: { ...headers, ...proxyHeaders },
|
||||
}),
|
||||
},
|
||||
requestInit: {
|
||||
headers,
|
||||
headers: { ...headers, ...proxyHeaders },
|
||||
},
|
||||
};
|
||||
break;
|
||||
|
|
@ -356,11 +397,15 @@ export function useConnection({
|
|||
eventSourceInit: {
|
||||
fetch: (
|
||||
url: string | URL | globalThis.Request,
|
||||
init: RequestInit | undefined,
|
||||
) => fetch(url, { ...init, headers }),
|
||||
init?: RequestInit,
|
||||
) =>
|
||||
fetch(url, {
|
||||
...init,
|
||||
headers: { ...headers, ...proxyHeaders },
|
||||
}),
|
||||
},
|
||||
requestInit: {
|
||||
headers,
|
||||
headers: { ...headers, ...proxyHeaders },
|
||||
},
|
||||
// TODO these should be configurable...
|
||||
reconnectionOptions: {
|
||||
|
|
@ -377,14 +422,6 @@ export function useConnection({
|
|||
transportType,
|
||||
);
|
||||
|
||||
const clientTransport =
|
||||
transportType === "streamable-http"
|
||||
? new StreamableHTTPClientTransport(mcpProxyServerUrl as URL, {
|
||||
sessionId: undefined,
|
||||
...transportOptions,
|
||||
})
|
||||
: new SSEClientTransport(mcpProxyServerUrl as URL, transportOptions);
|
||||
|
||||
if (onNotification) {
|
||||
[
|
||||
CancelledNotificationSchema,
|
||||
|
|
@ -414,7 +451,20 @@ export function useConnection({
|
|||
|
||||
let capabilities;
|
||||
try {
|
||||
await client.connect(clientTransport);
|
||||
const transport =
|
||||
transportType === "streamable-http"
|
||||
? new StreamableHTTPClientTransport(mcpProxyServerUrl as URL, {
|
||||
sessionId: undefined,
|
||||
...transportOptions,
|
||||
})
|
||||
: new SSEClientTransport(
|
||||
mcpProxyServerUrl as URL,
|
||||
transportOptions,
|
||||
);
|
||||
|
||||
await client.connect(transport as Transport);
|
||||
|
||||
setClientTransport(transport);
|
||||
|
||||
capabilities = client.getServerCapabilities();
|
||||
const initializeRequest = {
|
||||
|
|
@ -431,6 +481,18 @@ 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);
|
||||
|
|
@ -468,10 +530,15 @@ export function useConnection({
|
|||
};
|
||||
|
||||
const disconnect = async () => {
|
||||
if (transportType === "streamable-http")
|
||||
await (
|
||||
clientTransport as StreamableHTTPClientTransport
|
||||
).terminateSession();
|
||||
await mcpClient?.close();
|
||||
const authProvider = new InspectorOAuthClientProvider(sseUrl);
|
||||
authProvider.clear();
|
||||
setMcpClient(null);
|
||||
setClientTransport(null);
|
||||
setConnectionStatus("disconnected");
|
||||
setCompletionsSupported(false);
|
||||
setServerCapabilities(null);
|
||||
|
|
|
|||
Loading…
Reference in a new issue