Merge branch 'main' into main

This commit is contained in:
Cliff Hall 2025-05-21 16:27:13 -04:00 • committed by GitHub
commit efa4959ec4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 111 additions and 52 deletions

View file

@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/inspector-cli", "name": "@modelcontextprotocol/inspector-cli",
"version": "0.12.0", "version": "0.13.0",
"description": "CLI for the Model Context Protocol inspector", "description": "CLI for the Model Context Protocol inspector",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@ -21,7 +21,7 @@
}, },
"devDependencies": {}, "devDependencies": {},
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0", "@modelcontextprotocol/sdk": "^1.11.5",
"commander": "^13.1.0", "commander": "^13.1.0",
"spawn-rx": "^5.1.2" "spawn-rx": "^5.1.2"
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/inspector-client", "name": "@modelcontextprotocol/inspector-client",
"version": "0.12.0", "version": "0.13.0",
"description": "Client-side application for the Model Context Protocol inspector", "description": "Client-side application for the Model Context Protocol inspector",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@ -23,7 +23,7 @@
"test:watch": "jest --config jest.config.cjs --watch" "test:watch": "jest --config jest.config.cjs --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0", "@modelcontextprotocol/sdk": "^1.11.5",
"@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-checkbox": "^1.1.4",
"@radix-ui/react-dialog": "^1.1.3", "@radix-ui/react-dialog": "^1.1.3",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",

View file

