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