@mcp-use/inspector 20.0.0-beta.15 → 20.0.0-beta.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -58
- package/dist/app/inspector.css +2 -0
- package/dist/{cdn → app}/inspector.js +8249 -7972
- package/dist/cli.js +292 -286
- package/dist/client/auth/manufact-auth.d.ts +1 -1
- package/dist/client/auth/manufact-auth.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/server/{chunk-XCNS5CIW.js → chunk-2K7OKCVV.js} +67 -67
- package/dist/server/{chunk-UJLXHNQP.js → chunk-EKD2XITW.js} +3 -2
- package/dist/server/{chunk-WNQGHIZ3.js → chunk-EPPZCSJQ.js} +23 -77
- package/dist/server/chunk-JWDVSQED.js +156 -0
- package/dist/server/{chunk-M5TZA42I.js → chunk-PZF2PUDE.js} +15 -11
- package/dist/server/{chunk-XKCUJ6ZJ.js → chunk-RFJAZOK7.js} +27 -8
- package/dist/server/{chunk-OWR2BIBW.js → chunk-RKFQG67Z.js} +1 -3
- package/dist/server/{chunk-K2F2AJOI.js → chunk-V5A5XLFJ.js} +148 -5
- package/dist/server/cli.js +11 -16
- package/dist/server/create-dev-api-app.d.ts.map +1 -1
- package/dist/server/create-dev-api-app.js +4 -4
- package/dist/server/favicon-links.d.ts +2 -2
- package/dist/server/favicon-links.d.ts.map +1 -1
- package/dist/server/index.d.ts +2 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +8 -13
- package/dist/server/{cdn-shell.d.ts → inspector-shell.d.ts} +7 -5
- package/dist/server/inspector-shell.d.ts.map +1 -0
- package/dist/server/inspector-shell.js +10 -0
- package/dist/server/middleware.d.ts +52 -27
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +8 -10
- package/dist/server/proxy/index.js +2 -2
- package/dist/server/proxy/mcp-proxy.d.ts.map +1 -1
- package/dist/server/proxy/mcp-proxy.js +2 -2
- package/dist/server/proxy/oauth-proxy.d.ts +2 -0
- package/dist/server/proxy/oauth-proxy.d.ts.map +1 -1
- package/dist/server/proxy/oauth-proxy.js +1 -1
- package/dist/server/proxy-routes.d.ts.map +1 -1
- package/dist/server/proxy-routes.js +3 -3
- package/dist/server/server.js +4 -4
- package/dist/server/static-assets.d.ts +3 -3
- package/dist/server/static-assets.d.ts.map +1 -1
- package/dist/server/static-assets.js +3 -3
- package/dist/server/version.js +1 -1
- package/dist/server/vite-dev-api-plugin.js +4 -4
- package/dist/web/assets/index-Dj_E94k4.css +1 -0
- package/dist/web/assets/{index-Bqfsh_Rp.js → index-O3gsi3le.js} +91 -91
- package/dist/web/index.html +3 -3
- package/package.json +30 -11
- package/dist/cdn/inspector.css +0 -2
- package/dist/server/asset-urls.d.ts +0 -15
- package/dist/server/asset-urls.d.ts.map +0 -1
- package/dist/server/asset-urls.js +0 -13
- package/dist/server/cdn-shell.d.ts.map +0 -1
- package/dist/server/cdn-shell.js +0 -12
- package/dist/server/chunk-J4FNYLBF.js +0 -54
- package/dist/server/chunk-JZT7N2BJ.js +0 -58
- package/dist/server/chunk-ZPGABKXL.js +0 -72
- package/dist/server/favicon-static.d.ts +0 -4
- package/dist/server/favicon-static.d.ts.map +0 -1
- package/dist/server/favicon-static.js +0 -8
- package/dist/web/assets/index-bCIH1Sdx.css +0 -1
- /package/dist/{cdn → app}/apple-touch-icon.png +0 -0
- /package/dist/{cdn → app}/favicon-96x96.png +0 -0
- /package/dist/{cdn → app}/favicon-black.svg +0 -0
- /package/dist/{cdn → app}/favicon-white.svg +0 -0
- /package/dist/{cdn → app}/favicon.ico +0 -0
- /package/dist/{cdn → app}/favicon.svg +0 -0
- /package/dist/{cdn → app}/providers/anthropic.png +0 -0
- /package/dist/{cdn → app}/providers/google.png +0 -0
- /package/dist/{cdn → app}/providers/openai.png +0 -0
- /package/dist/{cdn → app}/site.webmanifest +0 -0
- /package/dist/{cdn → app}/web-app-manifest-192x192.png +0 -0
- /package/dist/{cdn → app}/web-app-manifest-512x512.png +0 -0
|
@@ -13,7 +13,7 @@ interface ManufactAuthSnapshot {
|
|
|
13
13
|
}
|
|
14
14
|
export declare function canShareManufactSession(inspectorUrl: string, cloudOrigin: string): boolean;
|
|
15
15
|
export declare function getSharedManufactSession(chatApiUrl: string): Promise<ManufactUser | null>;
|
|
16
|
-
export declare function authorizeManufact(chatApiUrl: string,
|
|
16
|
+
export declare function authorizeManufact(chatApiUrl: string, _options?: {
|
|
17
17
|
isRetry?: boolean;
|
|
18
18
|
}): Promise<void>;
|
|
19
19
|
export declare function completeManufactAuthorization(url?: URL): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manufact-auth.d.ts","sourceRoot":"","sources":["../../../src/client/auth/manufact-auth.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AA6BD,UAAU,oBAAoB;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,IAAI,CAAC;CAClC;AAgDD,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,OAAO,CAeT;AAiUD,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAE9B;AAgED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,
|
|
1
|
+
{"version":3,"file":"manufact-auth.d.ts","sourceRoot":"","sources":["../../../src/client/auth/manufact-auth.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AA6BD,UAAU,oBAAoB;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,IAAI,CAAC;CAClC;AAgDD,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,OAAO,CAeT;AAiUD,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAE9B;AAgED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC/B,OAAO,CAAC,IAAI,CAAC,CAsEf;AAED,wBAAsB,6BAA6B,CACjD,GAAG,MAAgC,GAClC,OAAO,CAAC,IAAI,CAAC,CAmCf;AA0FD,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,GACjC,OAAO,CAAC,IAAI,CAAC,CAYf;AAED,wBAAsB,sBAAsB,CAC1C,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG;IACtE,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,IAAI,CAAC;IACjC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7B,CAiDA"}
|
package/dist/client/index.js
CHANGED
|
@@ -15774,7 +15774,7 @@ async function load(origin) {
|
|
|
15774
15774
|
loading.set(origin, promise);
|
|
15775
15775
|
return promise;
|
|
15776
15776
|
}
|
|
15777
|
-
async function authorizeManufact(chatApiUrl,
|
|
15777
|
+
async function authorizeManufact(chatApiUrl, _options) {
|
|
15778
15778
|
const origin = authOrigin(chatApiUrl);
|
|
15779
15779
|
pendingAuthorizeChatApiUrl = chatApiUrl;
|
|
15780
15780
|
setSkipSharedSession(origin, false);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isSafeProxyTarget
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-V5A5XLFJ.js";
|
|
4
4
|
|
|
5
5
|
// src/server/proxy/mcp-proxy.ts
|
|
6
6
|
import { cors } from "hono/cors";
|
|
7
7
|
import { logger } from "hono/logger";
|
|
8
|
+
var MAX_REDIRECTS = 3;
|
|
8
9
|
function isOpenEndedSseResponse(contentType, contentLength) {
|
|
9
10
|
return contentType.includes("text/event-stream") && !contentLength;
|
|
10
11
|
}
|
|
@@ -88,81 +89,48 @@ function mountMcpProxy(app, options = {}) {
|
|
|
88
89
|
const requestHeaders = c.req.header();
|
|
89
90
|
for (const [key, value] of Object.entries(requestHeaders)) {
|
|
90
91
|
const lowerKey = key.toLowerCase();
|
|
91
|
-
if (!lowerKey.startsWith("x-proxy-") && !lowerKey.startsWith("x-target-") && !lowerKey.startsWith("x-mcp-") && !lowerKey.startsWith("x-forwarded-") && !lowerKey.startsWith("cf-") && lowerKey !== "x-original-host" && lowerKey !== "host" && lowerKey !== "accept-encoding" && lowerKey !== "cdn-loop") {
|
|
92
|
+
if (!lowerKey.startsWith("x-proxy-") && !lowerKey.startsWith("x-target-") && !lowerKey.startsWith("x-mcp-") && !lowerKey.startsWith("x-forwarded-") && !lowerKey.startsWith("cf-") && lowerKey !== "x-original-host" && lowerKey !== "host" && lowerKey !== "origin" && lowerKey !== "referer" && lowerKey !== "cookie" && lowerKey !== "proxy-authorization" && lowerKey !== "accept-encoding" && lowerKey !== "cdn-loop" && !lowerKey.startsWith("sec-fetch-")) {
|
|
92
93
|
headers[key] = value;
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
96
|
headers["Accept-Encoding"] = "identity";
|
|
96
|
-
try {
|
|
97
|
-
const targetUrlObj = new URL(targetUrl);
|
|
98
|
-
headers.Host = targetUrlObj.host;
|
|
99
|
-
} catch {
|
|
100
|
-
return c.json({ error: "Invalid target URL" }, 400);
|
|
101
|
-
}
|
|
102
97
|
const body = method !== "GET" && method !== "HEAD" ? new Uint8Array(await c.req.arrayBuffer()).slice() : void 0;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
98
|
+
let currentUrl = targetUrl;
|
|
99
|
+
let currentMethod = method;
|
|
100
|
+
let currentBody = body;
|
|
101
|
+
for (let redirectCount = 0; ; redirectCount += 1) {
|
|
102
|
+
const response = await fetch(currentUrl, {
|
|
103
|
+
method: currentMethod,
|
|
104
|
+
headers,
|
|
105
|
+
body: currentBody,
|
|
106
|
+
redirect: "manual"
|
|
107
|
+
});
|
|
110
108
|
const location = response.headers.get("location");
|
|
111
|
-
if (location) {
|
|
112
|
-
|
|
113
|
-
if (!await isSafeProxyTarget(
|
|
114
|
-
redirectUrl,
|
|
115
|
-
options.allowLoopback ?? false
|
|
116
|
-
) || options.validateRequest && !await options.validateRequest(redirectUrl, c)) {
|
|
117
|
-
return c.json({ error: "Redirect target is not allowed" }, 403);
|
|
118
|
-
}
|
|
119
|
-
const redirectResponse = await fetch(redirectUrl, {
|
|
120
|
-
method,
|
|
121
|
-
headers,
|
|
122
|
-
body,
|
|
123
|
-
redirect: "manual"
|
|
124
|
-
});
|
|
125
|
-
const redirectHeaders = {};
|
|
126
|
-
redirectResponse.headers.forEach((value, key) => {
|
|
127
|
-
const lowerKey = key.toLowerCase();
|
|
128
|
-
if (lowerKey !== "content-encoding" && lowerKey !== "transfer-encoding" && lowerKey !== "content-length") {
|
|
129
|
-
redirectHeaders[key] = value;
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
return new Response(redirectResponse.body, {
|
|
133
|
-
status: redirectResponse.status,
|
|
134
|
-
statusText: redirectResponse.statusText,
|
|
135
|
-
headers: redirectHeaders
|
|
136
|
-
});
|
|
109
|
+
if (!(response.status >= 300 && response.status < 400 && location)) {
|
|
110
|
+
return proxyResponse(response);
|
|
137
111
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
response.headers.forEach((value, key) => {
|
|
141
|
-
const lowerKey = key.toLowerCase();
|
|
142
|
-
if (lowerKey !== "content-encoding" && lowerKey !== "transfer-encoding" && lowerKey !== "content-length") {
|
|
143
|
-
responseHeaders[key] = value;
|
|
112
|
+
if (redirectCount >= MAX_REDIRECTS) {
|
|
113
|
+
return c.json({ error: "Too many upstream redirects" }, 502);
|
|
144
114
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
115
|
+
const redirectUrl = new URL(location, currentUrl);
|
|
116
|
+
if (!await isSafeProxyTarget(
|
|
117
|
+
redirectUrl.toString(),
|
|
118
|
+
options.allowLoopback ?? false
|
|
119
|
+
) || options.validateRequest && !await options.validateRequest(redirectUrl.toString(), c)) {
|
|
120
|
+
return c.json({ error: "Redirect target is not allowed" }, 403);
|
|
121
|
+
}
|
|
122
|
+
if (redirectUrl.origin !== new URL(currentUrl).origin) {
|
|
123
|
+
deleteHeader(headers, "authorization");
|
|
124
|
+
deleteHeader(headers, "proxy-authorization");
|
|
125
|
+
}
|
|
126
|
+
if (response.status === 303 || (response.status === 301 || response.status === 302) && currentMethod === "POST") {
|
|
127
|
+
currentMethod = "GET";
|
|
128
|
+
currentBody = void 0;
|
|
129
|
+
deleteHeader(headers, "content-type");
|
|
130
|
+
deleteHeader(headers, "content-length");
|
|
131
|
+
}
|
|
132
|
+
currentUrl = redirectUrl.toString();
|
|
158
133
|
}
|
|
159
|
-
const bodyBuffer = await response.arrayBuffer();
|
|
160
|
-
responseHeaders["Content-Length"] = String(bodyBuffer.byteLength);
|
|
161
|
-
return new Response(bodyBuffer, {
|
|
162
|
-
status: response.status,
|
|
163
|
-
statusText: response.statusText,
|
|
164
|
-
headers: responseHeaders
|
|
165
|
-
});
|
|
166
134
|
} catch (error) {
|
|
167
135
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
168
136
|
const targetUrl = c.req.header("X-Target-URL");
|
|
@@ -192,6 +160,38 @@ function mountMcpProxy(app, options = {}) {
|
|
|
192
160
|
}
|
|
193
161
|
});
|
|
194
162
|
}
|
|
163
|
+
function deleteHeader(headers, name) {
|
|
164
|
+
for (const key of Object.keys(headers)) {
|
|
165
|
+
if (key.toLowerCase() === name) delete headers[key];
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async function proxyResponse(response) {
|
|
169
|
+
const responseHeaders = {};
|
|
170
|
+
response.headers.forEach((value, key) => {
|
|
171
|
+
const lowerKey = key.toLowerCase();
|
|
172
|
+
if (lowerKey !== "content-encoding" && lowerKey !== "transfer-encoding" && lowerKey !== "content-length" && lowerKey !== "set-cookie") {
|
|
173
|
+
responseHeaders[key] = value;
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
const isTrueStream = isOpenEndedSseResponse(
|
|
177
|
+
response.headers.get("content-type") || "",
|
|
178
|
+
response.headers.get("content-length")
|
|
179
|
+
);
|
|
180
|
+
if (isTrueStream) {
|
|
181
|
+
return new Response(response.body, {
|
|
182
|
+
status: response.status,
|
|
183
|
+
statusText: response.statusText,
|
|
184
|
+
headers: responseHeaders
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
const bodyBuffer = await response.arrayBuffer();
|
|
188
|
+
responseHeaders["Content-Length"] = String(bodyBuffer.byteLength);
|
|
189
|
+
return new Response(bodyBuffer, {
|
|
190
|
+
status: response.status,
|
|
191
|
+
statusText: response.statusText,
|
|
192
|
+
headers: responseHeaders
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
195
|
|
|
196
196
|
export {
|
|
197
197
|
isOpenEndedSseResponse,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
mountMcpProxy
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-2K7OKCVV.js";
|
|
4
4
|
import {
|
|
5
5
|
mountOAuthProxy
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-V5A5XLFJ.js";
|
|
7
7
|
|
|
8
8
|
// src/server/proxy-routes.ts
|
|
9
9
|
function registerInspectorProxyRoutes(app, config, basePath = "") {
|
|
@@ -25,6 +25,7 @@ function registerInspectorProxyRoutes(app, config, basePath = "") {
|
|
|
25
25
|
if (mountOAuth) {
|
|
26
26
|
mountOAuthProxy(app, {
|
|
27
27
|
basePath: p("/inspector/api/oauth"),
|
|
28
|
+
callbackPath: p("/inspector/oauth/callback"),
|
|
28
29
|
enableLogging: true,
|
|
29
30
|
allowedOrigins: config?.oauthProxyAllowedOrigins ?? [],
|
|
30
31
|
allowLoopback
|
|
@@ -1,76 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
registerInspectorStaticAssets
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-PZF2PUDE.js";
|
|
4
4
|
import {
|
|
5
5
|
getInspectorVersion
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
resolveInspectorAssetUrls
|
|
9
|
-
} from "./chunk-JZT7N2BJ.js";
|
|
10
|
-
import {
|
|
11
|
-
registerInspectorFaviconStatic
|
|
12
|
-
} from "./chunk-J4FNYLBF.js";
|
|
6
|
+
} from "./chunk-RFJAZOK7.js";
|
|
13
7
|
import {
|
|
14
8
|
renderInspectorFaviconLinks
|
|
15
9
|
} from "./chunk-WFT4JHYI.js";
|
|
16
10
|
|
|
17
|
-
// src/server/
|
|
11
|
+
// src/server/inspector-shell.ts
|
|
18
12
|
var INSPECTOR_VERSION = getInspectorVersion();
|
|
19
|
-
var INSPECTOR_VERSION_RESOLVER_URL = "https://data.jsdelivr.com/v1/packages/npm/@mcp-use/inspector/resolved?specifier=beta";
|
|
20
|
-
var INSPECTOR_CDN_PACKAGE_URL = "https://cdn.jsdelivr.net/npm/@mcp-use/inspector";
|
|
21
13
|
var OAUTH_POPUP_CLOSED_HTML = `<!doctype html>
|
|
22
14
|
<html lang="en"><head><meta charset="utf-8"><title>Signed in</title><meta name="robots" content="noindex"><style>html,body{margin:0;height:100%;display:flex;align-items:center;justify-content:center;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#4b5563;background:#fff}</style></head>
|
|
23
15
|
<body><div>Signed in. You can close this window.</div>
|
|
24
16
|
<script>try{if(window.opener&&!window.opener.closed)window.opener.postMessage({type:"manufact:oauth-complete"},"*")}catch(e){}try{window.close()}catch(e){}</script>
|
|
25
17
|
</body></html>`;
|
|
26
|
-
function
|
|
27
|
-
return `<script type="module">
|
|
28
|
-
const resolverUrl = ${JSON.stringify(INSPECTOR_VERSION_RESOLVER_URL)};
|
|
29
|
-
const packageUrl = ${JSON.stringify(INSPECTOR_CDN_PACKAGE_URL)};
|
|
30
|
-
const versionPattern = /^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$/;
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
const controller = new AbortController();
|
|
34
|
-
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
35
|
-
let response;
|
|
36
|
-
try {
|
|
37
|
-
response = await fetch(resolverUrl, { signal: controller.signal });
|
|
38
|
-
} finally {
|
|
39
|
-
clearTimeout(timeout);
|
|
40
|
-
}
|
|
41
|
-
if (!response.ok) {
|
|
42
|
-
throw new Error(\`Inspector version resolver returned HTTP \${response.status}\`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const resolved = await response.json();
|
|
46
|
-
if (
|
|
47
|
-
resolved?.name !== "@mcp-use/inspector" ||
|
|
48
|
-
typeof resolved.version !== "string" ||
|
|
49
|
-
!versionPattern.test(resolved.version)
|
|
50
|
-
) {
|
|
51
|
-
throw new Error("Inspector version resolver returned an invalid release");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const version = resolved.version;
|
|
55
|
-
const assetBase = \`\${packageUrl}@\${version}/dist/cdn\`;
|
|
56
|
-
const stylesheet = document.createElement("link");
|
|
57
|
-
stylesheet.rel = "stylesheet";
|
|
58
|
-
stylesheet.href = \`\${assetBase}/inspector.css\`;
|
|
59
|
-
document.head.append(stylesheet);
|
|
60
|
-
|
|
61
|
-
window.__INSPECTOR_VERSION__ = version;
|
|
62
|
-
await import(\`\${assetBase}/inspector.js\`);
|
|
63
|
-
} catch (error) {
|
|
64
|
-
console.error("[Inspector] Failed to load the latest Inspector release:", error);
|
|
65
|
-
document.querySelector(".mcp-boot-spinner")?.remove();
|
|
66
|
-
const label = document.querySelector(".mcp-boot-label");
|
|
67
|
-
if (label) {
|
|
68
|
-
label.textContent = "Unable to load Inspector. Reload to try again.";
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
</script>`;
|
|
72
|
-
}
|
|
73
|
-
function generateCdnShellHtml(config, basePath, assets) {
|
|
18
|
+
function generateInspectorShellHtml(config, basePath, assets) {
|
|
74
19
|
const scripts = [];
|
|
75
20
|
if (config?.basePath !== void 0) {
|
|
76
21
|
scripts.push(
|
|
@@ -105,22 +50,20 @@ function generateCdnShellHtml(config, basePath, assets) {
|
|
|
105
50
|
`<script>window.__MCP_USE_ANONYMIZED_TELEMETRY__ = false;try{localStorage.setItem("MCP_USE_ANONYMIZED_TELEMETRY","false");}catch(e){}</script>`
|
|
106
51
|
);
|
|
107
52
|
}
|
|
53
|
+
if (process.env.MCP_USE_DEV_CLI === "1") {
|
|
54
|
+
scripts.push(`<script>window.__MCP_DEV_CLI__ = true;</script>`);
|
|
55
|
+
}
|
|
108
56
|
const runtimeScripts = scripts.join("\n ");
|
|
109
|
-
const assetPreconnects = assets.resolveLatest ? ` <link rel="preconnect" href="https://data.jsdelivr.com" crossorigin />
|
|
110
|
-
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />` : "";
|
|
111
|
-
const stylesheetTag = assets.resolveLatest ? "" : ` <link rel="stylesheet" href="${assets.cssUrl}" />`;
|
|
112
|
-
const assetLoader = assets.resolveLatest ? renderDefaultInspectorAssetLoader() : `<script type="module" src="${assets.jsUrl}"></script>`;
|
|
113
57
|
return `<!doctype html>
|
|
114
58
|
<html lang="en">
|
|
115
59
|
<head>
|
|
116
60
|
<meta charset="UTF-8" />
|
|
117
|
-
${renderInspectorFaviconLinks(basePath)}
|
|
61
|
+
${renderInspectorFaviconLinks(`${basePath}/inspector/assets`)}
|
|
118
62
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
119
63
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
120
64
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
121
|
-
${assetPreconnects}
|
|
122
65
|
<link href="https://fonts.googleapis.com/css2?family=Ubuntu:wght@400;500;700&display=swap" rel="stylesheet" />
|
|
123
|
-
${
|
|
66
|
+
<link rel="stylesheet" href="${assets.cssUrl}" />
|
|
124
67
|
<title>Inspector | mcp-use</title>
|
|
125
68
|
<meta name="description" content="Free, open-source MCP Inspector by mcp-use. Connect to any MCP server, test tools, prompts, and resources, inspect RPC logs, and debug MCP apps \u2014 all in your browser." />
|
|
126
69
|
<style>
|
|
@@ -200,12 +143,17 @@ ${stylesheetTag}
|
|
|
200
143
|
</div>
|
|
201
144
|
</div>
|
|
202
145
|
</div>
|
|
203
|
-
${
|
|
146
|
+
<script type="module" src="${assets.jsUrl}"></script>
|
|
204
147
|
</body>
|
|
205
148
|
</html>`;
|
|
206
149
|
}
|
|
207
|
-
function
|
|
208
|
-
const
|
|
150
|
+
function registerInspectorShell(app, config, basePath = "") {
|
|
151
|
+
const assetsPath = `${basePath}/inspector/assets`;
|
|
152
|
+
const version = encodeURIComponent(INSPECTOR_VERSION);
|
|
153
|
+
const assets = {
|
|
154
|
+
jsUrl: `${assetsPath}/inspector.js?v=${version}`,
|
|
155
|
+
cssUrl: `${assetsPath}/inspector.css?v=${version}`
|
|
156
|
+
};
|
|
209
157
|
const p = (suffix) => `${basePath}${suffix}`;
|
|
210
158
|
const effectiveConfig = {
|
|
211
159
|
...config,
|
|
@@ -214,10 +162,11 @@ function registerInspectorCdnShell(app, config, basePath = "") {
|
|
|
214
162
|
disableTelemetry: config?.disableTelemetry ?? process.env.MCP_USE_ANONYMIZED_TELEMETRY === "false"
|
|
215
163
|
};
|
|
216
164
|
const serveShell = (c) => {
|
|
217
|
-
|
|
218
|
-
|
|
165
|
+
return c.html(
|
|
166
|
+
generateInspectorShellHtml(effectiveConfig, basePath, assets)
|
|
167
|
+
);
|
|
219
168
|
};
|
|
220
|
-
|
|
169
|
+
registerInspectorStaticAssets(app, assetsPath);
|
|
221
170
|
app.get(
|
|
222
171
|
p("/inspector/oauth-popup-closed.html"),
|
|
223
172
|
(c) => c.html(OAUTH_POPUP_CLOSED_HTML)
|
|
@@ -237,17 +186,14 @@ function registerInspectorCdnShell(app, config, basePath = "") {
|
|
|
237
186
|
}
|
|
238
187
|
return serveShell(c);
|
|
239
188
|
});
|
|
240
|
-
if (basePath === "") {
|
|
189
|
+
if (basePath === "" && config?.rootRedirect !== false) {
|
|
241
190
|
app.get("/", (c) => {
|
|
242
191
|
const url = new URL(c.req.url);
|
|
243
192
|
return c.redirect(`${p("/inspector")}${url.search}`);
|
|
244
193
|
});
|
|
245
194
|
}
|
|
246
|
-
if (assets.useLocal) {
|
|
247
|
-
registerInspectorStaticAssets(app, basePath);
|
|
248
|
-
}
|
|
249
195
|
}
|
|
250
196
|
|
|
251
197
|
export {
|
|
252
|
-
|
|
198
|
+
registerInspectorShell
|
|
253
199
|
};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import {
|
|
2
|
+
registerInspectorShell
|
|
3
|
+
} from "./chunk-EPPZCSJQ.js";
|
|
4
|
+
import {
|
|
5
|
+
registerInspectorProxyRoutes
|
|
6
|
+
} from "./chunk-EKD2XITW.js";
|
|
7
|
+
|
|
8
|
+
// src/server/middleware.ts
|
|
9
|
+
import { Hono } from "hono";
|
|
10
|
+
import { Readable } from "stream";
|
|
11
|
+
function mountInspector(appOrOptions, maybeOptions) {
|
|
12
|
+
if (isMountableApp(appOrOptions)) {
|
|
13
|
+
const app = appOrOptions;
|
|
14
|
+
const options2 = maybeOptions;
|
|
15
|
+
const basePath2 = normalizeInspectorBasePath(options2?.basePath);
|
|
16
|
+
if (isHonoApp(app)) {
|
|
17
|
+
registerInspectorRoutes(app, options2, basePath2);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const inspectorApp = createInspectorApp(options2, basePath2);
|
|
21
|
+
const inspectorFetch = toInspectorFetchHandler(inspectorApp);
|
|
22
|
+
app.use(
|
|
23
|
+
createExpressInspectorMiddleware(
|
|
24
|
+
inspectorFetch,
|
|
25
|
+
inspectorApp.routes.map((route) => route.path)
|
|
26
|
+
)
|
|
27
|
+
);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const options = appOrOptions;
|
|
31
|
+
const basePath = normalizeInspectorBasePath(options?.basePath);
|
|
32
|
+
return toInspectorFetchHandler(createInspectorApp(options, basePath));
|
|
33
|
+
}
|
|
34
|
+
function createInspectorApp(options, basePath) {
|
|
35
|
+
const app = new Hono();
|
|
36
|
+
registerInspectorRoutes(app, options, basePath);
|
|
37
|
+
return app;
|
|
38
|
+
}
|
|
39
|
+
function registerInspectorRoutes(app, options, basePath) {
|
|
40
|
+
const routesConfig = {
|
|
41
|
+
oauthProxyAllowedOrigins: options?.oauthProxyAllowedOrigins ?? [],
|
|
42
|
+
// mountInspector is development tooling. Loopback is therefore useful and
|
|
43
|
+
// safe by default, while callers embedding it elsewhere can opt out.
|
|
44
|
+
oauthProxyAllowLoopback: options?.oauthProxyAllowLoopback ?? true
|
|
45
|
+
};
|
|
46
|
+
if (options?.autoConnectUrl !== void 0) {
|
|
47
|
+
routesConfig.autoConnectUrl = options.autoConnectUrl;
|
|
48
|
+
} else {
|
|
49
|
+
app.get(`${basePath}/inspector/config.json`, (c) => {
|
|
50
|
+
const requestUrl = new URL(c.req.url);
|
|
51
|
+
return c.json({ autoConnectUrl: `${requestUrl.origin}${basePath}` });
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
registerInspectorProxyRoutes(app, routesConfig, basePath);
|
|
55
|
+
registerInspectorShell(
|
|
56
|
+
app,
|
|
57
|
+
{
|
|
58
|
+
devMode: options?.devMode ?? true,
|
|
59
|
+
sandboxOrigin: options?.sandboxOrigin,
|
|
60
|
+
inspectorMode: "embedded",
|
|
61
|
+
rootRedirect: false,
|
|
62
|
+
basePath,
|
|
63
|
+
proxyUrl: `${basePath}/inspector/api/proxy`,
|
|
64
|
+
manufactChatUrl: options?.manufactChatUrl
|
|
65
|
+
},
|
|
66
|
+
basePath
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
function toInspectorFetchHandler(app) {
|
|
70
|
+
return (request) => Promise.resolve(app.fetch(request));
|
|
71
|
+
}
|
|
72
|
+
function createExpressInspectorMiddleware(fetch, registeredPaths) {
|
|
73
|
+
const exactPaths = new Set(
|
|
74
|
+
registeredPaths.filter((path) => !path.includes("*"))
|
|
75
|
+
);
|
|
76
|
+
const prefixPaths = registeredPaths.filter((path) => path.endsWith("/*")).map((path) => path.slice(0, -1));
|
|
77
|
+
return (req, res, next) => {
|
|
78
|
+
const url = new URL(req.originalUrl || req.url || "", requestOrigin(req));
|
|
79
|
+
if (!exactPaths.has(url.pathname) && !prefixPaths.some((prefix) => url.pathname.startsWith(prefix))) {
|
|
80
|
+
next();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const request = expressRequestToFetchRequest(req, url);
|
|
84
|
+
void fetch(request).then((fetchResponse) => writeFetchResponse(res, fetchResponse)).catch(next);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function requestOrigin(req) {
|
|
88
|
+
const forwardedProtocol = firstHeaderValue(req.headers["x-forwarded-proto"]);
|
|
89
|
+
const protocol = forwardedProtocol || req.protocol || "http";
|
|
90
|
+
const forwardedHost = firstHeaderValue(req.headers["x-forwarded-host"]);
|
|
91
|
+
const host = forwardedHost || firstHeaderValue(req.headers.host) || "localhost";
|
|
92
|
+
return `${protocol}://${host}`;
|
|
93
|
+
}
|
|
94
|
+
function firstHeaderValue(value) {
|
|
95
|
+
return Array.isArray(value) ? value[0] ?? "" : (value ?? "").split(",")[0].trim();
|
|
96
|
+
}
|
|
97
|
+
function expressRequestToFetchRequest(req, url) {
|
|
98
|
+
const init = {
|
|
99
|
+
method: req.method,
|
|
100
|
+
headers: req.headers
|
|
101
|
+
};
|
|
102
|
+
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
103
|
+
if (req.body !== void 0) {
|
|
104
|
+
init.body = bodyToRequestBody(req.body);
|
|
105
|
+
} else {
|
|
106
|
+
init.body = Readable.toWeb(req);
|
|
107
|
+
init.duplex = "half";
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return new globalThis.Request(url, init);
|
|
111
|
+
}
|
|
112
|
+
function bodyToRequestBody(body) {
|
|
113
|
+
if (typeof body === "string" || body instanceof ArrayBuffer || ArrayBuffer.isView(body) || body instanceof Blob || body instanceof FormData || body instanceof URLSearchParams || body instanceof ReadableStream) {
|
|
114
|
+
return body;
|
|
115
|
+
}
|
|
116
|
+
return JSON.stringify(body);
|
|
117
|
+
}
|
|
118
|
+
async function writeFetchResponse(res, fetchResponse) {
|
|
119
|
+
res.status(fetchResponse.status);
|
|
120
|
+
fetchResponse.headers.forEach((value, key) => {
|
|
121
|
+
if (key !== "set-cookie") res.setHeader(key, value);
|
|
122
|
+
});
|
|
123
|
+
const setCookies = fetchResponse.headers.getSetCookie();
|
|
124
|
+
if (setCookies.length > 0) res.setHeader("set-cookie", setCookies);
|
|
125
|
+
if (!fetchResponse.body) {
|
|
126
|
+
res.end();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const reader = fetchResponse.body.getReader();
|
|
130
|
+
while (true) {
|
|
131
|
+
const { done, value } = await reader.read();
|
|
132
|
+
if (done) break;
|
|
133
|
+
res.write(value);
|
|
134
|
+
}
|
|
135
|
+
res.end();
|
|
136
|
+
}
|
|
137
|
+
function isMountableApp(value) {
|
|
138
|
+
if (!value || typeof value !== "object" && typeof value !== "function") {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return typeof value.use === "function" || isHonoApp(value);
|
|
142
|
+
}
|
|
143
|
+
function isHonoApp(value) {
|
|
144
|
+
return !!value && typeof value === "object" && typeof value.fetch === "function" && typeof value.route === "function";
|
|
145
|
+
}
|
|
146
|
+
function normalizeInspectorBasePath(raw) {
|
|
147
|
+
if (raw === void 0) return "/mcp";
|
|
148
|
+
let value = raw.trim().replace(/\/{2,}/g, "/").replace(/\/+$/, "");
|
|
149
|
+
if (value === "" || value === "/") return "";
|
|
150
|
+
if (!value.startsWith("/")) value = `/${value}`;
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export {
|
|
155
|
+
mountInspector
|
|
156
|
+
};
|
|
@@ -10,45 +10,49 @@ var CONTENT_TYPES = {
|
|
|
10
10
|
".ico": "image/x-icon",
|
|
11
11
|
".webmanifest": "application/manifest+json"
|
|
12
12
|
};
|
|
13
|
-
function
|
|
13
|
+
function resolveInspectorAppDir() {
|
|
14
14
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
15
15
|
for (const dir of [
|
|
16
|
-
path.resolve(here, "
|
|
16
|
+
path.resolve(here, "app"),
|
|
17
17
|
// dist/cli.js (bundled)
|
|
18
|
-
path.resolve(here, "../
|
|
18
|
+
path.resolve(here, "../app"),
|
|
19
19
|
// dist/server/*.js
|
|
20
|
+
path.resolve(here, "../../dist/app")
|
|
21
|
+
// src/server/*.ts (workspace dev)
|
|
20
22
|
]) {
|
|
21
23
|
if (existsSync(path.join(dir, "inspector.js"))) {
|
|
22
24
|
return dir;
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
throw new Error(
|
|
26
|
-
"Inspector bundle not found (expected dist/
|
|
28
|
+
"Inspector bundle not found (expected dist/app/inspector.js)"
|
|
27
29
|
);
|
|
28
30
|
}
|
|
29
|
-
function registerInspectorStaticAssets(app,
|
|
30
|
-
const
|
|
31
|
-
const mountPath = `${basePath}/dist/cdn`;
|
|
31
|
+
function registerInspectorStaticAssets(app, mountPath = "/inspector/assets") {
|
|
32
|
+
const appDir = resolveInspectorAppDir();
|
|
32
33
|
app.get(`${mountPath}/*`, (c) => {
|
|
33
34
|
const subPath = c.req.path.slice(mountPath.length);
|
|
34
35
|
const relative = subPath.startsWith("/") ? subPath.slice(1) : subPath;
|
|
35
36
|
if (!relative || relative.includes("..")) {
|
|
36
37
|
return c.notFound();
|
|
37
38
|
}
|
|
38
|
-
const file = path.resolve(
|
|
39
|
-
const root =
|
|
39
|
+
const file = path.resolve(appDir, relative);
|
|
40
|
+
const root = appDir.endsWith(path.sep) ? appDir : `${appDir}${path.sep}`;
|
|
40
41
|
if (!file.startsWith(root) || !existsSync(file)) {
|
|
41
42
|
return c.notFound();
|
|
42
43
|
}
|
|
43
44
|
const ext = path.extname(file);
|
|
44
45
|
return c.body(readFileSync(file), 200, {
|
|
45
46
|
"Content-Type": CONTENT_TYPES[ext] ?? "application/octet-stream",
|
|
46
|
-
|
|
47
|
+
// Standalone assets use stable URLs across CLI restarts. Revalidate them
|
|
48
|
+
// so a rebuilt or upgraded Inspector cannot keep running an hour-old UI
|
|
49
|
+
// bundle that predates its storage migrations or proxy contract.
|
|
50
|
+
"Cache-Control": "no-cache"
|
|
47
51
|
});
|
|
48
52
|
});
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
export {
|
|
52
|
-
|
|
56
|
+
resolveInspectorAppDir,
|
|
53
57
|
registerInspectorStaticAssets
|
|
54
58
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "@mcp-use/inspector",
|
|
4
4
|
type: "module",
|
|
5
|
-
version: "20.0.0-beta.
|
|
5
|
+
version: "20.0.0-beta.16",
|
|
6
6
|
description: "MCP Inspector - A tool for inspecting and debugging MCP servers",
|
|
7
7
|
author: "",
|
|
8
8
|
license: "MIT",
|
|
@@ -24,7 +24,13 @@ var package_default = {
|
|
|
24
24
|
exports: {
|
|
25
25
|
".": {
|
|
26
26
|
types: "./dist/server/index.d.ts",
|
|
27
|
-
import: "./dist/server/index.js"
|
|
27
|
+
import: "./dist/server/index.js",
|
|
28
|
+
default: "./dist/server/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./dev": {
|
|
31
|
+
types: "./dist/server/index.d.ts",
|
|
32
|
+
import: "./dist/server/index.js",
|
|
33
|
+
default: "./dist/server/index.js"
|
|
28
34
|
},
|
|
29
35
|
"./proxy": {
|
|
30
36
|
types: "./dist/server/proxy-routes.d.ts",
|
|
@@ -48,12 +54,13 @@ var package_default = {
|
|
|
48
54
|
"dev:client": "pnpm run dev",
|
|
49
55
|
"dev:server": "VITE_DEV=true tsx watch src/server/server.ts",
|
|
50
56
|
"dev:standalone": "tsx watch src/server/server.ts",
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
+
clean: "rimraf dist",
|
|
58
|
+
build: "npm run clean && npm run build:client && npm run build:client-exports && npm run build:server && npm run build:cli && npm run build:app",
|
|
59
|
+
"build:app": "vite build --config vite.app.config.ts",
|
|
60
|
+
"watch:app": "vite build --watch --config vite.app.config.ts",
|
|
61
|
+
"preview:app": "vite preview --config vite.app.config.ts --host 127.0.0.1",
|
|
62
|
+
"serve:app": "pnpm build:app && pnpm preview:app",
|
|
63
|
+
"analyze:app": "ANALYZE=true vite build --config vite.app.config.ts",
|
|
57
64
|
"build:client": "vite build",
|
|
58
65
|
"build:client-exports": "tsup --config tsup.client.ts && tsc -p tsconfig.client.json --emitDeclarationOnly --declaration",
|
|
59
66
|
"build:server": "tsup 'src/server/**/*.ts' --format esm --out-dir dist/server && tsc -p tsconfig.server.json --emitDeclarationOnly --declaration",
|
|
@@ -93,8 +100,20 @@ var package_default = {
|
|
|
93
100
|
"react-router": "^7.12.0"
|
|
94
101
|
},
|
|
95
102
|
peerDependenciesMeta: {
|
|
103
|
+
"@mcp-use/client": {
|
|
104
|
+
optional: true
|
|
105
|
+
},
|
|
96
106
|
express: {
|
|
97
107
|
optional: true
|
|
108
|
+
},
|
|
109
|
+
react: {
|
|
110
|
+
optional: true
|
|
111
|
+
},
|
|
112
|
+
"react-dom": {
|
|
113
|
+
optional: true
|
|
114
|
+
},
|
|
115
|
+
"react-router": {
|
|
116
|
+
optional: true
|
|
98
117
|
}
|
|
99
118
|
},
|
|
100
119
|
dependencies: {
|