@ -234,7 +234,6 @@ const App = () => {
const onOAuthConnect = useCallback( const onOAuthConnect = useCallback(
(serverUrl: string) => { (serverUrl: string) => {
setSseUrl(serverUrl); setSseUrl(serverUrl);
setTransportType("sse");
setIsAuthDebuggerVisible(false); setIsAuthDebuggerVisible(false);
void connectMcpServer(); void connectMcpServer();
}, },

View file

@ -127,14 +127,14 @@ const Sidebar = ({
return { return {
type: "sse", type: "sse",
url: sseUrl, url: sseUrl,
note: "For SSE connections, add this URL directly in Client", note: "For SSE connections, add this URL directly in your MCP Client",
}; };
} }
if (transportType === "streamable-http") { if (transportType === "streamable-http") {
return { return {
type: "streamable-http", type: "streamable-http",
url: sseUrl, url: sseUrl,
note: "For Streamable HTTP connections, add this URL directly in Client", note: "For Streamable HTTP connections, add this URL directly in your MCP Client",
}; };
} }
return {}; return {};
@ -172,7 +172,7 @@ const Sidebar = ({
description: description:
transportType === "stdio" transportType === "stdio"
? "Server configuration has been copied to clipboard. Add this to your mcp.json inside the 'mcpServers' object with your preferred server name." ? "Server configuration has been copied to clipboard. Add this to your mcp.json inside the 'mcpServers' object with your preferred server name."
: "SSE URL has been copied. Use this URL in Cursor directly.", : "SSE URL has been copied. Use this URL directly in your MCP Client.",
}); });
setTimeout(() => { setTimeout(() => {

View file

@ -755,7 +755,7 @@ describe("Sidebar Environment Variables", () => {
{ {
type: "sse", type: "sse",
url: sseUrl, url: sseUrl,
note: "For SSE connections, add this URL directly in Client", note: "For SSE connections, add this URL directly in your MCP Client",
}, },
null, null,
4, 4,
@ -780,7 +780,7 @@ describe("Sidebar Environment Variables", () => {
"default-server": { "default-server": {
type: "sse", type: "sse",
url: sseUrl, url: sseUrl,
note: "For SSE connections, add this URL directly in Client", note: "For SSE connections, add this URL directly in your MCP Client",
}, },
}, },
}, },
@ -805,7 +805,7 @@ describe("Sidebar Environment Variables", () => {
{ {
type: "streamable-http", type: "streamable-http",
url: sseUrl, url: sseUrl,
note: "For Streamable HTTP connections, add this URL directly in Client", note: "For Streamable HTTP connections, add this URL directly in your MCP Client",
}, },
null, null,
4, 4,
@ -830,7 +830,7 @@ describe("Sidebar Environment Variables", () => {
"default-server": { "default-server": {
type: "streamable-http", type: "streamable-http",
url: sseUrl, url: sseUrl,
note: "For Streamable HTTP connections, add this URL directly in Client", note: "For Streamable HTTP connections, add this URL directly in your MCP Client",
}, },
}, },
}, },

View file

@ -249,9 +249,16 @@ export function useConnection({
} }
}; };
const is401Error = (error: unknown): boolean => {
return (
(error instanceof SseError && error.code === 401) ||
(error instanceof Error && error.message.includes("401")) ||
(error instanceof Error && error.message.includes("Unauthorized"))
);
};
const handleAuthError = async (error: unknown) => { const handleAuthError = async (error: unknown) => {
if (error instanceof SseError && error.code === 401) { if (is401Error(error)) {
// Create a new auth provider with the current server URL
const serverAuthProvider = new InspectorOAuthClientProvider(sseUrl); const serverAuthProvider = new InspectorOAuthClientProvider(sseUrl);
const result = await auth(serverAuthProvider, { serverUrl: sseUrl }); const result = await auth(serverAuthProvider, { serverUrl: sseUrl });
@ -330,7 +337,6 @@ export function useConnection({
mcpProxyServerUrl = new URL(`${getMCPProxyAddress(config)}/sse`); mcpProxyServerUrl = new URL(`${getMCPProxyAddress(config)}/sse`);
mcpProxyServerUrl.searchParams.append("url", sseUrl); mcpProxyServerUrl.searchParams.append("url", sseUrl);
transportOptions = { transportOptions = {
authProvider: serverAuthProvider,
eventSourceInit: { eventSourceInit: {
fetch: ( fetch: (
url: string | URL | globalThis.Request, url: string | URL | globalThis.Request,
@ -347,7 +353,6 @@ export function useConnection({
mcpProxyServerUrl = new URL(`${getMCPProxyAddress(config)}/mcp`); mcpProxyServerUrl = new URL(`${getMCPProxyAddress(config)}/mcp`);
mcpProxyServerUrl.searchParams.append("url", sseUrl); mcpProxyServerUrl.searchParams.append("url", sseUrl);
transportOptions = { transportOptions = {
authProvider: serverAuthProvider,
eventSourceInit: { eventSourceInit: {
fetch: ( fetch: (
url: string | URL | globalThis.Request, url: string | URL | globalThis.Request,
@ -425,13 +430,14 @@ export function useConnection({
`Failed to connect to MCP Server via the MCP Inspector Proxy: ${mcpProxyServerUrl}:`, `Failed to connect to MCP Server via the MCP Inspector Proxy: ${mcpProxyServerUrl}:`,
error, error,
); );
const shouldRetry = await handleAuthError(error); const shouldRetry = await handleAuthError(error);
if (shouldRetry) { if (shouldRetry) {
return connect(undefined, retryCount + 1); return connect(undefined, retryCount + 1);
} }
if (is401Error(error)) {
if (error instanceof SseError && error.code === 401) {
// Don't set error state if we're about to redirect for auth // Don't set error state if we're about to redirect for auth
return; return;
} }
throw error; throw error;

91
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "@modelcontextprotocol/inspector", "name": "@modelcontextprotocol/inspector",
"version": "0.12.0", "version": "0.13.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@modelcontextprotocol/inspector", "name": "@modelcontextprotocol/inspector",
"version": "0.12.0", "version": "0.13.0",
"license": "MIT", "license": "MIT",
"workspaces": [ "workspaces": [
"client", "client",
@ -14,10 +14,10 @@
"cli" "cli"
], ],
"dependencies": { "dependencies": {
"@modelcontextprotocol/inspector-cli": "^0.12.0", "@modelcontextprotocol/inspector-cli": "^0.13.0",
"@modelcontextprotocol/inspector-client": "^0.12.0", "@modelcontextprotocol/inspector-client": "^0.13.0",
"@modelcontextprotocol/inspector-server": "^0.12.0", "@modelcontextprotocol/inspector-server": "^0.13.0",
"@modelcontextprotocol/sdk": "^1.11.2", "@modelcontextprotocol/sdk": "^1.11.5",
"concurrently": "^9.0.1", "concurrently": "^9.0.1",
"open": "^10.1.0", "open": "^10.1.0",
"shell-quote": "^1.8.2", "shell-quote": "^1.8.2",
@ -40,10 +40,10 @@
}, },
"cli": { "cli": {
"name": "@modelcontextprotocol/inspector-cli", "name": "@modelcontextprotocol/inspector-cli",
"version": "0.12.0", "version": "0.13.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0", "@modelcontextprotocol/sdk": "^1.11.5",
"commander": "^13.1.0", "commander": "^13.1.0",
"spawn-rx": "^5.1.2" "spawn-rx": "^5.1.2"
}, },
@ -63,10 +63,10 @@
}, },
"client": { "client": {
"name": "@modelcontextprotocol/inspector-client", "name": "@modelcontextprotocol/inspector-client",
"version": "0.12.0", "version": "0.13.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0", "@modelcontextprotocol/sdk": "^1.11.5",
"@radix-ui/react-checkbox": "^1.1.4", "@radix-ui/react-checkbox": "^1.1.4",
"@radix-ui/react-dialog": "^1.1.3", "@radix-ui/react-dialog": "^1.1.3",
"@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-icons": "^1.3.0",
@ -2004,13 +2004,15 @@
"link": true "link": true
}, },
"node_modules/@modelcontextprotocol/sdk": { "node_modules/@modelcontextprotocol/sdk": {
"version": "1.11.2", "version": "1.11.5",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.2.tgz", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.5.tgz",
"integrity": "sha512-H9vwztj5OAqHg9GockCQC06k1natgcxWQSRpQcPJf6i5+MWBzfKkRtxGbjQf0X2ihii0ffLZCRGbYV2f2bjNCQ==", "integrity": "sha512-gS7Q7IHpKxjVaNLMUZyTtatZ63ca3h418zPPntAhu/MvG5yfz/8HMcDAOpvpQfx3V3dsw9QQxk8RuFNrQhLlgA==",
"license": "MIT",
"dependencies": { "dependencies": {
"ajv": "^8.17.1",
"content-type": "^1.0.5", "content-type": "^1.0.5",
"cors": "^2.8.5", "cors": "^2.8.5",
"cross-spawn": "^7.0.3", "cross-spawn": "^7.0.5",
"eventsource": "^3.0.2", "eventsource": "^3.0.2",
"express": "^5.0.1", "express": "^5.0.1",
"express-rate-limit": "^7.5.0", "express-rate-limit": "^7.5.0",
@ -2023,6 +2025,28 @@
"node": ">=18" "node": ">=18"
} }
}, },
"node_modules/@modelcontextprotocol/sdk/node_modules/ajv": {
"version": "8.17.1",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/@modelcontextprotocol/sdk/node_modules/json-schema-traverse": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"license": "MIT"
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -5652,7 +5676,6 @@
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-glob": { "node_modules/fast-glob": {
@ -5697,6 +5720,22 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-uri": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz",
"integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "BSD-3-Clause"
},
"node_modules/fastq": { "node_modules/fastq": {
"version": "1.19.1", "version": "1.19.1",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
@ -8407,15 +8446,6 @@
"node": "20 || >=22" "node": "20 || >=22"
} }
}, },
"node_modules/path-to-regexp": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
"integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==",
"license": "MIT",
"engines": {
"node": ">=16"
}
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
@ -9037,6 +9067,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/requires-port": { "node_modules/requires-port": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@ -10933,10 +10972,10 @@
}, },
"server": { "server": {
"name": "@modelcontextprotocol/inspector-server", "name": "@modelcontextprotocol/inspector-server",
"version": "0.12.0", "version": "0.13.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0", "@modelcontextprotocol/sdk": "^1.11.5",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^5.1.0", "express": "^5.1.0",
"ws": "^8.18.0", "ws": "^8.18.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/inspector", "name": "@modelcontextprotocol/inspector",
"version": "0.12.0", "version": "0.13.0",
"description": "Model Context Protocol inspector", "description": "Model Context Protocol inspector",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@ -40,10 +40,10 @@
"publish-all": "npm publish --workspaces --access public && npm publish --access public" "publish-all": "npm publish --workspaces --access public && npm publish --access public"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/inspector-cli": "^0.12.0", "@modelcontextprotocol/inspector-cli": "^0.13.0",
"@modelcontextprotocol/inspector-client": "^0.12.0", "@modelcontextprotocol/inspector-client": "^0.13.0",
"@modelcontextprotocol/inspector-server": "^0.12.0", "@modelcontextprotocol/inspector-server": "^0.13.0",
"@modelcontextprotocol/sdk": "^1.11.2", "@modelcontextprotocol/sdk": "^1.11.5",
"concurrently": "^9.0.1", "concurrently": "^9.0.1",
"open": "^10.1.0", "open": "^10.1.0",
"shell-quote": "^1.8.2", "shell-quote": "^1.8.2",

View file

@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/inspector-server", "name": "@modelcontextprotocol/inspector-server",
"version": "0.12.0", "version": "0.13.0",
"description": "Server-side application for the Model Context Protocol inspector", "description": "Server-side application for the Model Context Protocol inspector",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@ -27,7 +27,7 @@
"typescript": "^5.6.2" "typescript": "^5.6.2"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0", "@modelcontextprotocol/sdk": "^1.11.5",
"cors": "^2.8.5", "cors": "^2.8.5",
"express": "^5.1.0", "express": "^5.1.0",
"ws": "^8.18.0", "ws": "^8.18.0",

View file

@ -1,4 +1,5 @@
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js"; import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
import { isJSONRPCRequest } from "@modelcontextprotocol/sdk/types.js";
function onClientError(error: Error) { function onClientError(error: Error) {
console.error("Error from inspector client:", error); console.error("Error from inspector client:", error);
@ -19,7 +20,21 @@ export default function mcpProxy({
let transportToServerClosed = false; let transportToServerClosed = false;
transportToClient.onmessage = (message) => { transportToClient.onmessage = (message) => {
transportToServer.send(message).catch(onServerError); transportToServer.send(message).catch((error) => {
// Send error response back to client if it was a request (has id) and connection is still open
if (isJSONRPCRequest(message) && !transportToClientClosed) {
const errorResponse = {
jsonrpc: "2.0" as const,
id: message.id,
error: {
code: -32001,
message: error.message,
data: error,
},
};
transportToClient.send(errorResponse).catch(onClientError);
}
});
}; };
transportToServer.onmessage = (message) => { transportToServer.onmessage = (message) => {