@mcp-ts/sdk 1.3.9 → 1.4.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/README.md +0 -1
- package/dist/adapters/langchain-adapter.js.map +1 -1
- package/dist/adapters/langchain-adapter.mjs.map +1 -1
- package/dist/client/index.d.mts +3 -189
- package/dist/client/index.d.ts +3 -189
- package/dist/client/index.js +218 -54
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +215 -55
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/react.d.mts +29 -40
- package/dist/client/react.d.ts +29 -40
- package/dist/client/react.js +492 -147
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +490 -149
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.d.mts +3 -2
- package/dist/client/vue.d.ts +3 -2
- package/dist/client/vue.js +239 -63
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +236 -64
- package/dist/client/vue.mjs.map +1 -1
- package/dist/index-CQr9q0bF.d.mts +295 -0
- package/dist/index-nE_7Io0I.d.ts +295 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +315 -64
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +303 -65
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.js +93 -10
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +88 -10
- package/dist/server/index.mjs.map +1 -1
- package/package.json +13 -11
- package/src/adapters/langchain-adapter.ts +1 -1
- package/src/client/core/app-host.ts +252 -65
- package/src/client/core/constants.ts +30 -0
- package/src/client/index.ts +6 -1
- package/src/client/react/index.ts +6 -1
- package/src/client/react/use-app-host.ts +13 -19
- package/src/client/react/use-mcp-apps.tsx +297 -125
- package/src/client/react/use-mcp.ts +75 -36
- package/src/client/utils/app-host-utils.ts +62 -0
- package/src/client/vue/use-mcp.ts +23 -12
- package/src/server/mcp/oauth-client.ts +31 -8
- package/src/server/storage/crypto.ts +92 -0
- package/src/server/storage/supabase-backend.ts +7 -6
package/dist/client/react.js
CHANGED
|
@@ -277,6 +277,7 @@ function useMcp(options) {
|
|
|
277
277
|
"disconnected"
|
|
278
278
|
);
|
|
279
279
|
const [isInitializing, setIsInitializing] = react.useState(false);
|
|
280
|
+
const [sseClient, setSseClient] = react.useState(null);
|
|
280
281
|
react.useEffect(() => {
|
|
281
282
|
isMountedRef.current = true;
|
|
282
283
|
const clientOptions = {
|
|
@@ -299,6 +300,7 @@ function useMcp(options) {
|
|
|
299
300
|
};
|
|
300
301
|
const client = new SSEClient(clientOptions);
|
|
301
302
|
clientRef.current = client;
|
|
303
|
+
setSseClient(client);
|
|
302
304
|
if (autoConnect) {
|
|
303
305
|
client.connect();
|
|
304
306
|
if (autoInitialize) {
|
|
@@ -354,18 +356,28 @@ function useMcp(options) {
|
|
|
354
356
|
);
|
|
355
357
|
}
|
|
356
358
|
case "auth_required": {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
359
|
+
const url2 = (event.authUrl || "").trim();
|
|
360
|
+
if (!url2) {
|
|
361
|
+
onLog?.("error", "OAuth required but authorization URL is missing", { sessionId: event.sessionId });
|
|
362
|
+
return prev.map(
|
|
363
|
+
(c) => c.sessionId === event.sessionId ? {
|
|
364
|
+
...c,
|
|
365
|
+
state: "FAILED",
|
|
366
|
+
error: "OAuth authorization URL not available",
|
|
367
|
+
authUrl: void 0
|
|
368
|
+
} : c
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
onLog?.("info", `OAuth required - redirecting to ${url2}`, { authUrl: url2 });
|
|
372
|
+
if (!suppressAuthRedirectSessionsRef.current.has(event.sessionId)) {
|
|
373
|
+
if (onRedirect) {
|
|
374
|
+
onRedirect(url2);
|
|
375
|
+
} else if (typeof window !== "undefined") {
|
|
376
|
+
window.location.href = url2;
|
|
365
377
|
}
|
|
366
378
|
}
|
|
367
379
|
return prev.map(
|
|
368
|
-
(c) => c.sessionId === event.sessionId ? { ...c, state: "AUTHENTICATING", authUrl:
|
|
380
|
+
(c) => c.sessionId === event.sessionId ? { ...c, state: "AUTHENTICATING", authUrl: url2 } : c
|
|
369
381
|
);
|
|
370
382
|
}
|
|
371
383
|
case "error": {
|
|
@@ -532,46 +544,137 @@ function useMcp(options) {
|
|
|
532
544
|
},
|
|
533
545
|
[getConnection]
|
|
534
546
|
);
|
|
535
|
-
return
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
547
|
+
return react.useMemo(
|
|
548
|
+
() => ({
|
|
549
|
+
connections,
|
|
550
|
+
status,
|
|
551
|
+
isInitializing,
|
|
552
|
+
connect,
|
|
553
|
+
disconnect,
|
|
554
|
+
getConnection,
|
|
555
|
+
getConnectionByServerId,
|
|
556
|
+
isServerConnected,
|
|
557
|
+
getTools,
|
|
558
|
+
refresh,
|
|
559
|
+
connectSSE,
|
|
560
|
+
disconnectSSE,
|
|
561
|
+
finishAuth,
|
|
562
|
+
resumeAuth,
|
|
563
|
+
callTool,
|
|
564
|
+
listTools,
|
|
565
|
+
listPrompts,
|
|
566
|
+
getPrompt,
|
|
567
|
+
listResources,
|
|
568
|
+
readResource,
|
|
569
|
+
sseClient
|
|
570
|
+
}),
|
|
571
|
+
[
|
|
572
|
+
connections,
|
|
573
|
+
status,
|
|
574
|
+
isInitializing,
|
|
575
|
+
connect,
|
|
576
|
+
disconnect,
|
|
577
|
+
getConnection,
|
|
578
|
+
getConnectionByServerId,
|
|
579
|
+
isServerConnected,
|
|
580
|
+
getTools,
|
|
581
|
+
refresh,
|
|
582
|
+
connectSSE,
|
|
583
|
+
disconnectSSE,
|
|
584
|
+
finishAuth,
|
|
585
|
+
resumeAuth,
|
|
586
|
+
callTool,
|
|
587
|
+
listTools,
|
|
588
|
+
listPrompts,
|
|
589
|
+
getPrompt,
|
|
590
|
+
listResources,
|
|
591
|
+
readResource,
|
|
592
|
+
sseClient
|
|
593
|
+
]
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// src/client/core/constants.ts
|
|
598
|
+
var SANDBOX_PROXY_READY_METHOD = "ui/notifications/sandbox-proxy-ready";
|
|
599
|
+
var SANDBOX_RESOURCE_READY_METHOD = "ui/notifications/sandbox-resource-ready";
|
|
600
|
+
var APP_HOST_DEFAULTS = {
|
|
601
|
+
/** Default timeout for waiting for the sandbox proxy to be ready (ms). */
|
|
602
|
+
SANDBOX_TIMEOUT_MS: 1e4,
|
|
603
|
+
/** Default host info reported to guest apps. */
|
|
604
|
+
HOST_INFO: { name: "mcp-ts-host", version: "1.0.0" },
|
|
605
|
+
/** Supported MCP App URI schemes. */
|
|
606
|
+
URI_SCHEMES: ["ui://", "mcp-app://"],
|
|
607
|
+
/** Default theme for the host context. */
|
|
608
|
+
THEME: "dark",
|
|
609
|
+
/** Default platform for the host context. */
|
|
610
|
+
PLATFORM: "web",
|
|
611
|
+
/** Default max height for the iframe container (px). */
|
|
612
|
+
MAX_HEIGHT: 6e3
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
// src/client/utils/app-host-utils.ts
|
|
616
|
+
var DEFAULT_SANDBOX_TIMEOUT_MS = APP_HOST_DEFAULTS.SANDBOX_TIMEOUT_MS;
|
|
617
|
+
async function setupSandboxProxyIframe(iframe, sandboxProxyUrl) {
|
|
618
|
+
iframe.style.width = "100%";
|
|
619
|
+
iframe.style.height = "100%";
|
|
620
|
+
iframe.style.border = "none";
|
|
621
|
+
iframe.style.backgroundColor = "transparent";
|
|
622
|
+
iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-downloads");
|
|
623
|
+
const onReady = new Promise((resolve, reject) => {
|
|
624
|
+
let settled = false;
|
|
625
|
+
const cleanup = () => {
|
|
626
|
+
window.removeEventListener("message", messageListener);
|
|
627
|
+
iframe.removeEventListener("error", errorListener);
|
|
628
|
+
};
|
|
629
|
+
const timeoutId = setTimeout(() => {
|
|
630
|
+
if (!settled) {
|
|
631
|
+
settled = true;
|
|
632
|
+
cleanup();
|
|
633
|
+
reject(new Error("Timed out waiting for sandbox proxy iframe to be ready"));
|
|
634
|
+
}
|
|
635
|
+
}, DEFAULT_SANDBOX_TIMEOUT_MS);
|
|
636
|
+
const messageListener = (event) => {
|
|
637
|
+
if (event.source === iframe.contentWindow) {
|
|
638
|
+
if (event.data?.method === SANDBOX_PROXY_READY_METHOD) {
|
|
639
|
+
if (!settled) {
|
|
640
|
+
settled = true;
|
|
641
|
+
clearTimeout(timeoutId);
|
|
642
|
+
cleanup();
|
|
643
|
+
resolve();
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
const errorListener = () => {
|
|
649
|
+
if (!settled) {
|
|
650
|
+
settled = true;
|
|
651
|
+
clearTimeout(timeoutId);
|
|
652
|
+
cleanup();
|
|
653
|
+
reject(new Error("Failed to load sandbox proxy iframe"));
|
|
654
|
+
}
|
|
655
|
+
};
|
|
656
|
+
window.addEventListener("message", messageListener);
|
|
657
|
+
iframe.addEventListener("error", errorListener);
|
|
658
|
+
});
|
|
659
|
+
iframe.src = sandboxProxyUrl.href;
|
|
660
|
+
return { onReady };
|
|
558
661
|
}
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
"
|
|
564
|
-
|
|
565
|
-
"
|
|
566
|
-
|
|
567
|
-
"
|
|
568
|
-
|
|
569
|
-
"
|
|
570
|
-
|
|
571
|
-
"
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
var MCP_URI_SCHEMES =
|
|
662
|
+
|
|
663
|
+
// src/client/core/app-host.ts
|
|
664
|
+
var DEFAULT_MCP_APP_CSP = {
|
|
665
|
+
"default-src": "'self'",
|
|
666
|
+
"script-src": "'self' 'unsafe-inline' 'unsafe-eval' https: blob:",
|
|
667
|
+
"style-src": "'self' 'unsafe-inline' https:",
|
|
668
|
+
"connect-src": "'self' https: wss:",
|
|
669
|
+
"img-src": "'self' data: https: blob:",
|
|
670
|
+
"font-src": "'self' data: https:",
|
|
671
|
+
"media-src": "'self' https: blob:",
|
|
672
|
+
"frame-src": "'none'",
|
|
673
|
+
"object-src": "'none'",
|
|
674
|
+
"base-uri": "'self'"
|
|
675
|
+
};
|
|
676
|
+
var HOST_INFO = APP_HOST_DEFAULTS.HOST_INFO;
|
|
677
|
+
var MCP_URI_SCHEMES = APP_HOST_DEFAULTS.URI_SCHEMES;
|
|
575
678
|
var AppHost = class {
|
|
576
679
|
constructor(client, iframe, options) {
|
|
577
680
|
this.client = client;
|
|
@@ -580,10 +683,12 @@ var AppHost = class {
|
|
|
580
683
|
__publicField(this, "sessionId");
|
|
581
684
|
__publicField(this, "resourceCache", /* @__PURE__ */ new Map());
|
|
582
685
|
__publicField(this, "debug");
|
|
583
|
-
|
|
686
|
+
__publicField(this, "sandboxConfig");
|
|
687
|
+
__publicField(this, "options");
|
|
584
688
|
__publicField(this, "onAppMessage");
|
|
585
|
-
this.
|
|
586
|
-
this.
|
|
689
|
+
this.options = options || {};
|
|
690
|
+
this.debug = this.options.debug ?? false;
|
|
691
|
+
this.sandboxConfig = this.options.sandbox;
|
|
587
692
|
this.bridge = this.initializeBridge();
|
|
588
693
|
}
|
|
589
694
|
// ============================================
|
|
@@ -610,19 +715,35 @@ var AppHost = class {
|
|
|
610
715
|
}
|
|
611
716
|
}
|
|
612
717
|
/**
|
|
613
|
-
* Launch an MCP App from a URL
|
|
718
|
+
* Launch an MCP App from a URL, MCP resource URI, or RAW HTML.
|
|
614
719
|
* Loads the HTML first, then establishes bridge connection.
|
|
615
720
|
*/
|
|
616
|
-
async launch(
|
|
721
|
+
async launch(source, sessionId) {
|
|
617
722
|
if (sessionId) this.sessionId = sessionId;
|
|
618
723
|
const initializedPromise = this.onAppReady();
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
724
|
+
let htmlToRender = source.html;
|
|
725
|
+
if (!htmlToRender && source.uri) {
|
|
726
|
+
if (this.isMcpUri(source.uri)) {
|
|
727
|
+
htmlToRender = await this.readMcpAppHtml(source.uri);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
if (!htmlToRender && source.uri && !this.isMcpUri(source.uri)) {
|
|
731
|
+
this.iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-downloads");
|
|
732
|
+
this.iframe.src = source.uri;
|
|
733
|
+
await this.onIframeReady();
|
|
734
|
+
await this.connectBridge();
|
|
735
|
+
} else if (htmlToRender) {
|
|
736
|
+
if (!this.sandboxConfig) {
|
|
737
|
+
throw new Error("Sandbox configuration requires a proxy URL to render HTML safely.");
|
|
738
|
+
}
|
|
739
|
+
await this.launchSandboxedHtml(htmlToRender, this.sandboxConfig);
|
|
740
|
+
await this.connectBridge();
|
|
741
|
+
this.log("Sending HTML resource to sandbox proxy (MCP Apps notification)");
|
|
742
|
+
await this.bridge.sendSandboxResourceReady({
|
|
743
|
+
html: htmlToRender,
|
|
744
|
+
csp: this.sandboxConfig.csp
|
|
745
|
+
});
|
|
623
746
|
}
|
|
624
|
-
await this.onIframeReady();
|
|
625
|
-
await this.connectBridge();
|
|
626
747
|
this.log("Waiting for app initialization");
|
|
627
748
|
await Promise.race([
|
|
628
749
|
initializedPromise,
|
|
@@ -633,6 +754,19 @@ var AppHost = class {
|
|
|
633
754
|
]);
|
|
634
755
|
this.log("App launched and ready");
|
|
635
756
|
}
|
|
757
|
+
// Set host context manually
|
|
758
|
+
setHostContext(context) {
|
|
759
|
+
this.options.hostContext = context;
|
|
760
|
+
if (this.bridge) {
|
|
761
|
+
this.bridge.setHostContext(context);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
// Send streaming inputs manually
|
|
765
|
+
sendToolInputPartial(params) {
|
|
766
|
+
if (this.bridge) {
|
|
767
|
+
this.bridge.sendToolInputPartial(params);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
636
770
|
/**
|
|
637
771
|
* Wait for app to signal initialization complete
|
|
638
772
|
*/
|
|
@@ -683,14 +817,17 @@ var AppHost = class {
|
|
|
683
817
|
this.log("Sending tool cancellation to app");
|
|
684
818
|
this.bridge.sendToolCancelled({ reason });
|
|
685
819
|
}
|
|
820
|
+
/**
|
|
821
|
+
* Tell the guest UI the resource is being torn down (unload / cleanup).
|
|
822
|
+
* Forwards to {@link AppBridge.teardownResource} on `@modelcontextprotocol/ext-apps/app-bridge`.
|
|
823
|
+
*/
|
|
824
|
+
teardownResource(params = {}) {
|
|
825
|
+
this.log("Sending resource teardown to app");
|
|
826
|
+
this.bridge.teardownResource(params);
|
|
827
|
+
}
|
|
686
828
|
// ============================================
|
|
687
829
|
// Private: Initialization
|
|
688
830
|
// ============================================
|
|
689
|
-
configureSandbox() {
|
|
690
|
-
if (this.iframe.sandbox.value !== SANDBOX_PERMISSIONS) {
|
|
691
|
-
this.iframe.sandbox.value = SANDBOX_PERMISSIONS;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
831
|
initializeBridge() {
|
|
695
832
|
const bridge = new appBridge.AppBridge(
|
|
696
833
|
null,
|
|
@@ -699,12 +836,10 @@ var AppHost = class {
|
|
|
699
836
|
openLinks: {},
|
|
700
837
|
serverTools: {},
|
|
701
838
|
logging: {},
|
|
702
|
-
// Declare support for model context updates
|
|
703
839
|
updateModelContext: { text: {} }
|
|
704
840
|
},
|
|
705
841
|
{
|
|
706
|
-
|
|
707
|
-
hostContext: {
|
|
842
|
+
hostContext: this.options.hostContext || {
|
|
708
843
|
theme: "dark",
|
|
709
844
|
platform: "web",
|
|
710
845
|
containerDimensions: { maxHeight: 6e3 },
|
|
@@ -713,19 +848,56 @@ var AppHost = class {
|
|
|
713
848
|
}
|
|
714
849
|
}
|
|
715
850
|
);
|
|
851
|
+
bridge.fallbackRequestHandler = this.options.onFallbackRequest;
|
|
716
852
|
bridge.oncalltool = (params) => this.handleToolCall(params);
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
853
|
+
if (this.options.onReadResource) {
|
|
854
|
+
bridge.onreadresource = async (params) => {
|
|
855
|
+
const resp = await this.options.onReadResource(params.uri);
|
|
856
|
+
return {
|
|
857
|
+
contents: resp.contents.map((c) => ({
|
|
858
|
+
uri: params.uri,
|
|
859
|
+
text: c.text,
|
|
860
|
+
blob: c.blob
|
|
861
|
+
}))
|
|
862
|
+
};
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
bridge.onopenlink = async (params, extra) => {
|
|
866
|
+
if (this.options.onOpenLink) {
|
|
867
|
+
return await this.options.onOpenLink(params, extra);
|
|
868
|
+
}
|
|
869
|
+
return this.handleOpenLink(params);
|
|
870
|
+
};
|
|
871
|
+
bridge.onmessage = async (params, extra) => {
|
|
872
|
+
if (this.options.onMessage) {
|
|
873
|
+
return await this.options.onMessage(params, extra);
|
|
874
|
+
}
|
|
875
|
+
return this.handleMessage(params);
|
|
876
|
+
};
|
|
877
|
+
bridge.onloggingmessage = (params) => {
|
|
878
|
+
this.log(`App log [${params.level}]: ${params.data}`);
|
|
879
|
+
if (this.options.onLoggingMessage) {
|
|
880
|
+
this.options.onLoggingMessage(params);
|
|
881
|
+
}
|
|
882
|
+
};
|
|
720
883
|
bridge.onupdatemodelcontext = async () => ({});
|
|
721
|
-
bridge.onsizechange = async (
|
|
722
|
-
|
|
723
|
-
if (
|
|
884
|
+
bridge.onsizechange = async (params) => {
|
|
885
|
+
const { width, height } = params;
|
|
886
|
+
if (height !== void 0 && height > 0) {
|
|
887
|
+
this.iframe.style.height = `${height}px`;
|
|
888
|
+
}
|
|
889
|
+
if (width !== void 0 && width > 0) this.iframe.style.minWidth = `min(${width}px, 100%)`;
|
|
890
|
+
if (this.options.onSizeChanged) {
|
|
891
|
+
this.options.onSizeChanged(params);
|
|
892
|
+
}
|
|
724
893
|
return {};
|
|
725
894
|
};
|
|
726
|
-
bridge.onrequestdisplaymode = async (params) =>
|
|
727
|
-
|
|
728
|
-
|
|
895
|
+
bridge.onrequestdisplaymode = async (params, extra) => {
|
|
896
|
+
if (this.options.onRequestDisplayMode) {
|
|
897
|
+
return await this.options.onRequestDisplayMode(params, extra);
|
|
898
|
+
}
|
|
899
|
+
return { mode: params.mode === "fullscreen" ? "fullscreen" : "inline" };
|
|
900
|
+
};
|
|
729
901
|
return bridge;
|
|
730
902
|
}
|
|
731
903
|
async connectBridge() {
|
|
@@ -739,6 +911,9 @@ var AppHost = class {
|
|
|
739
911
|
this.log("Bridge connected successfully");
|
|
740
912
|
} catch (error) {
|
|
741
913
|
this.log("Bridge connection failed", "error");
|
|
914
|
+
if (this.options.onError) {
|
|
915
|
+
this.options.onError(error instanceof Error ? error : new Error(String(error)));
|
|
916
|
+
}
|
|
742
917
|
throw error;
|
|
743
918
|
}
|
|
744
919
|
}
|
|
@@ -746,8 +921,11 @@ var AppHost = class {
|
|
|
746
921
|
// Private: Bridge Event Handlers
|
|
747
922
|
// ============================================
|
|
748
923
|
async handleToolCall(params) {
|
|
749
|
-
if (
|
|
750
|
-
|
|
924
|
+
if (this.options.onCallTool) {
|
|
925
|
+
return await this.options.onCallTool(params);
|
|
926
|
+
}
|
|
927
|
+
if (!this.client || !this.client.isConnected()) {
|
|
928
|
+
throw new Error("Client disconnected or not provided");
|
|
751
929
|
}
|
|
752
930
|
const sessionId = await this.getSessionId();
|
|
753
931
|
if (!sessionId) {
|
|
@@ -771,13 +949,19 @@ var AppHost = class {
|
|
|
771
949
|
// ============================================
|
|
772
950
|
// Private: Resource Loading
|
|
773
951
|
// ============================================
|
|
774
|
-
async
|
|
775
|
-
|
|
776
|
-
|
|
952
|
+
async launchSandboxedHtml(html, config) {
|
|
953
|
+
const sandboxUrlString = config.url instanceof URL ? config.url.href : config.url;
|
|
954
|
+
const url = new URL(sandboxUrlString, globalThis.location?.href);
|
|
955
|
+
if (config.csp && Object.keys(config.csp).length > 0) {
|
|
956
|
+
url.searchParams.set("csp", JSON.stringify(config.csp));
|
|
777
957
|
}
|
|
958
|
+
const { onReady } = await setupSandboxProxyIframe(this.iframe, url);
|
|
959
|
+
await onReady;
|
|
960
|
+
}
|
|
961
|
+
async readMcpAppHtml(uri) {
|
|
778
962
|
const sessionId = await this.getSessionId();
|
|
779
|
-
if (!sessionId) {
|
|
780
|
-
throw new Error("No active session");
|
|
963
|
+
if (!sessionId && !this.options.onReadResource) {
|
|
964
|
+
throw new Error("No active session.");
|
|
781
965
|
}
|
|
782
966
|
const response = await this.fetchResourceWithCache(sessionId, uri);
|
|
783
967
|
if (!response?.contents?.length) {
|
|
@@ -788,10 +972,18 @@ var AppHost = class {
|
|
|
788
972
|
if (!html) {
|
|
789
973
|
throw new Error(`Invalid content in resource: ${uri}`);
|
|
790
974
|
}
|
|
791
|
-
|
|
792
|
-
this.iframe.src = URL.createObjectURL(blob);
|
|
975
|
+
return html;
|
|
793
976
|
}
|
|
794
977
|
async fetchResourceWithCache(sessionId, uri) {
|
|
978
|
+
if (this.options.onReadResource) {
|
|
979
|
+
return await this.options.onReadResource(uri);
|
|
980
|
+
}
|
|
981
|
+
if (!sessionId) {
|
|
982
|
+
throw new Error("No active session");
|
|
983
|
+
}
|
|
984
|
+
if (!this.client) {
|
|
985
|
+
throw new Error("No client to read resource from");
|
|
986
|
+
}
|
|
795
987
|
if (this.hasClientCache()) {
|
|
796
988
|
return this.client.getOrFetchResource(sessionId, uri);
|
|
797
989
|
}
|
|
@@ -804,8 +996,11 @@ var AppHost = class {
|
|
|
804
996
|
}
|
|
805
997
|
async preloadResource(uri) {
|
|
806
998
|
try {
|
|
999
|
+
if (this.options.onReadResource) {
|
|
1000
|
+
return await this.options.onReadResource(uri);
|
|
1001
|
+
}
|
|
807
1002
|
const sessionId = await this.getSessionId();
|
|
808
|
-
if (!sessionId) return null;
|
|
1003
|
+
if (!sessionId || !this.client) return null;
|
|
809
1004
|
return await this.client.readResource(sessionId, uri);
|
|
810
1005
|
} catch (error) {
|
|
811
1006
|
this.log(`Preload failed for ${uri}`, "warn");
|
|
@@ -817,6 +1012,7 @@ var AppHost = class {
|
|
|
817
1012
|
// ============================================
|
|
818
1013
|
async getSessionId() {
|
|
819
1014
|
if (this.sessionId) return this.sessionId;
|
|
1015
|
+
if (!this.client) return void 0;
|
|
820
1016
|
const result = await this.client.getSessions();
|
|
821
1017
|
return result.sessions?.[0]?.sessionId;
|
|
822
1018
|
}
|
|
@@ -824,6 +1020,7 @@ var AppHost = class {
|
|
|
824
1020
|
return MCP_URI_SCHEMES.some((scheme) => url.startsWith(scheme));
|
|
825
1021
|
}
|
|
826
1022
|
hasClientCache() {
|
|
1023
|
+
if (!this.client) return false;
|
|
827
1024
|
return "getOrFetchResource" in this.client && typeof this.client.getOrFetchResource === "function";
|
|
828
1025
|
}
|
|
829
1026
|
extractUiResourceUri(tool) {
|
|
@@ -867,10 +1064,7 @@ function useAppHost(client, iframeRef, options) {
|
|
|
867
1064
|
initializingRef.current = true;
|
|
868
1065
|
const initHost = async () => {
|
|
869
1066
|
try {
|
|
870
|
-
const appHost = new AppHost(client, iframeRef.current);
|
|
871
|
-
appHost.onAppMessage = (params) => {
|
|
872
|
-
onMessageRef.current?.(params);
|
|
873
|
-
};
|
|
1067
|
+
const appHost = new AppHost(client, iframeRef.current, options);
|
|
874
1068
|
setHost(appHost);
|
|
875
1069
|
await appHost.start();
|
|
876
1070
|
} catch (err) {
|
|
@@ -886,39 +1080,106 @@ function useAppHost(client, iframeRef, options) {
|
|
|
886
1080
|
}, [client, iframeRef]);
|
|
887
1081
|
return { host, error };
|
|
888
1082
|
}
|
|
889
|
-
var
|
|
890
|
-
|
|
1083
|
+
var McpAppViewInner = react.forwardRef(function McpAppView({
|
|
1084
|
+
clientRef,
|
|
891
1085
|
name,
|
|
1086
|
+
toolResourceUri,
|
|
1087
|
+
html,
|
|
892
1088
|
input,
|
|
893
1089
|
result,
|
|
894
|
-
status,
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1090
|
+
status = "idle",
|
|
1091
|
+
toolInputPartial,
|
|
1092
|
+
toolCancelled,
|
|
1093
|
+
sandbox,
|
|
1094
|
+
hostContext,
|
|
1095
|
+
onCallTool,
|
|
1096
|
+
onReadResource,
|
|
1097
|
+
onFallbackRequest,
|
|
1098
|
+
onMessage,
|
|
1099
|
+
onOpenLink,
|
|
1100
|
+
onLoggingMessage,
|
|
1101
|
+
onSizeChanged,
|
|
1102
|
+
onError: onHostError,
|
|
1103
|
+
className,
|
|
1104
|
+
loader
|
|
1105
|
+
}, ref) {
|
|
1106
|
+
const mcpClient = clientRef.current;
|
|
1107
|
+
const metadata = getMcpAppMetadata(mcpClient, name);
|
|
1108
|
+
const sseClient = mcpClient?.sseClient ?? null;
|
|
1109
|
+
const resourceUri = toolResourceUri || metadata?.resourceUri;
|
|
1110
|
+
const appSessionId = metadata?.sessionId;
|
|
1111
|
+
const iframeRef = react.useRef(null);
|
|
1112
|
+
const containerRef = react.useRef(null);
|
|
1113
|
+
const preFullscreenHeightRef = react.useRef(null);
|
|
1114
|
+
const displayModeRef = react.useRef("inline");
|
|
1115
|
+
const [displayMode, setDisplayMode] = react.useState("inline");
|
|
1116
|
+
const setDisplayModeWithRef = (mode) => {
|
|
1117
|
+
displayModeRef.current = mode;
|
|
1118
|
+
setDisplayMode(mode);
|
|
1119
|
+
};
|
|
1120
|
+
const { host, error: hostError } = useAppHost(sseClient, iframeRef, {
|
|
1121
|
+
sandbox,
|
|
1122
|
+
hostContext,
|
|
1123
|
+
onCallTool,
|
|
1124
|
+
onReadResource,
|
|
1125
|
+
onFallbackRequest,
|
|
1126
|
+
onMessage,
|
|
1127
|
+
onOpenLink,
|
|
1128
|
+
onLoggingMessage,
|
|
1129
|
+
// Intercept onSizeChanged: when exiting fullscreen, ignore guest resize events
|
|
1130
|
+
// that arrive with the shrunken viewport dimensions, and restore the pre-fullscreen height.
|
|
1131
|
+
onSizeChanged: (params) => {
|
|
1132
|
+
if (displayModeRef.current === "inline" && preFullscreenHeightRef.current !== null) {
|
|
1133
|
+
const savedHeight = preFullscreenHeightRef.current;
|
|
1134
|
+
preFullscreenHeightRef.current = null;
|
|
1135
|
+
if (iframeRef.current) {
|
|
1136
|
+
iframeRef.current.style.height = `${savedHeight}px`;
|
|
910
1137
|
}
|
|
1138
|
+
return;
|
|
911
1139
|
}
|
|
1140
|
+
onSizeChanged?.(params);
|
|
1141
|
+
},
|
|
1142
|
+
onError: onHostError,
|
|
1143
|
+
onRequestDisplayMode: async (params) => {
|
|
1144
|
+
if (params.mode === "fullscreen") {
|
|
1145
|
+
if (iframeRef.current) {
|
|
1146
|
+
const h = iframeRef.current.getBoundingClientRect().height;
|
|
1147
|
+
if (h > 0) preFullscreenHeightRef.current = h;
|
|
1148
|
+
}
|
|
1149
|
+
try {
|
|
1150
|
+
if (containerRef.current?.requestFullscreen) {
|
|
1151
|
+
await containerRef.current.requestFullscreen();
|
|
1152
|
+
} else if (containerRef.current?.webkitRequestFullscreen) {
|
|
1153
|
+
await containerRef.current.webkitRequestFullscreen();
|
|
1154
|
+
}
|
|
1155
|
+
setDisplayModeWithRef("fullscreen");
|
|
1156
|
+
} catch (err) {
|
|
1157
|
+
console.warn("[McpAppHost] requestFullscreen failed:", err);
|
|
1158
|
+
preFullscreenHeightRef.current = null;
|
|
1159
|
+
return { mode: "inline" };
|
|
1160
|
+
}
|
|
1161
|
+
} else if (params.mode === "inline") {
|
|
1162
|
+
restoreHeightAfterFullscreen();
|
|
1163
|
+
try {
|
|
1164
|
+
if (document.fullscreenElement) {
|
|
1165
|
+
await document.exitFullscreen();
|
|
1166
|
+
}
|
|
1167
|
+
} catch (err) {
|
|
1168
|
+
}
|
|
1169
|
+
setDisplayModeWithRef("inline");
|
|
1170
|
+
}
|
|
1171
|
+
return { mode: params.mode };
|
|
912
1172
|
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1173
|
+
});
|
|
1174
|
+
react.useImperativeHandle(
|
|
1175
|
+
ref,
|
|
1176
|
+
() => ({
|
|
1177
|
+
teardownResource: (params) => {
|
|
1178
|
+
host?.teardownResource(params ?? {});
|
|
1179
|
+
}
|
|
1180
|
+
}),
|
|
1181
|
+
[host]
|
|
1182
|
+
);
|
|
922
1183
|
const [isLaunched, setIsLaunched] = react.useState(false);
|
|
923
1184
|
const [error, setError] = react.useState(null);
|
|
924
1185
|
const sentInputRef = react.useRef(false);
|
|
@@ -927,19 +1188,41 @@ var McpAppRenderer = react.memo(function McpAppRenderer2({
|
|
|
927
1188
|
const lastResultRef = react.useRef(result);
|
|
928
1189
|
const lastStatusRef = react.useRef(status);
|
|
929
1190
|
react.useEffect(() => {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
}, [
|
|
1191
|
+
setIsLaunched(false);
|
|
1192
|
+
setError(null);
|
|
1193
|
+
}, [resourceUri, appSessionId]);
|
|
1194
|
+
const restoreHeightAfterFullscreen = () => {
|
|
1195
|
+
const savedHeight = preFullscreenHeightRef.current;
|
|
1196
|
+
if (savedHeight && iframeRef.current) {
|
|
1197
|
+
iframeRef.current.style.height = `${savedHeight}px`;
|
|
1198
|
+
}
|
|
1199
|
+
preFullscreenHeightRef.current = null;
|
|
1200
|
+
};
|
|
1201
|
+
react.useEffect(() => {
|
|
1202
|
+
const onFullscreenChange = () => {
|
|
1203
|
+
const isFullscreen = !!document.fullscreenElement;
|
|
1204
|
+
if (!isFullscreen && displayModeRef.current === "fullscreen") {
|
|
1205
|
+
restoreHeightAfterFullscreen();
|
|
1206
|
+
setDisplayModeWithRef("inline");
|
|
1207
|
+
}
|
|
1208
|
+
};
|
|
1209
|
+
document.addEventListener("fullscreenchange", onFullscreenChange);
|
|
1210
|
+
return () => document.removeEventListener("fullscreenchange", onFullscreenChange);
|
|
1211
|
+
}, []);
|
|
933
1212
|
react.useEffect(() => {
|
|
934
|
-
if (!host || !
|
|
1213
|
+
if (!host || !resourceUri && !html) return;
|
|
1214
|
+
host.launch({ uri: resourceUri, html }, appSessionId).then(() => setIsLaunched(true)).catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
|
|
1215
|
+
}, [host, resourceUri, html, appSessionId]);
|
|
1216
|
+
react.useEffect(() => {
|
|
1217
|
+
if (!host || !isLaunched || !resourceUri || !appSessionId || !input) return;
|
|
935
1218
|
if (!sentInputRef.current || JSON.stringify(input) !== JSON.stringify(lastInputRef.current)) {
|
|
936
1219
|
sentInputRef.current = true;
|
|
937
1220
|
lastInputRef.current = input;
|
|
938
1221
|
host.sendToolInput(input);
|
|
939
1222
|
}
|
|
940
|
-
}, [host, isLaunched, input]);
|
|
1223
|
+
}, [host, isLaunched, input, resourceUri, appSessionId, name]);
|
|
941
1224
|
react.useEffect(() => {
|
|
942
|
-
if (!host || !isLaunched || result === void 0) return;
|
|
1225
|
+
if (!host || !isLaunched || !resourceUri || !appSessionId || result === void 0) return;
|
|
943
1226
|
if (status !== "complete") return;
|
|
944
1227
|
if (!sentResultRef.current || JSON.stringify(result) !== JSON.stringify(lastResultRef.current)) {
|
|
945
1228
|
sentResultRef.current = true;
|
|
@@ -947,7 +1230,7 @@ var McpAppRenderer = react.memo(function McpAppRenderer2({
|
|
|
947
1230
|
const formattedResult = typeof result === "string" ? { content: [{ type: "text", text: result }] } : result;
|
|
948
1231
|
host.sendToolResult(formattedResult);
|
|
949
1232
|
}
|
|
950
|
-
}, [host, isLaunched, result, status]);
|
|
1233
|
+
}, [host, isLaunched, result, status, resourceUri, appSessionId, name]);
|
|
951
1234
|
react.useEffect(() => {
|
|
952
1235
|
if (status === "executing" && lastStatusRef.current !== "executing") {
|
|
953
1236
|
sentInputRef.current = false;
|
|
@@ -955,6 +1238,28 @@ var McpAppRenderer = react.memo(function McpAppRenderer2({
|
|
|
955
1238
|
}
|
|
956
1239
|
lastStatusRef.current = status;
|
|
957
1240
|
}, [status]);
|
|
1241
|
+
react.useEffect(() => {
|
|
1242
|
+
if (!host) return;
|
|
1243
|
+
const mergedCtx = {
|
|
1244
|
+
theme: APP_HOST_DEFAULTS.THEME,
|
|
1245
|
+
platform: APP_HOST_DEFAULTS.PLATFORM,
|
|
1246
|
+
containerDimensions: { maxHeight: APP_HOST_DEFAULTS.MAX_HEIGHT },
|
|
1247
|
+
availableDisplayModes: ["inline", "fullscreen"],
|
|
1248
|
+
...hostContext || {},
|
|
1249
|
+
displayMode
|
|
1250
|
+
// always override with our authoritative state
|
|
1251
|
+
};
|
|
1252
|
+
host.setHostContext(mergedCtx);
|
|
1253
|
+
}, [host, hostContext, displayMode]);
|
|
1254
|
+
react.useEffect(() => {
|
|
1255
|
+
if (host && toolInputPartial) host.sendToolInputPartial(toolInputPartial);
|
|
1256
|
+
}, [host, toolInputPartial]);
|
|
1257
|
+
react.useEffect(() => {
|
|
1258
|
+
if (host && toolCancelled) host.sendToolCancelled("User cancelled");
|
|
1259
|
+
}, [host, toolCancelled]);
|
|
1260
|
+
if (!metadata && !html && !toolResourceUri) {
|
|
1261
|
+
return null;
|
|
1262
|
+
}
|
|
958
1263
|
const displayError = error || hostError;
|
|
959
1264
|
if (displayError) {
|
|
960
1265
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `p-4 bg-red-900/20 border border-red-700 rounded text-red-200 ${className || ""}`, children: [
|
|
@@ -962,50 +1267,90 @@ var McpAppRenderer = react.memo(function McpAppRenderer2({
|
|
|
962
1267
|
displayError.message || String(displayError)
|
|
963
1268
|
] });
|
|
964
1269
|
}
|
|
965
|
-
|
|
1270
|
+
const opacityClass = isLaunched ? "opacity-100" : "opacity-0";
|
|
1271
|
+
let containerClass = `w-full border border-gray-700 rounded bg-transparent my-2 relative ${className || ""}`;
|
|
1272
|
+
let iframeClass = `w-full transition-opacity duration-300 ${opacityClass}`;
|
|
1273
|
+
if (displayMode === "fullscreen") {
|
|
1274
|
+
containerClass = `w-full h-full bg-black m-0 p-0 flex flex-col relative`;
|
|
1275
|
+
iframeClass = `w-full flex-1 transition-opacity duration-300 ${opacityClass}`;
|
|
1276
|
+
}
|
|
1277
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: containerClass, children: [
|
|
1278
|
+
displayMode === "fullscreen" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-0 right-0 p-2 z-[100000] w-full bg-gradient-to-b from-black/80 to-transparent flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1279
|
+
"button",
|
|
1280
|
+
{
|
|
1281
|
+
title: "Exit Fullscreen",
|
|
1282
|
+
onClick: () => {
|
|
1283
|
+
restoreHeightAfterFullscreen();
|
|
1284
|
+
if (document.fullscreenElement) document.exitFullscreen();
|
|
1285
|
+
setDisplayModeWithRef("inline");
|
|
1286
|
+
},
|
|
1287
|
+
className: "px-4 py-2 bg-gray-800 hover:bg-gray-700 text-white rounded-md shadow flex items-center gap-2 border border-gray-600 transition-colors",
|
|
1288
|
+
children: [
|
|
1289
|
+
/* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3" }) }),
|
|
1290
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Exit" })
|
|
1291
|
+
]
|
|
1292
|
+
}
|
|
1293
|
+
) }),
|
|
966
1294
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
967
1295
|
"iframe",
|
|
968
1296
|
{
|
|
969
1297
|
ref: iframeRef,
|
|
970
1298
|
sandbox: "allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-downloads",
|
|
971
|
-
|
|
972
|
-
|
|
1299
|
+
allow: "fullscreen",
|
|
1300
|
+
className: iframeClass,
|
|
973
1301
|
title: "MCP App"
|
|
974
1302
|
}
|
|
975
1303
|
),
|
|
976
|
-
!isLaunched && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-
|
|
1304
|
+
!isLaunched && loader && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 bg-transparent flex items-center justify-center pointer-events-none z-10", children: loader })
|
|
977
1305
|
] });
|
|
978
1306
|
});
|
|
1307
|
+
var McpAppView2 = react.memo(McpAppViewInner);
|
|
1308
|
+
McpAppView2.displayName = "McpAppView";
|
|
979
1309
|
function useMcpApps(mcpClient) {
|
|
1310
|
+
const clientRef = react.useRef(mcpClient);
|
|
1311
|
+
clientRef.current = mcpClient;
|
|
980
1312
|
const getAppMetadata = react.useCallback(
|
|
981
|
-
(toolName) =>
|
|
982
|
-
|
|
983
|
-
const extractedName = extractToolName(toolName);
|
|
984
|
-
for (const conn of mcpClient.connections) {
|
|
985
|
-
for (const tool of conn.tools) {
|
|
986
|
-
const candidateName = extractToolName(tool.name);
|
|
987
|
-
const resourceUri = tool.mcpApp?.resourceUri ?? tool._meta?.ui?.resourceUri ?? tool._meta?.["ui/resourceUri"];
|
|
988
|
-
if (resourceUri && candidateName === extractedName) {
|
|
989
|
-
return {
|
|
990
|
-
toolName: candidateName,
|
|
991
|
-
resourceUri,
|
|
992
|
-
sessionId: conn.sessionId
|
|
993
|
-
};
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
}
|
|
997
|
-
return void 0;
|
|
998
|
-
},
|
|
999
|
-
[mcpClient]
|
|
1313
|
+
(toolName) => getMcpAppMetadata(clientRef.current, toolName),
|
|
1314
|
+
[]
|
|
1000
1315
|
);
|
|
1316
|
+
const McpAppRenderer = react.useMemo(() => {
|
|
1317
|
+
const Inner = react.forwardRef(function McpAppRenderer2(props, ref) {
|
|
1318
|
+
return /* @__PURE__ */ jsxRuntime.jsx(McpAppView2, { ref, clientRef, ...props });
|
|
1319
|
+
});
|
|
1320
|
+
const Renderer = react.memo(Inner);
|
|
1321
|
+
Renderer.displayName = "McpAppRenderer";
|
|
1322
|
+
return Renderer;
|
|
1323
|
+
}, []);
|
|
1001
1324
|
return { getAppMetadata, McpAppRenderer };
|
|
1002
1325
|
}
|
|
1003
1326
|
function extractToolName(fullName) {
|
|
1004
1327
|
const match = fullName.match(/(?:tool_[^_]+_)?(.+)$/);
|
|
1005
1328
|
return match?.[1] || fullName;
|
|
1006
1329
|
}
|
|
1330
|
+
function getMcpAppMetadata(mcpClient, toolName) {
|
|
1331
|
+
if (!mcpClient) return void 0;
|
|
1332
|
+
const extractedName = extractToolName(toolName);
|
|
1333
|
+
for (const conn of mcpClient.connections) {
|
|
1334
|
+
for (const tool of conn.tools) {
|
|
1335
|
+
const candidateName = extractToolName(tool.name);
|
|
1336
|
+
const resourceUri = tool.mcpApp?.resourceUri ?? tool._meta?.ui?.resourceUri ?? tool._meta?.["ui/resourceUri"];
|
|
1337
|
+
if (resourceUri && candidateName === extractedName) {
|
|
1338
|
+
return {
|
|
1339
|
+
toolName: candidateName,
|
|
1340
|
+
resourceUri,
|
|
1341
|
+
sessionId: conn.sessionId
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
return void 0;
|
|
1347
|
+
}
|
|
1007
1348
|
|
|
1349
|
+
exports.APP_HOST_DEFAULTS = APP_HOST_DEFAULTS;
|
|
1008
1350
|
exports.AppHost = AppHost;
|
|
1351
|
+
exports.DEFAULT_MCP_APP_CSP = DEFAULT_MCP_APP_CSP;
|
|
1352
|
+
exports.SANDBOX_PROXY_READY_METHOD = SANDBOX_PROXY_READY_METHOD;
|
|
1353
|
+
exports.SANDBOX_RESOURCE_READY_METHOD = SANDBOX_RESOURCE_READY_METHOD;
|
|
1009
1354
|
exports.SSEClient = SSEClient;
|
|
1010
1355
|
exports.useAppHost = useAppHost;
|
|
1011
1356
|
exports.useMcp = useMcp;
|