@mcp-use/inspector 0.6.1 → 0.7.0
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/dist/cli.js +295 -19
- package/dist/client/assets/__vite-browser-external-CHS79mP1.js +8 -0
- package/dist/client/assets/browser-BdCJ_qyB.js +38211 -0
- package/dist/client/assets/chunk-VL2OQCWN-CxD8xDNw.js +6475 -0
- package/dist/client/assets/display-YIYC6WJE-B6ZSv77R.js +44742 -0
- package/dist/client/assets/embeddings-DlCMB9po.js +21 -0
- package/dist/client/assets/index-B0NYybvW.js +5371 -0
- package/dist/client/assets/index-CKXUnlZB.js +94617 -0
- package/dist/client/assets/index-Cb09SlUY.js +17535 -0
- package/dist/client/assets/index-CsP5AdwX.js +10699 -0
- package/dist/client/assets/index-DX0TIfSM.js +102 -0
- package/dist/client/assets/index-Q_pqNaNk.js +1780 -0
- package/dist/client/assets/index-kVFYovMy.css +5752 -0
- package/dist/client/assets/path-QsnVvLoj.js +62 -0
- package/dist/client/assets/transport-wrapper-browser-ChPHVnHg.js +165 -0
- package/dist/client/assets/winston-qgF6niUt.js +12326 -0
- package/dist/client/index.html +3 -3
- package/dist/server/{chunk-37X7HLUV.js → chunk-3T2VCYG6.js} +87 -13
- package/dist/server/chunk-CVECQ7BJ.js +78 -0
- package/dist/server/{chunk-555LGZ3I.js → chunk-FS77NTZN.js} +133 -10
- package/dist/server/chunk-PKBMQBKP.js +7 -0
- package/dist/server/{chunk-WYBXXYSP.js → chunk-RRPLH7DL.js} +1 -1
- package/dist/server/{chunk-PYGYQT2G.js → chunk-S7NOZBMG.js} +3 -3
- package/dist/server/{chunk-DGUMOD7P.js → chunk-ZONLXYBO.js} +92 -10
- package/dist/server/cli.js +6 -4
- package/dist/server/index.js +7 -5
- package/dist/server/middleware.js +7 -5
- package/dist/server/rpc-log-bus.d.ts +17 -0
- package/dist/server/rpc-log-bus.d.ts.map +1 -0
- package/dist/server/rpc-log-bus.js +7 -0
- package/dist/server/server.js +6 -4
- package/dist/server/shared-routes.d.ts.map +1 -1
- package/dist/server/shared-routes.js +4 -2
- package/dist/server/shared-static.js +3 -2
- package/dist/server/shared-utils-browser.d.ts +2 -1
- package/dist/server/shared-utils-browser.d.ts.map +1 -1
- package/dist/server/shared-utils-browser.js +2 -1
- package/dist/server/shared-utils.d.ts +4 -1
- package/dist/server/shared-utils.d.ts.map +1 -1
- package/dist/server/shared-utils.js +2 -1
- package/dist/server/transport-wrapper.d.ts +6 -0
- package/dist/server/transport-wrapper.d.ts.map +1 -0
- package/dist/server/transport-wrapper.js +68 -0
- package/dist/server/utils.js +1 -0
- package/package.json +12 -3
- package/dist/client/assets/__vite-browser-external-DFygW7-s.js +0 -1
- package/dist/client/assets/chunk-VL2OQCWN-iRVOQjqe.js +0 -8
- package/dist/client/assets/display-LIYVTGEU-D2dm8q2H.js +0 -30
- package/dist/client/assets/embeddings-Dcyp0Vlp.js +0 -1
- package/dist/client/assets/index-6zrNEwtM.js +0 -4
- package/dist/client/assets/index-CAnbiFOL.css +0 -1
- package/dist/client/assets/index-CB1s6Wr6.js +0 -146
- package/dist/client/assets/index-CoMldIFv.js +0 -2
- package/dist/client/assets/index-DRz5BQNA.js +0 -1
- package/dist/client/assets/index-DUf1336L.js +0 -1559
- package/dist/client/assets/index-DmIKR5St.js +0 -1
- package/dist/client/assets/index-DpUpZFq2.js +0 -25
- package/dist/client/assets/index-DzegZXPW.js +0 -40
- package/dist/client/assets/langfuse-C4HKZ3NL-vCtAvQQV.js +0 -564
- package/dist/client/assets/path-C9FudP8b.js +0 -1
- package/dist/client/assets/winston-BVJ8PyEn.js +0 -37
package/dist/client/index.html
CHANGED
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
rel="stylesheet"
|
|
28
28
|
/>
|
|
29
29
|
<title>Inspector | mcp-use</title>
|
|
30
|
-
<script type="module" crossorigin src="/inspector/assets/index-
|
|
31
|
-
<link rel="stylesheet" crossorigin href="/inspector/assets/index-
|
|
32
|
-
<script>window.__INSPECTOR_VERSION__ = "0.
|
|
30
|
+
<script type="module" crossorigin src="/inspector/assets/index-CKXUnlZB.js"></script>
|
|
31
|
+
<link rel="stylesheet" crossorigin href="/inspector/assets/index-kVFYovMy.css">
|
|
32
|
+
<script>window.__INSPECTOR_VERSION__ = "0.7.0";</script>
|
|
33
33
|
</head>
|
|
34
34
|
<body>
|
|
35
35
|
<script>
|
|
@@ -267,7 +267,9 @@ function storeWidgetData(data) {
|
|
|
267
267
|
toolOutput,
|
|
268
268
|
resourceData,
|
|
269
269
|
toolId,
|
|
270
|
-
widgetCSP
|
|
270
|
+
widgetCSP: _widgetCSP,
|
|
271
|
+
devWidgetUrl,
|
|
272
|
+
devServerBaseUrl
|
|
271
273
|
} = data;
|
|
272
274
|
console.log("[Widget Store] Received request for toolId:", toolId);
|
|
273
275
|
console.log("[Widget Store] Fields:", {
|
|
@@ -276,7 +278,9 @@ function storeWidgetData(data) {
|
|
|
276
278
|
hasResourceData: !!resourceData,
|
|
277
279
|
hasToolInput: !!toolInput,
|
|
278
280
|
hasToolOutput: !!toolOutput,
|
|
279
|
-
hasWidgetCSP: !!
|
|
281
|
+
hasWidgetCSP: !!_widgetCSP,
|
|
282
|
+
devWidgetUrl,
|
|
283
|
+
devServerBaseUrl
|
|
280
284
|
});
|
|
281
285
|
if (!serverId || !uri || !toolId || !resourceData) {
|
|
282
286
|
const missingFields = [];
|
|
@@ -298,7 +302,9 @@ function storeWidgetData(data) {
|
|
|
298
302
|
resourceData,
|
|
299
303
|
toolId,
|
|
300
304
|
timestamp: Date.now(),
|
|
301
|
-
widgetCSP
|
|
305
|
+
widgetCSP: _widgetCSP,
|
|
306
|
+
devWidgetUrl,
|
|
307
|
+
devServerBaseUrl
|
|
302
308
|
});
|
|
303
309
|
console.log("[Widget Store] Data stored successfully for toolId:", toolId);
|
|
304
310
|
return { success: true };
|
|
@@ -341,7 +347,17 @@ function generateWidgetContainerHtml(basePath, toolId) {
|
|
|
341
347
|
`;
|
|
342
348
|
}
|
|
343
349
|
function generateWidgetContentHtml(widgetData) {
|
|
344
|
-
const {
|
|
350
|
+
const {
|
|
351
|
+
serverId,
|
|
352
|
+
uri,
|
|
353
|
+
toolInput,
|
|
354
|
+
toolOutput,
|
|
355
|
+
resourceData,
|
|
356
|
+
toolId,
|
|
357
|
+
widgetCSP: _widgetCSP,
|
|
358
|
+
devServerBaseUrl,
|
|
359
|
+
theme
|
|
360
|
+
} = widgetData;
|
|
345
361
|
console.log("[Widget Content] Using pre-fetched resource for:", {
|
|
346
362
|
serverId,
|
|
347
363
|
uri
|
|
@@ -372,23 +388,31 @@ function generateWidgetContentHtml(widgetData) {
|
|
|
372
388
|
const safeToolOutput = JSON.stringify(toolOutput ?? null).replace(/</g, "\\u003c").replace(/>/g, "\\u003e");
|
|
373
389
|
const safeToolId = JSON.stringify(toolId);
|
|
374
390
|
const safeWidgetStateKey = JSON.stringify(widgetStateKey);
|
|
391
|
+
const safeTheme = JSON.stringify(theme === "dark" ? "dark" : "light");
|
|
375
392
|
const apiScript = `
|
|
376
393
|
<script>
|
|
377
394
|
(function() {
|
|
378
395
|
'use strict';
|
|
379
396
|
|
|
380
397
|
// Change URL to "/" for React Router compatibility
|
|
381
|
-
if
|
|
398
|
+
// Skip if running in Inspector dev-widget proxy to prevent redirecting iframe to Inspector home
|
|
399
|
+
if (window.location.pathname !== '/' && !window.location.pathname.includes('/dev-widget/')) {
|
|
382
400
|
history.replaceState(null, '', '/');
|
|
383
401
|
}
|
|
384
402
|
|
|
403
|
+
// Inject MCP widget utilities for Image component and file access
|
|
404
|
+
window.__mcpPublicUrl = ${devServerBaseUrl ? `"${devServerBaseUrl}/mcp-use/public"` : '""'};
|
|
405
|
+
window.__getFile = function(filename) {
|
|
406
|
+
return ${devServerBaseUrl ? `"${devServerBaseUrl}/mcp-use/widgets/"` : '""'} + filename;
|
|
407
|
+
};
|
|
408
|
+
|
|
385
409
|
const openaiAPI = {
|
|
386
410
|
toolInput: ${safeToolInput},
|
|
387
411
|
toolOutput: ${safeToolOutput},
|
|
388
412
|
toolResponseMetadata: null,
|
|
389
413
|
displayMode: 'inline',
|
|
390
414
|
maxHeight: 600,
|
|
391
|
-
theme:
|
|
415
|
+
theme: ${safeTheme},
|
|
392
416
|
locale: 'en-US',
|
|
393
417
|
safeArea: { insets: { top: 0, bottom: 0, left: 0, right: 0 } },
|
|
394
418
|
userAgent: {},
|
|
@@ -483,6 +507,17 @@ function generateWidgetContentHtml(widgetData) {
|
|
|
483
507
|
enumerable: true
|
|
484
508
|
});
|
|
485
509
|
|
|
510
|
+
// Listen for widget state requests from inspector
|
|
511
|
+
window.addEventListener('message', (event) => {
|
|
512
|
+
if (event.data?.type === 'mcp-inspector:getWidgetState') {
|
|
513
|
+
window.parent.postMessage({
|
|
514
|
+
type: 'mcp-inspector:widgetStateResponse',
|
|
515
|
+
toolId: event.data.toolId,
|
|
516
|
+
state: openaiAPI.widgetState
|
|
517
|
+
}, '*');
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
|
|
486
521
|
setTimeout(() => {
|
|
487
522
|
try {
|
|
488
523
|
const globalsEvent = new CustomEvent('openai:set_globals', {
|
|
@@ -536,7 +571,7 @@ function generateWidgetContentHtml(widgetData) {
|
|
|
536
571
|
console.log("[Widget Content] Generated HTML length:", modifiedHtml.length);
|
|
537
572
|
return { html: modifiedHtml };
|
|
538
573
|
}
|
|
539
|
-
function getWidgetSecurityHeaders(widgetCSP) {
|
|
574
|
+
function getWidgetSecurityHeaders(widgetCSP, devServerBaseUrl) {
|
|
540
575
|
const trustedCdns = [
|
|
541
576
|
"https://persistent.oaistatic.com",
|
|
542
577
|
"https://*.oaistatic.com",
|
|
@@ -545,25 +580,48 @@ function getWidgetSecurityHeaders(widgetCSP) {
|
|
|
545
580
|
"https://cdnjs.cloudflare.com",
|
|
546
581
|
"https://cdn.skypack.dev"
|
|
547
582
|
];
|
|
548
|
-
const
|
|
583
|
+
const prodResourceDomains = [...trustedCdns];
|
|
549
584
|
if (widgetCSP?.resource_domains) {
|
|
550
|
-
|
|
585
|
+
prodResourceDomains.push(...widgetCSP.resource_domains);
|
|
586
|
+
}
|
|
587
|
+
const prodResourceDomainsStr = prodResourceDomains.join(" ");
|
|
588
|
+
let devServerOrigin = null;
|
|
589
|
+
const allResourceDomains = [...prodResourceDomains];
|
|
590
|
+
if (devServerBaseUrl) {
|
|
591
|
+
try {
|
|
592
|
+
devServerOrigin = new URL(devServerBaseUrl).origin;
|
|
593
|
+
allResourceDomains.push(devServerOrigin);
|
|
594
|
+
} catch (e) {
|
|
595
|
+
console.warn(`[CSP] Invalid devServerBaseUrl: ${devServerBaseUrl}`);
|
|
596
|
+
}
|
|
551
597
|
}
|
|
552
598
|
const resourceDomainsStr = allResourceDomains.join(" ");
|
|
599
|
+
let imgSrc = "'self' data: https: blob:";
|
|
600
|
+
if (devServerOrigin) {
|
|
601
|
+
imgSrc = `'self' data: https: blob: ${devServerOrigin}`;
|
|
602
|
+
}
|
|
603
|
+
let mediaSrc = "'self' data: https: blob:";
|
|
604
|
+
if (devServerOrigin) {
|
|
605
|
+
mediaSrc = `'self' data: https: blob: ${devServerOrigin}`;
|
|
606
|
+
}
|
|
607
|
+
let fontSrc = `'self' data: ${resourceDomainsStr}`;
|
|
608
|
+
if (devServerOrigin) {
|
|
609
|
+
fontSrc = `'self' data: https: http: ${resourceDomainsStr}`;
|
|
610
|
+
}
|
|
553
611
|
let connectSrc = "'self' https: wss: ws:";
|
|
554
612
|
if (widgetCSP?.connect_domains && widgetCSP.connect_domains.length > 0) {
|
|
555
613
|
connectSrc = `'self' ${widgetCSP.connect_domains.join(" ")} https: wss: ws:`;
|
|
556
614
|
}
|
|
557
|
-
|
|
615
|
+
const headers = {
|
|
558
616
|
"Content-Security-Policy": [
|
|
559
617
|
"default-src 'self'",
|
|
560
618
|
`script-src 'self' 'unsafe-inline' 'unsafe-eval' ${resourceDomainsStr}`,
|
|
561
619
|
"worker-src 'self' blob:",
|
|
562
620
|
"child-src 'self' blob:",
|
|
563
621
|
`style-src 'self' 'unsafe-inline' ${resourceDomainsStr}`,
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
`font-src
|
|
622
|
+
`img-src ${imgSrc}`,
|
|
623
|
+
`media-src ${mediaSrc}`,
|
|
624
|
+
`font-src ${fontSrc}`,
|
|
567
625
|
`connect-src ${connectSrc}`,
|
|
568
626
|
"frame-ancestors 'self'"
|
|
569
627
|
].join("; "),
|
|
@@ -573,6 +631,22 @@ function getWidgetSecurityHeaders(widgetCSP) {
|
|
|
573
631
|
Pragma: "no-cache",
|
|
574
632
|
Expires: "0"
|
|
575
633
|
};
|
|
634
|
+
if (devServerOrigin) {
|
|
635
|
+
const prodConnectSrc = "'self' https: wss: ws:";
|
|
636
|
+
headers["Content-Security-Policy-Report-Only"] = [
|
|
637
|
+
"default-src 'self'",
|
|
638
|
+
`script-src 'self' 'unsafe-inline' 'unsafe-eval' ${prodResourceDomainsStr}`,
|
|
639
|
+
"worker-src 'self' blob:",
|
|
640
|
+
"child-src 'self' blob:",
|
|
641
|
+
`style-src 'self' 'unsafe-inline' ${prodResourceDomainsStr}`,
|
|
642
|
+
"img-src 'self' data: https: blob:",
|
|
643
|
+
"media-src 'self' data: https: blob:",
|
|
644
|
+
`font-src 'self' data: ${prodResourceDomainsStr}`,
|
|
645
|
+
`connect-src ${prodConnectSrc}`,
|
|
646
|
+
"frame-ancestors 'self'"
|
|
647
|
+
].join("; ");
|
|
648
|
+
}
|
|
649
|
+
return headers;
|
|
576
650
|
}
|
|
577
651
|
|
|
578
652
|
export {
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__publicField
|
|
3
|
+
} from "./chunk-PKBMQBKP.js";
|
|
4
|
+
|
|
5
|
+
// src/server/rpc-log-bus.ts
|
|
6
|
+
var SimpleEventEmitter = class {
|
|
7
|
+
constructor() {
|
|
8
|
+
__publicField(this, "listeners", /* @__PURE__ */ new Map());
|
|
9
|
+
}
|
|
10
|
+
on(event, listener) {
|
|
11
|
+
if (!this.listeners.has(event)) {
|
|
12
|
+
this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
13
|
+
}
|
|
14
|
+
this.listeners.get(event).add(listener);
|
|
15
|
+
}
|
|
16
|
+
off(event, listener) {
|
|
17
|
+
this.listeners.get(event)?.delete(listener);
|
|
18
|
+
}
|
|
19
|
+
emit(event, ...args) {
|
|
20
|
+
this.listeners.get(event)?.forEach((listener) => {
|
|
21
|
+
try {
|
|
22
|
+
listener(...args);
|
|
23
|
+
} catch (e) {
|
|
24
|
+
console.error("Error in event listener:", e);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var RpcLogBus = class {
|
|
30
|
+
constructor() {
|
|
31
|
+
__publicField(this, "emitter", new SimpleEventEmitter());
|
|
32
|
+
__publicField(this, "bufferByServer", /* @__PURE__ */ new Map());
|
|
33
|
+
}
|
|
34
|
+
publish(event) {
|
|
35
|
+
const buffer = this.bufferByServer.get(event.serverId) ?? [];
|
|
36
|
+
buffer.push(event);
|
|
37
|
+
if (buffer.length > 1e3) {
|
|
38
|
+
buffer.shift();
|
|
39
|
+
}
|
|
40
|
+
this.bufferByServer.set(event.serverId, buffer);
|
|
41
|
+
this.emitter.emit("event", event);
|
|
42
|
+
}
|
|
43
|
+
subscribe(serverIds, listener) {
|
|
44
|
+
const filter = new Set(serverIds);
|
|
45
|
+
const handler = (event) => {
|
|
46
|
+
if (filter.size === 0 || filter.has(event.serverId)) listener(event);
|
|
47
|
+
};
|
|
48
|
+
this.emitter.on("event", handler);
|
|
49
|
+
return () => this.emitter.off("event", handler);
|
|
50
|
+
}
|
|
51
|
+
getBuffer(serverIds, limit) {
|
|
52
|
+
const filter = new Set(serverIds);
|
|
53
|
+
const all = [];
|
|
54
|
+
for (const [serverId, buf] of this.bufferByServer.entries()) {
|
|
55
|
+
if (filter.size > 0 && !filter.has(serverId)) continue;
|
|
56
|
+
all.push(...buf);
|
|
57
|
+
}
|
|
58
|
+
all.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
59
|
+
if (limit === 0) return [];
|
|
60
|
+
if (!Number.isFinite(limit) || limit < 0) return all;
|
|
61
|
+
return all.slice(0, limit);
|
|
62
|
+
}
|
|
63
|
+
clear(serverIds) {
|
|
64
|
+
if (serverIds && serverIds.length > 0) {
|
|
65
|
+
const filter = new Set(serverIds);
|
|
66
|
+
for (const serverId of filter) {
|
|
67
|
+
this.bufferByServer.delete(serverId);
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
this.bufferByServer.clear();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var rpcLogBus = new RpcLogBus();
|
|
75
|
+
|
|
76
|
+
export {
|
|
77
|
+
rpcLogBus
|
|
78
|
+
};
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
formatErrorResponse
|
|
3
3
|
} from "./chunk-JCLAFMDT.js";
|
|
4
|
+
import {
|
|
5
|
+
rpcLogBus
|
|
6
|
+
} from "./chunk-CVECQ7BJ.js";
|
|
4
7
|
import {
|
|
5
8
|
generateWidgetContainerHtml,
|
|
6
9
|
generateWidgetContentHtml,
|
|
@@ -9,7 +12,7 @@ import {
|
|
|
9
12
|
handleChatRequest,
|
|
10
13
|
handleChatRequestStream,
|
|
11
14
|
storeWidgetData
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-ZONLXYBO.js";
|
|
13
16
|
|
|
14
17
|
// src/server/shared-routes.ts
|
|
15
18
|
import { logger } from "hono/logger";
|
|
@@ -217,8 +220,10 @@ function registerInspectorRoutes(app, config) {
|
|
|
217
220
|
}
|
|
218
221
|
);
|
|
219
222
|
html = html.replace(
|
|
220
|
-
/(src|href)="\/mcp-use\/widgets
|
|
221
|
-
|
|
223
|
+
/(src|href)="(\/mcp-use\/widgets\/[^"]+)"/g,
|
|
224
|
+
(_match, attr, path) => {
|
|
225
|
+
return `${attr}="${widgetData.devServerBaseUrl}${path}"`;
|
|
226
|
+
}
|
|
222
227
|
);
|
|
223
228
|
html = html.replace(/(src|href)="\.\/([^"]+)"/g, (match, attr, path) => {
|
|
224
229
|
if (path.match(/\.(js|css|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/i)) {
|
|
@@ -226,14 +231,45 @@ function registerInspectorRoutes(app, config) {
|
|
|
226
231
|
}
|
|
227
232
|
return match;
|
|
228
233
|
});
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const
|
|
234
|
-
|
|
234
|
+
if (widgetData.devServerBaseUrl) {
|
|
235
|
+
const devServerUrl = new URL(widgetData.devServerBaseUrl);
|
|
236
|
+
const wsProtocol = devServerUrl.protocol === "https:" ? "wss" : "ws";
|
|
237
|
+
const wsHost = devServerUrl.host;
|
|
238
|
+
const directWsUrl = `${wsProtocol}://${wsHost}/mcp-use/widgets/`;
|
|
239
|
+
const baseTag = `<base href="${widgetData.devServerBaseUrl}/mcp-use/widgets/${widgetName}/">`;
|
|
240
|
+
const cspWarningScript = `
|
|
241
|
+
<script>
|
|
242
|
+
// Listen for CSP violations (from Report-Only policy)
|
|
243
|
+
document.addEventListener('securitypolicyviolation', (e) => {
|
|
244
|
+
// Only warn about report-only violations (not enforced ones)
|
|
245
|
+
if (e.disposition === 'report') {
|
|
246
|
+
console.warn(
|
|
247
|
+
'%c\u26A0\uFE0F CSP Warning: Resource would be blocked in production',
|
|
248
|
+
'color: orange; font-weight: bold',
|
|
249
|
+
'\\n Blocked URL:', e.blockedURI,
|
|
250
|
+
'\\n Directive:', e.violatedDirective,
|
|
251
|
+
'\\n Policy:', e.originalPolicy,
|
|
252
|
+
'\\n\\n\u2139\uFE0F To fix: Add this domain to your widget\\'s CSP configuration in appsSdkMetadata[\\'openai/widgetCSP\\']'
|
|
253
|
+
);
|
|
254
|
+
}
|
|
235
255
|
});
|
|
236
|
-
|
|
256
|
+
</script>`;
|
|
257
|
+
const viteConfigScript = `
|
|
258
|
+
<script>
|
|
259
|
+
// Configure Vite HMR to connect directly to dev server
|
|
260
|
+
window.__vite_ws_url__ = "${directWsUrl}";
|
|
261
|
+
</script>`;
|
|
262
|
+
html = html.replace(/<head>/i, `<head>
|
|
263
|
+
${baseTag}`);
|
|
264
|
+
html = html.replace(
|
|
265
|
+
/<script/,
|
|
266
|
+
cspWarningScript + viteConfigScript + "\n <script"
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
const headers = getWidgetSecurityHeaders(
|
|
270
|
+
widgetData.widgetCSP,
|
|
271
|
+
widgetData.devServerBaseUrl
|
|
272
|
+
);
|
|
237
273
|
Object.entries(headers).forEach(([key, value]) => {
|
|
238
274
|
c.header(key, value);
|
|
239
275
|
});
|
|
@@ -340,6 +376,93 @@ function registerInspectorRoutes(app, config) {
|
|
|
340
376
|
return c.json({ success: false });
|
|
341
377
|
}
|
|
342
378
|
});
|
|
379
|
+
app.post("/inspector/api/rpc/log", async (c) => {
|
|
380
|
+
try {
|
|
381
|
+
const event = await c.req.json();
|
|
382
|
+
rpcLogBus.publish(event);
|
|
383
|
+
return c.json({ success: true });
|
|
384
|
+
} catch (error) {
|
|
385
|
+
console.error("[RPC Log] Error receiving RPC event:", error);
|
|
386
|
+
return c.json({ success: false });
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
app.delete("/inspector/api/rpc/log", async (c) => {
|
|
390
|
+
try {
|
|
391
|
+
const url = new URL(c.req.url);
|
|
392
|
+
const serverIdsParam = url.searchParams.get("serverIds");
|
|
393
|
+
const serverIds = serverIdsParam ? serverIdsParam.split(",").filter(Boolean) : void 0;
|
|
394
|
+
rpcLogBus.clear(serverIds);
|
|
395
|
+
return c.json({ success: true });
|
|
396
|
+
} catch (error) {
|
|
397
|
+
console.error("[RPC Log] Error clearing RPC log:", error);
|
|
398
|
+
return c.json({ success: false });
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
app.get("/inspector/api/rpc/stream", async (c) => {
|
|
402
|
+
const url = new URL(c.req.url);
|
|
403
|
+
const replay = parseInt(url.searchParams.get("replay") || "3", 10);
|
|
404
|
+
const serverIdsParam = url.searchParams.get("serverIds");
|
|
405
|
+
const serverIds = serverIdsParam ? serverIdsParam.split(",").filter(Boolean) : [];
|
|
406
|
+
const encoder = new TextEncoder();
|
|
407
|
+
const stream = new ReadableStream({
|
|
408
|
+
start(controller) {
|
|
409
|
+
const send = (data) => {
|
|
410
|
+
try {
|
|
411
|
+
controller.enqueue(
|
|
412
|
+
encoder.encode(`data: ${JSON.stringify(data)}
|
|
413
|
+
|
|
414
|
+
`)
|
|
415
|
+
);
|
|
416
|
+
} catch {
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
try {
|
|
420
|
+
const recent = rpcLogBus.getBuffer(
|
|
421
|
+
serverIds,
|
|
422
|
+
isNaN(replay) ? 3 : replay
|
|
423
|
+
);
|
|
424
|
+
for (const evt of recent) {
|
|
425
|
+
send({ type: "rpc", ...evt });
|
|
426
|
+
}
|
|
427
|
+
} catch {
|
|
428
|
+
}
|
|
429
|
+
const unsubscribe = rpcLogBus.subscribe(
|
|
430
|
+
serverIds,
|
|
431
|
+
(evt) => {
|
|
432
|
+
send({ type: "rpc", ...evt });
|
|
433
|
+
}
|
|
434
|
+
);
|
|
435
|
+
const keepalive = setInterval(() => {
|
|
436
|
+
try {
|
|
437
|
+
controller.enqueue(encoder.encode(`: keepalive ${Date.now()}
|
|
438
|
+
|
|
439
|
+
`));
|
|
440
|
+
} catch {
|
|
441
|
+
}
|
|
442
|
+
}, 15e3);
|
|
443
|
+
c.req.raw.signal?.addEventListener("abort", () => {
|
|
444
|
+
try {
|
|
445
|
+
clearInterval(keepalive);
|
|
446
|
+
unsubscribe();
|
|
447
|
+
} catch {
|
|
448
|
+
}
|
|
449
|
+
try {
|
|
450
|
+
controller.close();
|
|
451
|
+
} catch {
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
return new Response(stream, {
|
|
457
|
+
headers: {
|
|
458
|
+
"Content-Type": "text/event-stream",
|
|
459
|
+
"Cache-Control": "no-cache",
|
|
460
|
+
Connection: "keep-alive",
|
|
461
|
+
"Access-Control-Allow-Origin": "*",
|
|
462
|
+
"Access-Control-Expose-Headers": "*"
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
});
|
|
343
466
|
}
|
|
344
467
|
|
|
345
468
|
export {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
__publicField
|
|
7
|
+
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
registerInspectorRoutes
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FS77NTZN.js";
|
|
4
4
|
import {
|
|
5
5
|
registerStaticRoutes
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-RRPLH7DL.js";
|
|
7
7
|
import {
|
|
8
8
|
checkClientFiles,
|
|
9
9
|
getClientDistPath
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3T2VCYG6.js";
|
|
11
11
|
|
|
12
12
|
// src/server/middleware.ts
|
|
13
13
|
import { Hono } from "hono";
|
|
@@ -312,7 +312,16 @@ function generateWidgetContainerHtml(basePath, toolId) {
|
|
|
312
312
|
`;
|
|
313
313
|
}
|
|
314
314
|
function generateWidgetContentHtml(widgetData) {
|
|
315
|
-
const {
|
|
315
|
+
const {
|
|
316
|
+
serverId,
|
|
317
|
+
uri,
|
|
318
|
+
toolInput,
|
|
319
|
+
toolOutput,
|
|
320
|
+
resourceData,
|
|
321
|
+
toolId,
|
|
322
|
+
devServerBaseUrl,
|
|
323
|
+
theme
|
|
324
|
+
} = widgetData;
|
|
316
325
|
console.log("[Widget Content] Using pre-fetched resource for:", {
|
|
317
326
|
serverId,
|
|
318
327
|
uri
|
|
@@ -343,23 +352,31 @@ function generateWidgetContentHtml(widgetData) {
|
|
|
343
352
|
const safeToolOutput = JSON.stringify(toolOutput ?? null).replace(/</g, "\\u003c").replace(/>/g, "\\u003e");
|
|
344
353
|
const safeToolId = JSON.stringify(toolId);
|
|
345
354
|
const safeWidgetStateKey = JSON.stringify(widgetStateKey);
|
|
355
|
+
const safeTheme = JSON.stringify(theme === "dark" ? "dark" : "light");
|
|
346
356
|
const apiScript = `
|
|
347
357
|
<script>
|
|
348
358
|
(function() {
|
|
349
359
|
'use strict';
|
|
350
360
|
|
|
351
361
|
// Change URL to "/" for React Router compatibility
|
|
352
|
-
if
|
|
362
|
+
// Skip if running in Inspector dev-widget proxy to prevent redirecting iframe to Inspector home
|
|
363
|
+
if (window.location.pathname !== '/' && !window.location.pathname.includes('/dev-widget/')) {
|
|
353
364
|
history.replaceState(null, '', '/');
|
|
354
365
|
}
|
|
355
366
|
|
|
367
|
+
// Inject MCP widget utilities for Image component and file access
|
|
368
|
+
window.__mcpPublicUrl = ${devServerBaseUrl ? `"${devServerBaseUrl}/mcp-use/public"` : '""'};
|
|
369
|
+
window.__getFile = function(filename) {
|
|
370
|
+
return ${devServerBaseUrl ? `"${devServerBaseUrl}/mcp-use/widgets/"` : '""'} + filename;
|
|
371
|
+
};
|
|
372
|
+
|
|
356
373
|
const openaiAPI = {
|
|
357
374
|
toolInput: ${safeToolInput},
|
|
358
375
|
toolOutput: ${safeToolOutput},
|
|
359
376
|
toolResponseMetadata: null,
|
|
360
377
|
displayMode: 'inline',
|
|
361
378
|
maxHeight: 600,
|
|
362
|
-
theme:
|
|
379
|
+
theme: ${safeTheme},
|
|
363
380
|
locale: 'en-US',
|
|
364
381
|
safeArea: { insets: { top: 0, bottom: 0, left: 0, right: 0 } },
|
|
365
382
|
userAgent: {},
|
|
@@ -432,6 +449,20 @@ function generateWidgetContentHtml(widgetData) {
|
|
|
432
449
|
return this.sendFollowupTurn(prompt);
|
|
433
450
|
},
|
|
434
451
|
|
|
452
|
+
async notifyIntrinsicHeight(height) {
|
|
453
|
+
console.log('[OpenAI Widget] notifyIntrinsicHeight called with:', height);
|
|
454
|
+
if (typeof height !== 'number' || height < 0) {
|
|
455
|
+
console.error('[OpenAI Widget] Invalid height value:', height);
|
|
456
|
+
throw new Error('Height must be a non-negative number');
|
|
457
|
+
}
|
|
458
|
+
const message = {
|
|
459
|
+
type: 'openai:notifyIntrinsicHeight',
|
|
460
|
+
height
|
|
461
|
+
};
|
|
462
|
+
console.log('[OpenAI Widget] Sending postMessage to parent:', message);
|
|
463
|
+
window.parent.postMessage(message, '*');
|
|
464
|
+
},
|
|
465
|
+
|
|
435
466
|
openExternal(payload) {
|
|
436
467
|
const href = typeof payload === 'string' ? payload : payload?.href;
|
|
437
468
|
if (href) {
|
|
@@ -476,6 +507,18 @@ function generateWidgetContentHtml(widgetData) {
|
|
|
476
507
|
} catch (err) {}
|
|
477
508
|
}, 0);
|
|
478
509
|
|
|
510
|
+
// Listen for widget state requests from inspector
|
|
511
|
+
window.addEventListener('message', (event) => {
|
|
512
|
+
if (event.data?.type === 'mcp-inspector:getWidgetState') {
|
|
513
|
+
window.parent.postMessage({
|
|
514
|
+
type: 'mcp-inspector:widgetStateResponse',
|
|
515
|
+
toolId: event.data.toolId,
|
|
516
|
+
state: openaiAPI.widgetState
|
|
517
|
+
}, '*');
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
|
|
479
522
|
// Listen for globals changes from parent (for displayMode, theme, etc.)
|
|
480
523
|
window.addEventListener('message', (event) => {
|
|
481
524
|
// Handle new general globalsChanged message
|
|
@@ -602,7 +645,7 @@ function generateWidgetContentHtml(widgetData) {
|
|
|
602
645
|
console.log("[Widget Content] Generated HTML length:", modifiedHtml.length);
|
|
603
646
|
return { html: modifiedHtml };
|
|
604
647
|
}
|
|
605
|
-
function getWidgetSecurityHeaders(widgetCSP) {
|
|
648
|
+
function getWidgetSecurityHeaders(widgetCSP, devServerBaseUrl) {
|
|
606
649
|
const trustedCdns = [
|
|
607
650
|
"https://persistent.oaistatic.com",
|
|
608
651
|
"https://*.oaistatic.com",
|
|
@@ -611,25 +654,48 @@ function getWidgetSecurityHeaders(widgetCSP) {
|
|
|
611
654
|
"https://cdnjs.cloudflare.com",
|
|
612
655
|
"https://cdn.skypack.dev"
|
|
613
656
|
];
|
|
614
|
-
const
|
|
657
|
+
const prodResourceDomains = [...trustedCdns];
|
|
615
658
|
if (widgetCSP?.resource_domains) {
|
|
616
|
-
|
|
659
|
+
prodResourceDomains.push(...widgetCSP.resource_domains);
|
|
660
|
+
}
|
|
661
|
+
const prodResourceDomainsStr = prodResourceDomains.join(" ");
|
|
662
|
+
let devServerOrigin = null;
|
|
663
|
+
const allResourceDomains = [...prodResourceDomains];
|
|
664
|
+
if (devServerBaseUrl) {
|
|
665
|
+
try {
|
|
666
|
+
devServerOrigin = new URL(devServerBaseUrl).origin;
|
|
667
|
+
allResourceDomains.push(devServerOrigin);
|
|
668
|
+
} catch (e) {
|
|
669
|
+
console.warn(`[CSP] Invalid devServerBaseUrl: ${devServerBaseUrl}`);
|
|
670
|
+
}
|
|
617
671
|
}
|
|
618
672
|
const resourceDomainsStr = allResourceDomains.join(" ");
|
|
673
|
+
let imgSrc = "'self' data: https: blob:";
|
|
674
|
+
if (devServerOrigin) {
|
|
675
|
+
imgSrc = `'self' data: https: blob: ${devServerOrigin}`;
|
|
676
|
+
}
|
|
677
|
+
let mediaSrc = "'self' data: https: blob:";
|
|
678
|
+
if (devServerOrigin) {
|
|
679
|
+
mediaSrc = `'self' data: https: blob: ${devServerOrigin}`;
|
|
680
|
+
}
|
|
681
|
+
let fontSrc = `'self' data: ${resourceDomainsStr}`;
|
|
682
|
+
if (devServerOrigin) {
|
|
683
|
+
fontSrc = `'self' data: https: http: ${resourceDomainsStr}`;
|
|
684
|
+
}
|
|
619
685
|
let connectSrc = "'self' https: wss: ws:";
|
|
620
686
|
if (widgetCSP?.connect_domains && widgetCSP.connect_domains.length > 0) {
|
|
621
687
|
connectSrc = `'self' ${widgetCSP.connect_domains.join(" ")} https: wss: ws:`;
|
|
622
688
|
}
|
|
623
|
-
|
|
689
|
+
const headers = {
|
|
624
690
|
"Content-Security-Policy": [
|
|
625
691
|
"default-src 'self'",
|
|
626
692
|
`script-src 'self' 'unsafe-inline' 'unsafe-eval' ${resourceDomainsStr}`,
|
|
627
693
|
"worker-src 'self' blob:",
|
|
628
694
|
"child-src 'self' blob:",
|
|
629
695
|
`style-src 'self' 'unsafe-inline' ${resourceDomainsStr}`,
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
`font-src
|
|
696
|
+
`img-src ${imgSrc}`,
|
|
697
|
+
`media-src ${mediaSrc}`,
|
|
698
|
+
`font-src ${fontSrc}`,
|
|
633
699
|
`connect-src ${connectSrc}`,
|
|
634
700
|
"frame-ancestors 'self'"
|
|
635
701
|
].join("; "),
|
|
@@ -639,6 +705,22 @@ function getWidgetSecurityHeaders(widgetCSP) {
|
|
|
639
705
|
Pragma: "no-cache",
|
|
640
706
|
Expires: "0"
|
|
641
707
|
};
|
|
708
|
+
if (devServerOrigin) {
|
|
709
|
+
const prodConnectSrc = "'self' https: wss: ws:";
|
|
710
|
+
headers["Content-Security-Policy-Report-Only"] = [
|
|
711
|
+
"default-src 'self'",
|
|
712
|
+
`script-src 'self' 'unsafe-inline' 'unsafe-eval' ${prodResourceDomainsStr}`,
|
|
713
|
+
"worker-src 'self' blob:",
|
|
714
|
+
"child-src 'self' blob:",
|
|
715
|
+
`style-src 'self' 'unsafe-inline' ${prodResourceDomainsStr}`,
|
|
716
|
+
"img-src 'self' data: https: blob:",
|
|
717
|
+
"media-src 'self' data: https: blob:",
|
|
718
|
+
`font-src 'self' data: ${prodResourceDomainsStr}`,
|
|
719
|
+
`connect-src ${prodConnectSrc}`,
|
|
720
|
+
"frame-ancestors 'self'"
|
|
721
|
+
].join("; ");
|
|
722
|
+
}
|
|
723
|
+
return headers;
|
|
642
724
|
}
|
|
643
725
|
|
|
644
726
|
export {
|