@ai-sdk/react 4.0.0-canary.126 → 4.0.0-canary.127

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @ai-sdk/react
2
2
 
3
+ ## 4.0.0-canary.127
4
+
5
+ ### Patch Changes
6
+
7
+ - 611f621: feat(mcp): feat(mcp): add support for MCP Apps
8
+ - Updated dependencies [611f621]
9
+ - @ai-sdk/mcp@2.0.0-canary.44
10
+
3
11
  ## 4.0.0-canary.126
4
12
 
5
13
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -1,6 +1,11 @@
1
- import { UIMessage, AbstractChat, ChatInit, CompletionRequestOptions, UseCompletionOptions, DeepPartial } from 'ai';
1
+ import { UIMessage, AbstractChat, ChatInit, CompletionRequestOptions, UseCompletionOptions, DeepPartial, ToolUIPart, UITools, DynamicToolUIPart } from 'ai';
2
2
  export { CreateUIMessage, UIMessage, UseCompletionOptions } from 'ai';
3
3
  import { FlexibleSchema, FetchFunction, Resolvable, InferSchema } from '@ai-sdk/provider-utils';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+ import * as react from 'react';
6
+ import { CSSProperties, ReactNode } from 'react';
7
+ import { MCPAppResource } from '@ai-sdk/mcp';
8
+ export { MCPAppResource } from '@ai-sdk/mcp';
4
9
 
5
10
  declare class Chat<UI_MESSAGE extends UIMessage> extends AbstractChat<UI_MESSAGE> {
6
11
  #private;
@@ -175,4 +180,73 @@ declare function useObject<SCHEMA extends FlexibleSchema, RESULT = InferSchema<S
175
180
  initialValue, fetch, onError, onFinish, headers, credentials, }: Experimental_UseObjectOptions<SCHEMA, RESULT>): Experimental_UseObjectHelpers<RESULT, INPUT>;
176
181
  declare const experimental_useObject: typeof useObject;
177
182
 
178
- export { Chat, Experimental_UseObjectHelpers, Experimental_UseObjectOptions, UseChatHelpers, UseChatOptions, UseCompletionHelpers, experimental_useObject, useChat, useCompletion };
183
+ type MCPAppDisplayMode = 'inline' | 'fullscreen' | 'pip';
184
+ type MCPAppMetadata = {
185
+ resourceUri: string;
186
+ mimeType: MCPAppResource['mimeType'];
187
+ visibility?: Array<'model' | 'app'>;
188
+ };
189
+ type MCPAppHostContext = {
190
+ theme?: 'light' | 'dark';
191
+ displayMode?: MCPAppDisplayMode;
192
+ availableDisplayModes?: MCPAppDisplayMode[];
193
+ [key: string]: unknown;
194
+ };
195
+ type MCPAppToolCallParams = {
196
+ name: string;
197
+ arguments?: Record<string, unknown>;
198
+ };
199
+ type MCPAppBridgeHandlers = {
200
+ allowedTools?: string[];
201
+ callTool?: (params: MCPAppToolCallParams) => Promise<unknown> | unknown;
202
+ readResource?: (params: {
203
+ uri: string;
204
+ }) => Promise<unknown> | unknown;
205
+ listResources?: (params?: unknown) => Promise<unknown> | unknown;
206
+ openLink?: (params: {
207
+ url: string;
208
+ }) => Promise<unknown> | unknown;
209
+ sendMessage?: (params: unknown) => Promise<unknown> | unknown;
210
+ updateModelContext?: (params: unknown) => Promise<unknown> | unknown;
211
+ requestDisplayMode?: (params: {
212
+ mode: MCPAppDisplayMode;
213
+ }) => Promise<{
214
+ mode: MCPAppDisplayMode;
215
+ }> | {
216
+ mode: MCPAppDisplayMode;
217
+ };
218
+ onSizeChange?: (params: {
219
+ width?: number;
220
+ height?: number;
221
+ }) => void;
222
+ onInitialized?: () => void;
223
+ onRequestTeardown?: (params: unknown) => void;
224
+ onLog?: (params: unknown) => void;
225
+ onError?: (error: Error) => void;
226
+ };
227
+ type MCPAppSandboxConfig = {
228
+ url: string | URL;
229
+ title?: string;
230
+ className?: string;
231
+ style?: CSSProperties;
232
+ targetOrigin?: string;
233
+ outerSandbox?: string;
234
+ innerSandbox?: string;
235
+ };
236
+ type MCPAppRendererProps = {
237
+ part: ToolUIPart<UITools> | DynamicToolUIPart;
238
+ sandbox: MCPAppSandboxConfig;
239
+ resource?: MCPAppResource;
240
+ loadResource?: (app: MCPAppMetadata) => Promise<MCPAppResource>;
241
+ handlers?: MCPAppBridgeHandlers;
242
+ hostInfo?: {
243
+ name: string;
244
+ version: string;
245
+ };
246
+ hostContext?: MCPAppHostContext;
247
+ fallback?: ReactNode;
248
+ };
249
+
250
+ declare function MCPAppRenderer({ part, sandbox, resource: resourceProp, loadResource, handlers, hostInfo, hostContext, fallback, }: MCPAppRendererProps): string | number | boolean | Iterable<react.ReactNode> | react_jsx_runtime.JSX.Element | null;
251
+
252
+ export { Chat, Experimental_UseObjectHelpers, Experimental_UseObjectOptions, MCPAppBridgeHandlers, MCPAppMetadata, MCPAppRendererProps, MCPAppSandboxConfig, UseChatHelpers, UseChatOptions, UseCompletionHelpers, MCPAppRenderer as experimental_MCPAppRenderer, experimental_useObject, useChat, useCompletion };
package/dist/index.js CHANGED
@@ -503,8 +503,578 @@ function useObject({
503
503
  };
504
504
  }
