Merge branch 'main' into inspector/error-popup
This commit is contained in:
commit
8cb845798e
1 changed files with 7119 additions and 2488 deletions
|
|
@ -7,6 +7,7 @@ import {
|
|||
import {
|
||||
StreamableHTTPClientTransport,
|
||||
StreamableHTTPClientTransportOptions,
|
||||
StreamableHTTPError,
|
||||
} from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
||||
import {
|
||||
ClientNotification,
|
||||
|
|
@ -30,11 +31,15 @@ import {
|
|||
Progress,
|
||||
LoggingLevel,
|
||||
ElicitRequestSchema,
|
||||
Implementation,
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
import type {
|
||||
AnySchema,
|
||||
SchemaOutput,
|
||||
} from "@modelcontextprotocol/sdk/server/zod-compat.js";
|
||||
import { RequestOptions } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useToast } from "@/lib/hooks/useToast";
|
||||
import { z } from "zod";
|
||||
import { ConnectionStatus, CLIENT_IDENTITY } from "../constants";
|
||||
import { Notification } from "../notificationTypes";
|
||||
import {
|
||||
|
|
@ -45,6 +50,8 @@ import {
|
|||
clearClientInformationFromSessionStorage,
|
||||
InspectorOAuthClientProvider,
|
||||
saveClientInformationToSessionStorage,
|
||||
saveScopeToSessionStorage,
|
||||
clearScopeFromSessionStorage,
|
||||
discoverScopes,
|
||||
} from "../auth";
|
||||
import {
|
||||
|
|
@ -57,6 +64,7 @@ import { getMCPServerRequestTimeout } from "@/utils/configUtils";
|
|||
import { InspectorConfig } from "../configurationTypes";
|
||||
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
||||
import { CustomHeaders } from "../types/customHeaders";
|
||||
import { resolveRefsInMessage } from "@/utils/schemaUtils";
|
||||
|
||||
interface UseConnectionOptions {
|
||||
transportType: "stdio" | "sse" | "streamable-http";
|
||||
|
|
@ -80,6 +88,8 @@ interface UseConnectionOptions {
|
|||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
getRoots?: () => any[];
|
||||
defaultLoggingLevel?: LoggingLevel;
|
||||
serverImplementation?: Implementation;
|
||||
metadata?: Record<string, string>;
|
||||
}
|
||||
|
||||
export function useConnection({
|
||||
|
|
@ -99,6 +109,7 @@ export function useConnection({
|
|||
onElicitationRequest,
|
||||
getRoots,
|
||||
defaultLoggingLevel,
|
||||
metadata = {},
|
||||
}: UseConnectionOptions) {
|
||||
const [connectionStatus, setConnectionStatus] =
|
||||
useState<ConnectionStatus>("disconnected");
|
||||
|
|
@ -117,6 +128,8 @@ export function useConnection({
|
|||
const [mcpProtocolVersion, setMcpProtocolVersion] = useState<string | null>(
|
||||
null,
|
||||
);
|
||||
const [serverImplementation, setServerImplementation] =
|
||||
useState<Implementation | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!oauthClientId) {
|
||||
|
|
@ -142,6 +155,15 @@ export function useConnection({
|
|||
});
|
||||
}, [oauthClientId, oauthClientSecret, sseUrl]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!oauthScope) {
|
||||
clearScopeFromSessionStorage(sseUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
saveScopeToSessionStorage(sseUrl, oauthScope);
|
||||
}, [oauthScope, sseUrl]);
|
||||
|
||||
const pushHistory = (request: object, response?: object) => {
|
||||
setRequestHistory((prev) => [
|
||||
...prev,
|
||||
|
|
@ -152,17 +174,31 @@ export function useConnection({
|
|||
]);
|
||||
};
|
||||
|
||||
const makeRequest = async <T extends z.ZodType>(
|
||||
const makeRequest = async <T extends AnySchema>(
|
||||
request: ClientRequest,
|
||||
schema: T,
|
||||
options?: RequestOptions & { suppressToast?: boolean },
|
||||
): Promise<z.output<T>> => {
|
||||
): Promise<SchemaOutput<T>> => {
|
||||
if (!mcpClient) {
|
||||
throw new Error("MCP client not connected");
|
||||
}
|
||||
try {
|
||||
const abortController = new AbortController();
|
||||
|
||||
// Add metadata to the request if available, but skip for tool calls
|
||||
// as they handle metadata merging separately
|
||||
const shouldAddGeneralMetadata =
|
||||
request.method !== "tools/call" && Object.keys(metadata).length > 0;
|
||||
const requestWithMetadata = shouldAddGeneralMetadata
|
||||
? {
|
||||
...request,
|
||||
params: {
|
||||
...request.params,
|
||||
_meta: metadata,
|
||||
},
|
||||
}
|
||||
: request;
|
||||
|
||||
// prepare MCP Client request options
|
||||
const mcpRequestOptions: RequestOptions = {
|
||||
signal: options?.signal ?? abortController.signal,
|
||||
|
|
@ -191,13 +227,17 @@ export function useConnection({
|
|||
|
||||
let response;
|
||||
try {
|
||||
response = await mcpClient.request(request, schema, mcpRequestOptions);
|
||||
response = await mcpClient.request(
|
||||
requestWithMetadata,
|
||||
schema,
|
||||
mcpRequestOptions,
|
||||
);
|
||||
|
||||
pushHistory(request, response);
|
||||
pushHistory(requestWithMetadata, response);
|
||||
} catch (error) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : String(error);
|
||||
pushHistory(request, { error: errorMessage });
|
||||
pushHistory(requestWithMetadata, { error: errorMessage });
|
||||
throw error;
|
||||
}
|
||||
|
||||
|
|
@ -319,8 +359,11 @@ export function useConnection({
|
|||
const is401Error = (error: unknown): boolean => {
|
||||
return (
|
||||
(error instanceof SseError && error.code === 401) ||
|
||||
(error instanceof StreamableHTTPError && error.code === 401) ||
|
||||
(error instanceof Error && error.message.includes("401")) ||
|
||||
(error instanceof Error && error.message.includes("Unauthorized"))
|
||||
(error instanceof Error && error.message.includes("Unauthorized")) ||
|
||||
(error instanceof Error &&
|
||||
error.message.includes("Missing Authorization header"))
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -346,10 +389,9 @@ export function useConnection({
|
|||
}
|
||||
scope = await discoverScopes(sseUrl, resourceMetadata);
|
||||
}
|
||||
const serverAuthProvider = new InspectorOAuthClientProvider(
|
||||
sseUrl,
|
||||
scope,
|
||||
);
|
||||
|
||||
saveScopeToSessionStorage(sseUrl, scope);
|
||||
const serverAuthProvider = new InspectorOAuthClientProvider(sseUrl);
|
||||
|
||||
const result = await auth(serverAuthProvider, {
|
||||
serverUrl: sseUrl,
|
||||
|
|
@ -681,9 +723,19 @@ export function useConnection({
|
|||
|
||||
await client.connect(transport as Transport);
|
||||
|
||||
const protocolOnMessage = transport.onmessage;
|
||||
if (protocolOnMessage) {
|
||||
transport.onmessage = (message) => {
|
||||
const resolvedMessage = resolveRefsInMessage(message);
|
||||
protocolOnMessage(resolvedMessage);
|
||||
};
|
||||
}
|
||||
|
||||
setClientTransport(transport);
|
||||
|
||||
capabilities = client.getServerCapabilities();
|
||||
const serverInfo = client.getServerVersion();
|
||||
setServerImplementation(serverInfo || null);
|
||||
const initializeRequest = {
|
||||
method: "initialize",
|
||||
};
|
||||
|
|
@ -807,11 +859,13 @@ export function useConnection({
|
|||
|
||||
const clearRequestHistory = () => {
|
||||
setRequestHistory([]);
|
||||
setServerImplementation(null);
|
||||
};
|
||||
|
||||
return {
|
||||
connectionStatus,
|
||||
serverCapabilities,
|
||||
serverImplementation,
|
||||
mcpClient,
|
||||
requestHistory,
|
||||
clearRequestHistory,
|
||||
|
|
|
|||
Loading…
Reference in a new issue