@atom8n/inspector
Advanced tools
Sorry, the diff of this file is too big to display
| import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-V4XBVTpj.js"; | ||
| const OAuthCallback = ({ onConnect }) => { | ||
| const { toast } = useToast(); | ||
| const hasProcessedRef = reactExports.useRef(false); | ||
| reactExports.useEffect(() => { | ||
| const handleCallback = async () => { | ||
| if (hasProcessedRef.current) { | ||
| return; | ||
| } | ||
| hasProcessedRef.current = true; | ||
| const notifyError = (description) => void toast({ | ||
| title: "OAuth Authorization Error", | ||
| description, | ||
| variant: "destructive" | ||
| }); | ||
| const params = parseOAuthCallbackParams(window.location.search); | ||
| if (!params.successful) { | ||
| return notifyError(generateOAuthErrorDescription(params)); | ||
| } | ||
| const serverUrl = sessionStorage.getItem(SESSION_KEYS.SERVER_URL); | ||
| if (!serverUrl) { | ||
| return notifyError("Missing Server URL"); | ||
| } | ||
| let result; | ||
| try { | ||
| const serverAuthProvider = new InspectorOAuthClientProvider(serverUrl); | ||
| result = await auth(serverAuthProvider, { | ||
| serverUrl, | ||
| authorizationCode: params.code | ||
| }); | ||
| } catch (error) { | ||
| console.error("OAuth callback error:", error); | ||
| return notifyError(`Unexpected error occurred: ${error}`); | ||
| } | ||
| if (result !== "AUTHORIZED") { | ||
| return notifyError( | ||
| `Expected to be authorized after providing auth code, got: ${result}` | ||
| ); | ||
| } | ||
| toast({ | ||
| title: "Success", | ||
| description: "Successfully authenticated with OAuth", | ||
| variant: "default" | ||
| }); | ||
| onConnect(serverUrl); | ||
| }; | ||
| handleCallback().finally(() => { | ||
| window.history.replaceState({}, document.title, "/"); | ||
| }); | ||
| }, [toast, onConnect]); | ||
| return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg text-gray-500", children: "Processing OAuth callback..." }) }); | ||
| }; | ||
| export { | ||
| OAuthCallback as default | ||
| }; |
| import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-V4XBVTpj.js"; | ||
| const OAuthDebugCallback = ({ onConnect }) => { | ||
| reactExports.useEffect(() => { | ||
| let isProcessed = false; | ||
| const handleCallback = async () => { | ||
| if (isProcessed) { | ||
| return; | ||
| } | ||
| isProcessed = true; | ||
| const params = parseOAuthCallbackParams(window.location.search); | ||
| if (!params.successful) { | ||
| const errorMsg = generateOAuthErrorDescription(params); | ||
| onConnect({ errorMsg }); | ||
| return; | ||
| } | ||
| const serverUrl = sessionStorage.getItem(SESSION_KEYS.SERVER_URL); | ||
| const storedState = sessionStorage.getItem( | ||
| SESSION_KEYS.AUTH_DEBUGGER_STATE | ||
| ); | ||
| let restoredState = null; | ||
| if (storedState) { | ||
| try { | ||
| restoredState = JSON.parse(storedState); | ||
| if (restoredState && typeof restoredState.resource === "string") { | ||
| restoredState.resource = new URL(restoredState.resource); | ||
| } | ||
| if (restoredState && typeof restoredState.authorizationUrl === "string") { | ||
| restoredState.authorizationUrl = new URL( | ||
| restoredState.authorizationUrl | ||
| ); | ||
| } | ||
| sessionStorage.removeItem(SESSION_KEYS.AUTH_DEBUGGER_STATE); | ||
| } catch (e) { | ||
| console.error("Failed to parse stored auth state:", e); | ||
| } | ||
| } | ||
| if (!serverUrl) { | ||
| return; | ||
| } | ||
| if (!params.code) { | ||
| onConnect({ errorMsg: "Missing authorization code" }); | ||
| return; | ||
| } | ||
| onConnect({ authorizationCode: params.code, restoredState }); | ||
| }; | ||
| handleCallback().finally(() => { | ||
| if (sessionStorage.getItem(SESSION_KEYS.SERVER_URL)) { | ||
| window.history.replaceState({}, document.title, "/"); | ||
| } | ||
| }); | ||
| return () => { | ||
| isProcessed = true; | ||
| }; | ||
| }, [onConnect]); | ||
| const callbackParams = parseOAuthCallbackParams(window.location.search); | ||
| return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-4 p-4 bg-secondary rounded-md max-w-md", children: [ | ||
| /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mb-2 text-sm", children: "Please copy this authorization code and return to the Auth Debugger:" }), | ||
| /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "block p-2 bg-muted rounded-sm overflow-x-auto text-xs", children: callbackParams.successful && "code" in callbackParams ? callbackParams.code : `No code found: ${callbackParams.error}, ${callbackParams.error_description}` }), | ||
| /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-4 text-xs text-muted-foreground", children: "Close this tab and paste the code in the OAuth flow to complete authentication." }) | ||
| ] }) }); | ||
| }; | ||
| export { | ||
| OAuthDebugCallback as default | ||
| }; |
+12
-2
@@ -26,2 +26,8 @@ #!/usr/bin/env node | ||
| } | ||
| function getServerConfigUrl(config) { | ||
| if ("command" in config) { | ||
| return ""; | ||
| } | ||
| return config.url || config.serverUrl || config.sseUrl || ""; | ||
| } | ||
| async function runWebClient(args) { | ||
@@ -221,4 +227,8 @@ // Path to the client entry point | ||
| else if (config.type === "sse" || config.type === "streamable-http") { | ||
| const serverUrl = getServerConfigUrl(config); | ||
| if (!serverUrl) { | ||
| throw new Error(`Server '${options.server}' is type '${config.type}' but is missing a URL. Expected one of: url, serverUrl, sseUrl.`); | ||
| } | ||
| return { | ||
| command: config.url, | ||
| command: serverUrl, | ||
| args: finalArgs, | ||
@@ -228,3 +238,3 @@ envArgs: options.e || {}, | ||
| transport: config.type, | ||
| serverUrl: config.url, | ||
| serverUrl, | ||
| headers: options.header, | ||
@@ -231,0 +241,0 @@ }; |
@@ -8,3 +8,3 @@ <!doctype html> | ||
| <title>MCP Inspector</title> | ||
| <script type="module" crossorigin src="/assets/index-d8E8lyY7.js"></script> | ||
| <script type="module" crossorigin src="/assets/index-V4XBVTpj.js"></script> | ||
| <link rel="stylesheet" crossorigin href="/assets/index-BFYf86Uc.css"> | ||
@@ -11,0 +11,0 @@ </head> |
+1
-1
@@ -6,3 +6,3 @@ { | ||
| }, | ||
| "version": "0.17.20", | ||
| "version": "0.17.21", | ||
| "description": "Model Context Protocol inspector", | ||
@@ -9,0 +9,0 @@ "license": "MIT", |
@@ -28,2 +28,5 @@ import { isJSONRPCRequest, } from "@modelcontextprotocol/sdk/types.js"; | ||
| } | ||
| function getErrorMessage(error) { | ||
| return error instanceof Error ? error.message : String(error); | ||
| } | ||
| /** | ||
@@ -85,3 +88,3 @@ * Filter a tools/list response to only include allowed tools. | ||
| } | ||
| export default function mcpProxy({ transportToClient, transportToServer, allowedTools, }) { | ||
| export default function mcpProxy({ transportToClient, transportToServer, allowedTools, onServerSendAuthError, }) { | ||
| let transportToClientClosed = false; | ||
@@ -99,3 +102,3 @@ let transportToServerClosed = false; | ||
| } | ||
| transportToClient.onmessage = (message) => { | ||
| const forwardToServer = async (message) => { | ||
| console.log(`[mcpProxy] Client → Server: ${summarizeMessage(message)}`); | ||
@@ -115,4 +118,21 @@ // If filtering is active, check tools/call requests | ||
| } | ||
| transportToServer.send(message).catch((error) => { | ||
| console.error(`[mcpProxy] Failed to send to server: ${error.message}`); | ||
| try { | ||
| await transportToServer.send(message); | ||
| } | ||
| catch (error) { | ||
| console.error(`[mcpProxy] Failed to send to server: ${getErrorMessage(error)}`); | ||
| if (onServerSendAuthError) { | ||
| try { | ||
| const shouldRetry = await onServerSendAuthError(error); | ||
| if (shouldRetry && !transportToServerClosed) { | ||
| console.log("[mcpProxy] Retrying client message after credential refresh"); | ||
| await transportToServer.send(message); | ||
| return; | ||
| } | ||
| } | ||
| catch (retryError) { | ||
| console.error("[mcpProxy] Credential refresh retry failed:", retryError); | ||
| error = retryError; | ||
| } | ||
| } | ||
| // Send error response back to client if it was a request (has id) and connection is still open | ||
@@ -125,3 +145,3 @@ if (isJSONRPCRequest(message) && !transportToClientClosed) { | ||
| code: -32001, | ||
| message: error.message, | ||
| message: getErrorMessage(error), | ||
| data: error, | ||
@@ -132,4 +152,7 @@ }, | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| transportToClient.onmessage = (message) => { | ||
| void forwardToServer(message); | ||
| }; | ||
| transportToServer.onmessage = (message) => { | ||
@@ -136,0 +159,0 @@ if (!reportedServerSession) { |
Sorry, the diff of this file is too big to display
| import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-d8E8lyY7.js"; | ||
| const OAuthCallback = ({ onConnect }) => { | ||
| const { toast } = useToast(); | ||
| const hasProcessedRef = reactExports.useRef(false); | ||
| reactExports.useEffect(() => { | ||
| const handleCallback = async () => { | ||
| if (hasProcessedRef.current) { | ||
| return; | ||
| } | ||
| hasProcessedRef.current = true; | ||
| const notifyError = (description) => void toast({ | ||
| title: "OAuth Authorization Error", | ||
| description, | ||
| variant: "destructive" | ||
| }); | ||
| const params = parseOAuthCallbackParams(window.location.search); | ||
| if (!params.successful) { | ||
| return notifyError(generateOAuthErrorDescription(params)); | ||
| } | ||
| const serverUrl = sessionStorage.getItem(SESSION_KEYS.SERVER_URL); | ||
| if (!serverUrl) { | ||
| return notifyError("Missing Server URL"); | ||
| } | ||
| let result; | ||
| try { | ||
| const serverAuthProvider = new InspectorOAuthClientProvider(serverUrl); | ||
| result = await auth(serverAuthProvider, { | ||
| serverUrl, | ||
| authorizationCode: params.code | ||
| }); | ||
| } catch (error) { | ||
| console.error("OAuth callback error:", error); | ||
| return notifyError(`Unexpected error occurred: ${error}`); | ||
| } | ||
| if (result !== "AUTHORIZED") { | ||
| return notifyError( | ||
| `Expected to be authorized after providing auth code, got: ${result}` | ||
| ); | ||
| } | ||
| toast({ | ||
| title: "Success", | ||
| description: "Successfully authenticated with OAuth", | ||
| variant: "default" | ||
| }); | ||
| onConnect(serverUrl); | ||
| }; | ||
| handleCallback().finally(() => { | ||
| window.history.replaceState({}, document.title, "/"); | ||
| }); | ||
| }, [toast, onConnect]); | ||
| return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg text-gray-500", children: "Processing OAuth callback..." }) }); | ||
| }; | ||
| export { | ||
| OAuthCallback as default | ||
| }; |
| import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-d8E8lyY7.js"; | ||
| const OAuthDebugCallback = ({ onConnect }) => { | ||
| reactExports.useEffect(() => { | ||
| let isProcessed = false; | ||
| const handleCallback = async () => { | ||
| if (isProcessed) { | ||
| return; | ||
| } | ||
| isProcessed = true; | ||
| const params = parseOAuthCallbackParams(window.location.search); | ||
| if (!params.successful) { | ||
| const errorMsg = generateOAuthErrorDescription(params); | ||
| onConnect({ errorMsg }); | ||
| return; | ||
| } | ||
| const serverUrl = sessionStorage.getItem(SESSION_KEYS.SERVER_URL); | ||
| const storedState = sessionStorage.getItem( | ||
| SESSION_KEYS.AUTH_DEBUGGER_STATE | ||
| ); | ||
| let restoredState = null; | ||
| if (storedState) { | ||
| try { | ||
| restoredState = JSON.parse(storedState); | ||
| if (restoredState && typeof restoredState.resource === "string") { | ||
| restoredState.resource = new URL(restoredState.resource); | ||
| } | ||
| if (restoredState && typeof restoredState.authorizationUrl === "string") { | ||
| restoredState.authorizationUrl = new URL( | ||
| restoredState.authorizationUrl | ||
| ); | ||
| } | ||
| sessionStorage.removeItem(SESSION_KEYS.AUTH_DEBUGGER_STATE); | ||
| } catch (e) { | ||
| console.error("Failed to parse stored auth state:", e); | ||
| } | ||
| } | ||
| if (!serverUrl) { | ||
| return; | ||
| } | ||
| if (!params.code) { | ||
| onConnect({ errorMsg: "Missing authorization code" }); | ||
| return; | ||
| } | ||
| onConnect({ authorizationCode: params.code, restoredState }); | ||
| }; | ||
| handleCallback().finally(() => { | ||
| if (sessionStorage.getItem(SESSION_KEYS.SERVER_URL)) { | ||
| window.history.replaceState({}, document.title, "/"); | ||
| } | ||
| }); | ||
| return () => { | ||
| isProcessed = true; | ||
| }; | ||
| }, [onConnect]); | ||
| const callbackParams = parseOAuthCallbackParams(window.location.search); | ||
| return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-screen", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-4 p-4 bg-secondary rounded-md max-w-md", children: [ | ||
| /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mb-2 text-sm", children: "Please copy this authorization code and return to the Auth Debugger:" }), | ||
| /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "block p-2 bg-muted rounded-sm overflow-x-auto text-xs", children: callbackParams.successful && "code" in callbackParams ? callbackParams.code : `No code found: ${callbackParams.error}, ${callbackParams.error_description}` }), | ||
| /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-4 text-xs text-muted-foreground", children: "Close this tab and paste the code in the OAuth flow to complete authentication." }) | ||
| ] }) }); | ||
| }; | ||
| export { | ||
| OAuthDebugCallback as default | ||
| }; |
Sorry, the diff of this file is too big to display
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
2287959
0.81%58084
0.83%