505
505
  var experimental_useObject = useObject;
506
+
507
+ // src/mcp-apps/app-renderer.tsx
508
+ import { useEffect as useEffect4, useState as useState3 } from "react";
509
+
510
+ // src/mcp-apps/app-frame.tsx
511
+ import { useEffect as useEffect3, useMemo, useRef as useRef4 } from "react";
512
+
513
+ // src/mcp-apps/bridge.ts
514
+ import { isJSONObject } from "@ai-sdk/provider";
515
+ var MCP_APP_PROTOCOL_VERSION = "2026-01-26";
516
+ function isJsonRpcMessage(value) {
517
+ return value != null && typeof value === "object" && !Array.isArray(value) && "jsonrpc" in value && value.jsonrpc === "2.0";
518
+ }
519
+ function isRequest(message) {
520
+ return "method" in message && "id" in message;
521
+ }
522
+ function isNotification(message) {
523
+ return "method" in message && !("id" in message);
524
+ }
525
+ function toError(error) {
526
+ return error instanceof Error ? error : new Error(String(error));
527
+ }
528
+ function assertToolCallParams(params) {
529
+ if (!isJSONObject(params) || typeof params.name !== "string") {
530
+ throw new Error("Invalid tools/call params");
531
+ }
532
+ return {
533
+ name: params.name,
534
+ arguments: isJSONObject(params.arguments) ? params.arguments : void 0
535
+ };
536
+ }
537
+ var MCPAppBridge = class {
538
+ constructor({
539
+ targetWindow,
540
+ targetOrigin = "*",
541
+ handlers = {},
542
+ hostInfo = { name: "ai-sdk-react", version: "1.0.0" },
543
+ hostContext = { displayMode: "inline" }
544
+ }) {
545
+ this.initialized = false;
546
+ this.pendingNotifications = [];
547
+ this.nextRequestId = 0;
548
+ this.pendingResponses = /* @__PURE__ */ new Map();
549
+ this.targetWindow = targetWindow;
550
+ this.targetOrigin = targetOrigin;
551
+ this.handlers = handlers;
552
+ this.hostInfo = hostInfo;
553
+ this.hostContext = hostContext;
554
+ }
555
+ /**
556
+ * Replaces the callbacks used to serve iframe requests.
557
+ */
558
+ setHandlers(handlers) {
559
+ this.handlers = handlers;
560
+ }
561
+ /**
562
+ * Updates host context and notifies the iframe after initialization.
563
+ *
564
+ * @example
565
+ * ```ts
566
+ * bridge.setHostContext({ theme: 'dark', displayMode: 'inline' });
567
+ * ```
568
+ */
569
+ setHostContext(hostContext) {
570
+ this.hostContext = hostContext;
571
+ this.sendNotification({
572
+ method: "ui/notifications/host-context-changed",
573
+ params: hostContext
574
+ });
575
+ }
576
+ /**
577
+ * Processes one `message` event from the sandbox proxy iframe.
578
+ */
579
+ handleMessage(event) {
580
+ if (event.source !== this.targetWindow || !isJsonRpcMessage(event.data)) {
581
+ return;
582
+ }
583
+ const message = event.data;
584
+ if ("result" in message || "error" in message) {
585
+ this.handleResponse(message);
586
+ return;
587
+ }
588
+ if (isRequest(message)) {
589
+ void this.handleRequest(message);
590
+ return;
591
+ }
592
+ if (isNotification(message)) {
593
+ this.handleNotification(message);
594
+ }
595
+ }
596
+ /**
597
+ * Sends app HTML and sandbox settings to the sandbox proxy.
598
+ */
599
+ sendSandboxResourceReady(params) {
600
+ this.post({
601
+ jsonrpc: "2.0",
602
+ method: "ui/notifications/sandbox-resource-ready",
603
+ params
604
+ });
605
+ }
606
+ /**
607
+ * Sends final tool arguments to the MCP App.
608
+ */
609
+ sendToolInput(input) {
610
+ this.sendNotification({
611
+ method: "ui/notifications/tool-input",
612
+ params: { arguments: input }
613
+ });
614
+ }
615
+ /**
616
+ * Sends a completed MCP tool result to the MCP App.
617
+ */
618
+ sendToolResult(result) {
619
+ this.sendNotification({
620
+ method: "ui/notifications/tool-result",
621
+ params: result
622
+ });
623
+ }
624
+ /**
625
+ * Notifies the MCP App that the related tool call was cancelled.
626
+ */
627
+ sendToolCancelled(reason) {
628
+ this.sendNotification({
629
+ method: "ui/notifications/tool-cancelled",
630
+ params: reason != null ? { reason } : {}
631
+ });
632
+ }
633
+ /**
634
+ * Requests graceful teardown before the host removes the iframe.
635
+ */
636
+ teardownResource() {
637
+ return this.request("ui/resource-teardown", {});
638
+ }
639
+ /**
640
+ * Rejects pending bridge requests and clears queued notifications.
641
+ */
642
+ close() {
643
+ for (const pending of this.pendingResponses.values()) {
644
+ pending.reject(new Error("MCP App bridge closed"));
645
+ }
646
+ this.pendingResponses.clear();
647
+ this.pendingNotifications = [];
648
+ }
649
+ /**
650
+ * Resolves or rejects a host-initiated request when the iframe responds.
651
+ */
652
+ handleResponse(response) {
653
+ const pending = this.pendingResponses.get(response.id);
654
+ if (pending == null) {
655
+ return;
656
+ }
657
+ this.pendingResponses.delete(response.id);
658
+ if (response.error != null) {
659
+ pending.reject(new Error(response.error.message));
660
+ } else {
661
+ pending.resolve(response.result);
662
+ }
663
+ }
664
+ /**
665
+ * Runs a handler for an iframe request and posts the JSON-RPC response.
666
+ */
667
+ async handleRequest(request) {
668
+ var _a, _b;
669
+ try {
670
+ const result = await this.getRequestResult(request);
671
+ this.post({ jsonrpc: "2.0", id: request.id, result });
672
+ } catch (error) {
673
+ const normalizedError = toError(error);
674
+ (_b = (_a = this.handlers).onError) == null ? void 0 : _b.call(_a, normalizedError);
675
+ this.post({
676
+ jsonrpc: "2.0",
677
+ id: request.id,
678
+ error: { code: -32603, message: normalizedError.message }
679
+ });
680
+ }
681
+ }
682
+ /**
683
+ * Maps supported iframe request methods to host callbacks.
684
+ */
685
+ async getRequestResult(request) {
686
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
687
+ switch (request.method) {
688
+ case "ui/initialize":
689
+ return {
690
+ protocolVersion: MCP_APP_PROTOCOL_VERSION,
691
+ hostCapabilities: {
692
+ ...this.handlers.callTool != null ? { serverTools: {} } : {},
693
+ ...this.handlers.readResource != null ? { serverResources: {} } : {},
694
+ ...this.handlers.onLog != null ? { logging: {} } : {}
695
+ },
696
+ hostInfo: this.hostInfo,
697
+ hostContext: this.hostContext
698
+ };
699
+ case "tools/call": {
700
+ if (this.handlers.callTool == null) {
701
+ throw new Error("No tools/call handler configured");
702
+ }
703
+ const params = assertToolCallParams(request.params);
704
+ if (this.handlers.allowedTools != null && !this.handlers.allowedTools.includes(params.name)) {
705
+ throw new Error(`Tool is not app-visible: ${params.name}`);
706
+ }
707
+ return this.handlers.callTool(params);
708
+ }
709
+ case "resources/read":
710
+ if (this.handlers.readResource == null) {
711
+ throw new Error("No resources/read handler configured");
712
+ }
713
+ return this.handlers.readResource(request.params);
714
+ case "resources/list":
715
+ if (this.handlers.listResources == null) {
716
+ throw new Error("No resources/list handler configured");
717
+ }
718
+ return this.handlers.listResources(request.params);
719
+ case "ui/open-link":
720
+ if (this.handlers.openLink == null) {
721
+ throw new Error("No ui/open-link handler configured");
722
+ }
723
+ return this.handlers.openLink(request.params);
724
+ case "ui/message":
725
+ return (_c = (_b = (_a = this.handlers).sendMessage) == null ? void 0 : _b.call(_a, request.params)) != null ? _c : {};
726
+ case "ui/update-model-context":
727
+ return (_f = (_e = (_d = this.handlers).updateModelContext) == null ? void 0 : _e.call(_d, request.params)) != null ? _f : {};
728
+ case "ui/request-display-mode":
729
+ return (_j = (_h = (_g = this.handlers).requestDisplayMode) == null ? void 0 : _h.call(
730
+ _g,
731
+ request.params
732
+ )) != null ? _j : { mode: (_i = this.hostContext.displayMode) != null ? _i : "inline" };
733
+ default:
734
+ throw new Error(`Unsupported MCP App method: ${request.method}`);
735
+ }
736
+ }
737
+ /**
738
+ * Handles iframe lifecycle and telemetry notifications.
739
+ */
740
+ handleNotification(notification) {
741
+ var _a, _b, _c, _d, _e, _f, _g, _h;
742
+ switch (notification.method) {
743
+ case "ui/notifications/initialized":
744
+ this.initialized = true;
745
+ this.flushNotifications();
746
+ (_b = (_a = this.handlers).onInitialized) == null ? void 0 : _b.call(_a);
747
+ break;
748
+ case "ui/notifications/size-changed":
749
+ (_d = (_c = this.handlers).onSizeChange) == null ? void 0 : _d.call(
750
+ _c,
751
+ notification.params
752
+ );
753
+ break;
754
+ case "ui/notifications/request-teardown":
755
+ (_f = (_e = this.handlers).onRequestTeardown) == null ? void 0 : _f.call(_e, notification.params);
756
+ break;
757
+ case "notifications/message":
758
+ (_h = (_g = this.handlers).onLog) == null ? void 0 : _h.call(_g, notification.params);
759
+ break;
760
+ }
761
+ }
762
+ /**
763
+ * Sends a host-to-iframe notification, queueing it until app initialization.
764
+ */
765
+ sendNotification(notification) {
766
+ const message = { jsonrpc: "2.0", ...notification };
767
+ if (!this.initialized && !notification.method.includes("sandbox")) {
768
+ this.pendingNotifications.push(message);
769
+ return;
770
+ }
771
+ this.post(message);
772
+ }
773
+ /**
774
+ * Sends notifications that were queued before `ui/notifications/initialized`.
775
+ */
776
+ flushNotifications() {
777
+ const notifications = this.pendingNotifications;
778
+ this.pendingNotifications = [];
779
+ for (const notification of notifications) {
780
+ this.post(notification);
781
+ }
782
+ }
783
+ /**
784
+ * Sends a host-initiated JSON-RPC request to the iframe.
785
+ */
786
+ request(method, params) {
787
+ const id = this.nextRequestId++;
788
+ this.post({ jsonrpc: "2.0", id, method, params });
789
+ return new Promise((resolve2, reject) => {
790
+ this.pendingResponses.set(id, { resolve: resolve2, reject });
791
+ });
792
+ }
793
+ /**
794
+ * Posts a JSON-RPC message to the sandbox proxy iframe.
795
+ */
796
+ post(message) {
797
+ this.targetWindow.postMessage(message, this.targetOrigin);
798
+ }
799
+ };
800
+
801
+ // src/mcp-apps/sandbox.ts
802
+ var MCP_APP_DEFAULT_OUTER_SANDBOX = "allow-scripts allow-same-origin allow-forms";
803
+ var MCP_APP_DEFAULT_INNER_SANDBOX = "allow-scripts allow-forms";
804
+ function getMCPAppCSP(csp) {
805
+ var _a, _b, _c;
806
+ if (csp == null) {
807
+ return void 0;
808
+ }
809
+ const connectSrc = ["'self'", ...(_a = csp.connectDomains) != null ? _a : []];
810
+ const imgSrc = ["'self'", "data:", ...(_b = csp.resourceDomains) != null ? _b : []];
811
+ const frameSrc = ["'self'", ...(_c = csp.frameDomains) != null ? _c : []];
812
+ return [
813
+ "default-src 'none'",
814
+ "script-src 'unsafe-inline'",
815
+ "style-src 'unsafe-inline'",
816
+ `connect-src ${connectSrc.join(" ")}`,
817
+ `img-src ${imgSrc.join(" ")}`,
818
+ `font-src ${imgSrc.join(" ")}`,
819
+ `frame-src ${frameSrc.join(" ")}`
820
+ ].join("; ");
821
+ }
822
+ function getMCPAppAllowAttribute(permissions) {
823
+ if (permissions == null) {
824
+ return void 0;
825
+ }
826
+ const allow = [];
827
+ if (permissions.camera)
828
+ allow.push("camera");
829
+ if (permissions.microphone)
830
+ allow.push("microphone");
831
+ if (permissions.geolocation)
832
+ allow.push("geolocation");
833
+ if (permissions.clipboardWrite)
834
+ allow.push("clipboard-write");
835
+ return allow.length > 0 ? allow.join("; ") : void 0;
836
+ }
837
+
838
+ // src/mcp-apps/utils.ts
839
+ import { isJSONObject as isJSONObject2 } from "@ai-sdk/provider";
840
+ function getMCPAppFromToolPart(part) {
841
+ var _a;
842
+ const mcpMetadata = (_a = part.toolMetadata) == null ? void 0 : _a.mcp;
843
+ const rawAppMetadata = isJSONObject2(mcpMetadata) ? mcpMetadata.app : void 0;
844
+ const appMetadata = isJSONObject2(rawAppMetadata) ? rawAppMetadata : void 0;
845
+ if (appMetadata == null || appMetadata.mimeType !== "text/html;profile=mcp-app" || typeof appMetadata.resourceUri !== "string" || !appMetadata.resourceUri.startsWith("ui://") || appMetadata.visibility != null && (!Array.isArray(appMetadata.visibility) || appMetadata.visibility.some(
846
+ (value) => value !== "model" && value !== "app"
847
+ ))) {
848
+ return void 0;
849
+ }
850
+ return appMetadata;
851
+ }
852
+ function normalizeMCPAppToolResult(output) {
853
+ if (output != null && typeof output === "object" && "content" in output) {
854
+ return output;
855
+ }
856
+ return {
857
+ content: [],
858
+ structuredContent: output
859
+ };
860
+ }
861
+
862
+ // src/mcp-apps/app-frame.tsx
863
+ import { jsx } from "react/jsx-runtime";
864
+ function sendToolState({
865
+ bridge,
866
+ input,
867
+ output
868
+ }) {
869
+ if (bridge == null) {
870
+ return;
871
+ }
872
+ if (input !== void 0) {
873
+ bridge.sendToolInput(input);
874
+ }
875
+ if (output !== void 0) {
876
+ bridge.sendToolResult(normalizeMCPAppToolResult(output));
877
+ }
878
+ }
879
+ function MCPAppFrame({
880
+ app,
881
+ resource,
882
+ input,
883
+ output,
884
+ sandbox,
885
+ handlers,
886
+ hostInfo,
887
+ hostContext
888
+ }) {
889
+ var _a, _b, _c, _d, _e, _f;
890
+ const iframeRef = useRef4(null);
891
+ const bridgeRef = useRef4(void 0);
892
+ const inputRef = useRef4(input);
893
+ const outputRef = useRef4(output);
894
+ const hostContextRef = useRef4(hostContext);
895
+ const initializedRef = useRef4(false);
896
+ inputRef.current = input;
897
+ outputRef.current = output;
898
+ hostContextRef.current = hostContext;
899
+ const targetOrigin = (_a = sandbox.targetOrigin) != null ? _a : "*";
900
+ const sandboxUrl = String(sandbox.url);
901
+ const resourceCSP = getMCPAppCSP((_b = resource.meta) == null ? void 0 : _b.csp);
902
+ const resourceAllow = getMCPAppAllowAttribute((_c = resource.meta) == null ? void 0 : _c.permissions);
903
+ const innerSandbox = (_d = sandbox.innerSandbox) != null ? _d : MCP_APP_DEFAULT_INNER_SANDBOX;
904
+ const bridgeHandlers = useMemo(
905
+ () => ({
906
+ ...handlers,
907
+ onInitialized: () => {
908
+ var _a2;
909
+ initializedRef.current = true;
910
+ (_a2 = handlers == null ? void 0 : handlers.onInitialized) == null ? void 0 : _a2.call(handlers);
911
+ sendToolState({
912
+ bridge: bridgeRef.current,
913
+ input: inputRef.current,
914
+ output: outputRef.current
915
+ });
916
+ }
917
+ }),
918
+ [handlers]
919
+ );
920
+ const bridgeHandlersRef = useRef4(bridgeHandlers);
921
+ bridgeHandlersRef.current = bridgeHandlers;
922
+ useEffect3(() => {
923
+ const iframe = iframeRef.current;
924
+ const targetWindow = iframe == null ? void 0 : iframe.contentWindow;
925
+ if (targetWindow == null) {
926
+ return;
927
+ }
928
+ initializedRef.current = false;
929
+ const bridge = new MCPAppBridge({
930
+ targetWindow,
931
+ targetOrigin,
932
+ handlers: bridgeHandlersRef.current,
933
+ hostInfo,
934
+ hostContext: hostContextRef.current
935
+ });
936
+ bridgeRef.current = bridge;
937
+ const onMessage = (event) => {
938
+ var _a2;
939
+ if (event.source === targetWindow && ((_a2 = event.data) == null ? void 0 : _a2.jsonrpc) === "2.0" && event.data.method === "ui/notifications/sandbox-proxy-ready") {
940
+ bridge.sendSandboxResourceReady({
941
+ html: resource.html,
942
+ csp: resourceCSP,
943
+ sandbox: innerSandbox,
944
+ allow: resourceAllow
945
+ });
946
+ return;
947
+ }
948
+ bridge.handleMessage(event);
949
+ };
950
+ window.addEventListener("message", onMessage);
951
+ return () => {
952
+ initializedRef.current = false;
953
+ window.removeEventListener("message", onMessage);
954
+ void bridge.teardownResource().catch(() => {
955
+ });
956
+ bridge.close();
957
+ bridgeRef.current = void 0;
958
+ };
959
+ }, [
960
+ hostInfo,
961
+ innerSandbox,
962
+ resource.html,
963
+ resourceAllow,
964
+ resourceCSP,
965
+ sandboxUrl,
966
+ targetOrigin
967
+ ]);
968
+ useEffect3(() => {
969
+ var _a2;
970
+ (_a2 = bridgeRef.current) == null ? void 0 : _a2.setHandlers(bridgeHandlers);
971
+ }, [bridgeHandlers]);
972
+ useEffect3(() => {
973
+ var _a2;
974
+ if (hostContext != null) {
975
+ (_a2 = bridgeRef.current) == null ? void 0 : _a2.setHostContext(hostContext);
976
+ }
977
+ }, [hostContext]);
978
+ useEffect3(() => {
979
+ var _a2;
980
+ if (initializedRef.current && input !== void 0) {
981
+ (_a2 = bridgeRef.current) == null ? void 0 : _a2.sendToolInput(input);
982
+ }
983
+ }, [input]);
984
+ useEffect3(() => {
985
+ var _a2;
986
+ if (initializedRef.current && output !== void 0) {
987
+ (_a2 = bridgeRef.current) == null ? void 0 : _a2.sendToolResult(normalizeMCPAppToolResult(output));
988
+ }
989
+ }, [output]);
990
+ return /* @__PURE__ */ jsx(
991
+ "iframe",
992
+ {
993
+ ref: iframeRef,
994
+ title: "MCP App",
995
+ "aria-label": (_e = sandbox.title) != null ? _e : app.resourceUri,
996
+ src: sandboxUrl,
997
+ className: sandbox.className,
998
+ style: sandbox.style,
999
+ sandbox: (_f = sandbox.outerSandbox) != null ? _f : MCP_APP_DEFAULT_OUTER_SANDBOX
1000
+ }
1001
+ );
1002
+ }
1003
+
1004
+ // src/mcp-apps/app-renderer.tsx
1005
+ import { jsx as jsx2 } from "react/jsx-runtime";
1006
+ function getToolPartOutput(part) {
1007
+ return part.state === "output-available" ? part.output : void 0;
1008
+ }
1009
+ function getToolPartInput(part) {
1010
+ return part.state === "input-available" || part.state === "output-available" ? part.input : void 0;
1011
+ }
1012
+ function MCPAppRenderer({
1013
+ part,
1014
+ sandbox,
1015
+ resource: resourceProp,
1016
+ loadResource,
1017
+ handlers,
1018
+ hostInfo,
1019
+ hostContext,
1020
+ fallback = null
1021
+ }) {
1022
+ const app = getMCPAppFromToolPart(part);
1023
+ const [cachedApp, setCachedApp] = useState3();
1024
+ const [loadedResource, setLoadedResource] = useState3();
1025
+ useEffect4(() => {
1026
+ if (app != null) {
1027
+ setCachedApp(
1028
+ (previous) => (previous == null ? void 0 : previous.resourceUri) === app.resourceUri ? previous : app
1029
+ );
1030
+ }
1031
+ }, [app == null ? void 0 : app.resourceUri]);
1032
+ const appForRender = app != null ? app : cachedApp;
1033
+ useEffect4(() => {
1034
+ if (appForRender == null || resourceProp != null || loadResource == null) {
1035
+ return;
1036
+ }
1037
+ let cancelled = false;
1038
+ const resourceUri = appForRender.resourceUri;
1039
+ loadResource(appForRender).then((resource2) => {
1040
+ if (!cancelled) {
1041
+ setLoadedResource({ resourceUri, resource: resource2 });
1042
+ }
1043
+ }).catch((error2) => {
1044
+ if (!cancelled) {
1045
+ setLoadedResource({
1046
+ resourceUri,
1047
+ error: error2 instanceof Error ? error2 : new Error(String(error2))
1048
+ });
1049
+ }
1050
+ });
1051
+ return () => {
1052
+ cancelled = true;
1053
+ };
1054
+ }, [appForRender == null ? void 0 : appForRender.resourceUri, loadResource, resourceProp]);
1055
+ const loadedResourceForApp = (loadedResource == null ? void 0 : loadedResource.resourceUri) === (appForRender == null ? void 0 : appForRender.resourceUri) ? loadedResource : void 0;
1056
+ const resource = resourceProp != null ? resourceProp : loadedResourceForApp == null ? void 0 : loadedResourceForApp.resource;
1057
+ const error = resourceProp == null ? loadedResourceForApp == null ? void 0 : loadedResourceForApp.error : void 0;
1058
+ if (appForRender == null || error != null || resource == null) {
1059
+ return fallback;
1060
+ }
1061
+ return /* @__PURE__ */ jsx2(
1062
+ MCPAppFrame,
1063
+ {
1064
+ app: appForRender,
1065
+ resource,
1066
+ input: getToolPartInput(part),
1067
+ output: getToolPartOutput(part),
1068
+ sandbox,
1069
+ handlers,
1070
+ hostInfo,
1071
+ hostContext
1072
+ }
1073
+ );
1074
+ }
506
1075
  export {
507
1076
  Chat,
1077
+ MCPAppRenderer as experimental_MCPAppRenderer,
508
1078
  experimental_useObject,
509
1079
  useChat,
510
1080
  useCompletion