@agent-native/core 0.72.3 → 0.72.4

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.
Files changed (136) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +10 -0
  3. package/corpus/core/package.json +6 -6
  4. package/corpus/core/src/a2a/client.ts +7 -3
  5. package/corpus/core/src/client/api-path.ts +28 -0
  6. package/corpus/core/src/client/embed-auth.ts +26 -0
  7. package/corpus/core/src/client/mcp-app-host.ts +6 -0
  8. package/corpus/core/src/client/mcp-apps/McpAppRenderer.tsx +227 -33
  9. package/corpus/core/src/client/resources/use-mcp-servers.ts +1 -0
  10. package/corpus/core/src/client/settings/DemoModeSection.tsx +3 -1
  11. package/corpus/core/src/demo/fetch-interceptor.ts +1 -1
  12. package/corpus/core/src/embedding/agent.ts +6 -1
  13. package/corpus/core/src/embedding/bridge.ts +34 -1
  14. package/corpus/core/src/mcp/build-server.ts +38 -10
  15. package/corpus/core/src/mcp/embed-app.ts +120 -45
  16. package/corpus/core/src/mcp/index.ts +5 -0
  17. package/corpus/core/src/mcp/org-directory.ts +70 -11
  18. package/corpus/core/src/mcp/server.ts +14 -0
  19. package/corpus/core/src/mcp-client/config.ts +12 -0
  20. package/corpus/core/src/mcp-client/index.ts +2 -0
  21. package/corpus/core/src/mcp-client/manager.ts +268 -9
  22. package/corpus/core/src/mcp-client/remote-store.ts +154 -0
  23. package/corpus/core/src/mcp-client/routes.ts +2 -0
  24. package/corpus/core/src/server/agent-chat-plugin.ts +8 -0
  25. package/corpus/core/src/server/index.ts +1 -0
  26. package/corpus/core/src/shared/mcp-embed-headers.ts +44 -3
  27. package/corpus/core/src/vite/client.ts +53 -0
  28. package/corpus/templates/assets/.agents/skills/a2a-assets/SKILL.md +17 -10
  29. package/corpus/templates/assets/.agents/skills/asset-generation/SKILL.md +15 -6
  30. package/corpus/templates/assets/AGENTS.md +7 -5
  31. package/corpus/templates/assets/actions/generate-asset.ts +161 -0
  32. package/corpus/templates/assets/actions/list-assets.ts +4 -2
  33. package/corpus/templates/assets/actions/open-asset-picker.ts +84 -3
  34. package/corpus/templates/assets/app/routes/library.tsx +243 -40
  35. package/corpus/templates/clips/desktop/src-tauri/src/native_speech.rs +9 -0
  36. package/corpus/templates/design/AGENTS.md +10 -5
  37. package/corpus/templates/design/actions/connect-assets-mcp.ts +131 -0
  38. package/corpus/templates/design/actions/insert-asset.ts +219 -0
  39. package/corpus/templates/design/actions/view-screen.ts +3 -1
  40. package/corpus/templates/design/app/components/editor/PromptDialog.tsx +1 -1
  41. package/corpus/templates/design/app/pages/DesignEditor.tsx +53 -0
  42. package/corpus/templates/design/server/plugins/agent-chat.ts +5 -1
  43. package/corpus/templates/design/server/plugins/assets-mcp.ts +60 -0
  44. package/dist/a2a/client.d.ts +1 -0
  45. package/dist/a2a/client.d.ts.map +1 -1
  46. package/dist/a2a/client.js +5 -3
  47. package/dist/a2a/client.js.map +1 -1
  48. package/dist/client/api-path.d.ts.map +1 -1
  49. package/dist/client/api-path.js +27 -0
  50. package/dist/client/api-path.js.map +1 -1
  51. package/dist/client/embed-auth.d.ts.map +1 -1
  52. package/dist/client/embed-auth.js +27 -0
  53. package/dist/client/embed-auth.js.map +1 -1
  54. package/dist/client/mcp-app-host.d.ts.map +1 -1
  55. package/dist/client/mcp-app-host.js +5 -0
  56. package/dist/client/mcp-app-host.js.map +1 -1
  57. package/dist/client/mcp-apps/McpAppRenderer.d.ts +1 -0
  58. package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  59. package/dist/client/mcp-apps/McpAppRenderer.js +179 -33
  60. package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
  61. package/dist/client/resources/use-mcp-servers.d.ts +1 -0
  62. package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
  63. package/dist/client/resources/use-mcp-servers.js.map +1 -1
  64. package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
  65. package/dist/client/settings/DemoModeSection.js +3 -1
  66. package/dist/client/settings/DemoModeSection.js.map +1 -1
  67. package/dist/demo/fetch-interceptor.js +1 -1
  68. package/dist/demo/fetch-interceptor.js.map +1 -1
  69. package/dist/embedding/agent.d.ts +1 -1
  70. package/dist/embedding/agent.d.ts.map +1 -1
  71. package/dist/embedding/agent.js +1 -1
  72. package/dist/embedding/agent.js.map +1 -1
  73. package/dist/embedding/bridge.d.ts.map +1 -1
  74. package/dist/embedding/bridge.js +27 -1
  75. package/dist/embedding/bridge.js.map +1 -1
  76. package/dist/extensions/schema.d.ts +2 -2
  77. package/dist/mcp/build-server.d.ts +2 -0
  78. package/dist/mcp/build-server.d.ts.map +1 -1
  79. package/dist/mcp/build-server.js +32 -9
  80. package/dist/mcp/build-server.js.map +1 -1
  81. package/dist/mcp/embed-app.d.ts.map +1 -1
  82. package/dist/mcp/embed-app.js +120 -45
  83. package/dist/mcp/embed-app.js.map +1 -1
  84. package/dist/mcp/index.d.ts +1 -0
  85. package/dist/mcp/index.d.ts.map +1 -1
  86. package/dist/mcp/index.js +1 -0
  87. package/dist/mcp/index.js.map +1 -1
  88. package/dist/mcp/org-directory.d.ts +1 -0
  89. package/dist/mcp/org-directory.d.ts.map +1 -1
  90. package/dist/mcp/org-directory.js +59 -11
  91. package/dist/mcp/org-directory.js.map +1 -1
  92. package/dist/mcp/server.d.ts.map +1 -1
  93. package/dist/mcp/server.js +9 -0
  94. package/dist/mcp/server.js.map +1 -1
  95. package/dist/mcp-client/config.d.ts +12 -0
  96. package/dist/mcp-client/config.d.ts.map +1 -1
  97. package/dist/mcp-client/config.js.map +1 -1
  98. package/dist/mcp-client/index.d.ts +1 -1
  99. package/dist/mcp-client/index.d.ts.map +1 -1
  100. package/dist/mcp-client/index.js +1 -1
  101. package/dist/mcp-client/index.js.map +1 -1
  102. package/dist/mcp-client/manager.d.ts +2 -0
  103. package/dist/mcp-client/manager.d.ts.map +1 -1
  104. package/dist/mcp-client/manager.js +201 -9
  105. package/dist/mcp-client/manager.js.map +1 -1
  106. package/dist/mcp-client/remote-store.d.ts +27 -0
  107. package/dist/mcp-client/remote-store.d.ts.map +1 -1
  108. package/dist/mcp-client/remote-store.js +105 -0
  109. package/dist/mcp-client/remote-store.js.map +1 -1
  110. package/dist/mcp-client/routes.d.ts +1 -0
  111. package/dist/mcp-client/routes.d.ts.map +1 -1
  112. package/dist/mcp-client/routes.js +1 -0
  113. package/dist/mcp-client/routes.js.map +1 -1
  114. package/dist/provider-api/actions/github-repo-files.d.ts +2 -2
  115. package/dist/provider-api/actions/query-staged-dataset.d.ts +3 -3
  116. package/dist/provider-api/corpus-jobs.d.ts +8 -8
  117. package/dist/server/agent-chat-plugin.d.ts +2 -0
  118. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  119. package/dist/server/agent-chat-plugin.js +8 -0
  120. package/dist/server/agent-chat-plugin.js.map +1 -1
  121. package/dist/server/index.d.ts +1 -1
  122. package/dist/server/index.d.ts.map +1 -1
  123. package/dist/server/index.js +1 -1
  124. package/dist/server/index.js.map +1 -1
  125. package/dist/shared/mcp-embed-headers.d.ts +3 -1
  126. package/dist/shared/mcp-embed-headers.d.ts.map +1 -1
  127. package/dist/shared/mcp-embed-headers.js +40 -3
  128. package/dist/shared/mcp-embed-headers.js.map +1 -1
  129. package/dist/sharing/actions/list-resource-shares.d.ts +1 -1
  130. package/dist/sharing/actions/set-resource-visibility.d.ts +2 -2
  131. package/dist/sharing/actions/share-resource.d.ts +1 -1
  132. package/dist/sharing/schema.d.ts +1 -1
  133. package/dist/vite/client.d.ts.map +1 -1
  134. package/dist/vite/client.js +44 -0
  135. package/dist/vite/client.js.map +1 -1
  136. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"embed-app.d.ts","sourceRoot":"","sources":["../../src/mcp/embed-app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAM/D,eAAO,MAAM,iCAAiC,mBAAmB,CAAC;AAElE,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAChD,eAAO,MAAM,+BAA+B,QACkB,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAUD,wBAAgB,QAAQ,CACtB,OAAO,GAAE,eAAoB,GAC5B,0BAA0B,CAs1D5B"}
1
+ {"version":3,"file":"embed-app.d.ts","sourceRoot":"","sources":["../../src/mcp/embed-app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAM/D,eAAO,MAAM,iCAAiC,mBAAmB,CAAC;AAElE,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAChD,eAAO,MAAM,+BAA+B,QACkB,CAAC;AAE/D,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAUD,wBAAgB,QAAQ,CACtB,OAAO,GAAE,eAAoB,GAC5B,0BAA0B,CAi6D5B"}
@@ -87,6 +87,7 @@ export function embedApp(options = {}) {
87
87
  const frameReadyMessageDelays = [0, 200, 500, 1500, 3000, 7000, 15000, 30000];
88
88
  const frameReadyTimeoutMs = 45000;
89
89
  const frameLoadTimeoutMs = 45000;
90
+ const maxEmbedSessionRefreshAttempts = 2;
90
91
  const defaultOpenAiBridgeWaitMs = 200;
91
92
  const chatGptOpenAiBridgeWaitMs = 5000;
92
93
  const openAiBridgePollMs = 50;
@@ -94,6 +95,7 @@ export function embedApp(options = {}) {
94
95
  const nativeBridgeRequestTimeoutMs = 30000;
95
96
  const wrapperRequestTimeoutMs = 5000;
96
97
  let app = null;
98
+ let appConnectPromise = null;
97
99
  let openAiBridge = null;
98
100
  let wrapperRequestId = 0;
99
101
  const wrapperRequests = new Map();
@@ -107,6 +109,7 @@ export function embedApp(options = {}) {
107
109
  let appFrameReadyTimer = null;
108
110
  let appFrameLoadTimer = null;
109
111
  let lastFrameSrc = "";
112
+ let embedSessionRefreshAttempts = 0;
110
113
 
111
114
  function esc(value) {
112
115
  return String(value ?? "")
@@ -242,9 +245,9 @@ export function embedApp(options = {}) {
242
245
  record.deepLinkUrl,
243
246
  record.deepLink,
244
247
  record.openUrl,
245
- record.url,
246
248
  structuredOpenLinkUrl,
247
- metaUrl
249
+ metaUrl,
250
+ record.url
248
251
  ]);
249
252
  }
250
253
 
@@ -297,6 +300,12 @@ export function embedApp(options = {}) {
297
300
  try { appFrame.contentWindow.postMessage(message, "*"); } catch {}
298
301
  }
299
302
 
303
+ function notifyOuterMcpAppReady() {
304
+ try {
305
+ window.parent.postMessage({ type: "agentNative.embeddedAppReady" }, "*");
306
+ } catch {}
307
+ }
308
+
300
309
  function nextWrapperRequestId() {
301
310
  wrapperRequestId += 1;
302
311
  return "mcp-wrapper-" + Date.now() + "-" + wrapperRequestId;
@@ -613,6 +622,21 @@ export function embedApp(options = {}) {
613
622
  );
614
623
  }
615
624
 
625
+ function importHeadChildrenWithBase(source, baseHref) {
626
+ const base = document.createElement("base");
627
+ base.href = baseHref;
628
+ const nodes = Array.from(source.childNodes).filter((node) => {
629
+ return !(
630
+ node.nodeType === 1 &&
631
+ String(node.nodeName || "").toLowerCase() === "base"
632
+ );
633
+ });
634
+ document.head.replaceChildren(
635
+ base,
636
+ ...nodes.map((node) => document.importNode(node, true))
637
+ );
638
+ }
639
+
616
640
  function isModuleScript(script) {
617
641
  return (script.getAttribute("type") || "").trim().toLowerCase() === "module";
618
642
  }
@@ -808,10 +832,7 @@ export function embedApp(options = {}) {
808
832
  );
809
833
  const scripts = Array.from(parsed.querySelectorAll("script"));
810
834
  copyDocumentElementAttributes(parsed.documentElement);
811
- importChildren(parsed.head, document.head);
812
- const base = document.createElement("base");
813
- base.href = config.baseHref;
814
- document.head.prepend(base);
835
+ importHeadChildrenWithBase(parsed.head, config.baseHref);
815
836
  importChildren(parsed.body, document.body);
816
837
  installExternalOpenControl(appUrl);
817
838
  for (const script of scripts) {
@@ -893,6 +914,7 @@ export function embedApp(options = {}) {
893
914
  window.history.replaceState(window.history.state, "", localPathFromUrl(appUrl, false));
894
915
  } catch {}
895
916
  await mountTransplantedHtml(html, appUrl);
917
+ embedSessionRefreshAttempts = 0;
896
918
  notifyHostHeightRepeatedly();
897
919
  }
898
920
 
@@ -1132,6 +1154,7 @@ export function embedApp(options = {}) {
1132
1154
  frame.addEventListener("load", () => {
1133
1155
  if (appFrame !== frame) return;
1134
1156
  clearFrameLoadTimer();
1157
+ notifyOuterMcpAppReady();
1135
1158
  sendFrameReadyMessages(frame);
1136
1159
  startFrameReadyTimer(frame);
1137
1160
  });
@@ -1150,6 +1173,13 @@ export function embedApp(options = {}) {
1150
1173
  renderFrameFallback();
1151
1174
  return;
1152
1175
  }
1176
+ if (embedSessionRefreshAttempts >= maxEmbedSessionRefreshAttempts) {
1177
+ renderAppLaunchError(
1178
+ "Embedded app session expired. Reopen the app to mint a fresh session."
1179
+ );
1180
+ return;
1181
+ }
1182
+ embedSessionRefreshAttempts += 1;
1153
1183
  openStartUrl = "";
1154
1184
  startedFor = "";
1155
1185
  lastFrameSrc = "";
@@ -1166,19 +1196,6 @@ export function embedApp(options = {}) {
1166
1196
  return true;
1167
1197
  }
1168
1198
 
1169
- // We have connected to a standards-track MCP Apps host (Codex, Cursor,
1170
- // Claude over the SDK, our own renderer, …) through the postMessage
1171
- // \`ui/*\` bridge rather than ChatGPT's \`window.openai\` global. These hosts
1172
- // render the resource in a strict sandboxed iframe (typically
1173
- // \`sandbox="allow-scripts"\`, opaque origin). Self-navigating that iframe to
1174
- // the real app origin tears down the host bridge and loses the opaque-origin
1175
- // auth context, which shows up as a permanent / flashing loading state.
1176
- // Transplanting the app document into the shell keeps the bridge alive and
1177
- // works under the opaque origin via embed-token auth, exactly like Claude.
1178
- function isNativeMcpAppsBridgeHost() {
1179
- return !!app && !openAiBridge;
1180
- }
1181
-
1182
1199
  function shouldTransplantAppDocument() {
1183
1200
  const render = renderModeSource();
1184
1201
  const mode = render.mode;
@@ -1188,7 +1205,6 @@ export function embedApp(options = {}) {
1188
1205
  return (
1189
1206
  isClaudeMcpContentHost() ||
1190
1207
  isChatGptSandboxHost() ||
1191
- isNativeMcpAppsBridgeHost() ||
1192
1208
  mode === "transplant" ||
1193
1209
  render.frame === "transplant"
1194
1210
  );
@@ -1213,10 +1229,29 @@ export function embedApp(options = {}) {
1213
1229
  }
1214
1230
 
1215
1231
  function shouldRenderControlledAppFrame() {
1216
- return !!openAiBridge || isChatGptSandboxHost();
1232
+ return !!openAiBridge || !!app || isChatGptSandboxHost();
1233
+ }
1234
+
1235
+ function shouldDirectRenderKnownAppRoute(src) {
1236
+ return !!app && !openAiBridge && !isEmbedStartUrl(src) && !shouldTransplantAppDocument();
1237
+ }
1238
+
1239
+ function isCurrentFrameUrl(src) {
1240
+ try {
1241
+ return new URL(src, window.location.href).href === window.location.href;
1242
+ } catch {
1243
+ return false;
1244
+ }
1217
1245
  }
1218
1246
 
1219
1247
  function navigateToAppFrame(src) {
1248
+ if (isCurrentFrameUrl(src)) {
1249
+ clearFrameReadyTimer();
1250
+ clearFrameLoadTimer();
1251
+ setMessage("App opened");
1252
+ notifyHostHeightRepeatedly();
1253
+ return;
1254
+ }
1220
1255
  clearFrameReadyTimer();
1221
1256
  clearFrameLoadTimer();
1222
1257
  appFrame = null;
@@ -1230,6 +1265,24 @@ export function embedApp(options = {}) {
1230
1265
  }
1231
1266
  }
1232
1267
 
1268
+ async function ensureHostAppConnected() {
1269
+ if (!app || typeof app.connect !== "function") return;
1270
+ if (!appConnectPromise) {
1271
+ appConnectPromise = Promise.resolve(app.connect())
1272
+ .then(async (value) => {
1273
+ // Let the host process ui/notifications/initialized before follow-up calls.
1274
+ await new Promise((resolve) => window.setTimeout(resolve, 0));
1275
+ await new Promise((resolve) => window.setTimeout(resolve, 0));
1276
+ return value;
1277
+ })
1278
+ .catch((err) => {
1279
+ appConnectPromise = null;
1280
+ throw err;
1281
+ });
1282
+ }
1283
+ await appConnectPromise;
1284
+ }
1285
+
1233
1286
  async function updateHostModelContext(data) {
1234
1287
  const params = {};
1235
1288
  if (Array.isArray(data && data.content)) params.content = data.content;
@@ -1244,6 +1297,7 @@ export function embedApp(options = {}) {
1244
1297
  return { ok: true };
1245
1298
  }
1246
1299
  if (!app || typeof app.updateModelContext !== "function") return { ok: false };
1300
+ await ensureHostAppConnected();
1247
1301
  await app.updateModelContext(params);
1248
1302
  return { ok: true };
1249
1303
  }
@@ -1329,6 +1383,7 @@ export function embedApp(options = {}) {
1329
1383
  agentNativeModelContext: modelContext
1330
1384
  });
1331
1385
  } else if (app && typeof app.updateModelContext === "function") {
1386
+ await ensureHostAppConnected();
1332
1387
  await app.updateModelContext(modelContext);
1333
1388
  }
1334
1389
  } catch (err) {
@@ -1345,6 +1400,7 @@ export function embedApp(options = {}) {
1345
1400
  }
1346
1401
  let result = null;
1347
1402
  if (app && typeof app.sendMessage === "function") {
1403
+ await ensureHostAppConnected();
1348
1404
  result = await app.sendMessage({
1349
1405
  role: "user",
1350
1406
  content
@@ -1385,8 +1441,10 @@ export function embedApp(options = {}) {
1385
1441
  const data = event.data.data || {};
1386
1442
  if (event.data.type === "agentNative.embeddedAppReady") {
1387
1443
  appFrameReady = true;
1444
+ embedSessionRefreshAttempts = 0;
1388
1445
  clearFrameLoadTimer();
1389
1446
  clearFrameReadyTimer();
1447
+ notifyOuterMcpAppReady();
1390
1448
  return;
1391
1449
  }
1392
1450
  if (event.data.type === "agentNative.embedSessionExpired") {
@@ -1427,7 +1485,7 @@ export function embedApp(options = {}) {
1427
1485
  }
1428
1486
 
1429
1487
  async function launchEmbed() {
1430
- const launchUrl = openStartUrl || openUrl;
1488
+ let launchUrl = openStartUrl || openUrl;
1431
1489
  if (!launchUrl) {
1432
1490
  renderAppLaunchError("Open link was not available.");
1433
1491
  return;
@@ -1436,11 +1494,11 @@ export function embedApp(options = {}) {
1436
1494
  setMessage("Ready to open.");
1437
1495
  return;
1438
1496
  }
1439
- if (startedFor === launchUrl) return;
1440
- startedFor = launchUrl;
1441
1497
  setMessage("Loading app");
1442
1498
  try {
1443
1499
  const selfNavigate = shouldSelfNavigateToApp();
1500
+ if (startedFor === launchUrl) return;
1501
+ startedFor = launchUrl;
1444
1502
  const embedUrl = withChatBridgeParam(launchUrl);
1445
1503
  if (selfNavigate && isEmbedStartUrl(embedUrl)) {
1446
1504
  if (shouldTransplantAppDocument()) {
@@ -1456,6 +1514,10 @@ export function embedApp(options = {}) {
1456
1514
  renderFrame(embedUrl);
1457
1515
  return;
1458
1516
  }
1517
+ if (shouldDirectRenderKnownAppRoute(embedUrl)) {
1518
+ renderFrame(embedUrl);
1519
+ return;
1520
+ }
1459
1521
  const result = await callEmbedSessionTool(embedSessionArgsFor(embedUrl));
1460
1522
  const data = parseToolResult(result);
1461
1523
  if (typeof data.startUrl !== "string" || !data.startUrl) {
@@ -1613,7 +1675,7 @@ export function embedApp(options = {}) {
1613
1675
 
1614
1676
  function createNativeMcpAppsBridge() {
1615
1677
  let rpcId = 0;
1616
- let connected = false;
1678
+ let connectPromise = null;
1617
1679
  let hostContext = {};
1618
1680
  const pendingRequests = new Map();
1619
1681
 
@@ -1681,26 +1743,32 @@ export function embedApp(options = {}) {
1681
1743
  return hostContext.protocolVersion || "mcp-apps-postmessage";
1682
1744
  },
1683
1745
  async connect() {
1684
- if (connected) return hostContext;
1685
- connected = true;
1686
- window.addEventListener("message", onMessage, { passive: true });
1687
- const result = await rpcRequest(
1688
- "ui/initialize",
1689
- {
1690
- appInfo: { name: "Agent Native Embed", version: "1.0.0" },
1691
- appCapabilities: {},
1692
- protocolVersion: "2026-01-26"
1693
- },
1694
- nativeBridgeInitializeTimeoutMs
1695
- );
1696
- hostContext = objectValue(result);
1697
- rpcNotify("ui/notifications/initialized", {});
1698
- if (typeof nativeApp.onhostcontextchanged === "function") {
1699
- nativeApp.onhostcontextchanged(hostContext);
1700
- }
1701
- return hostContext;
1746
+ if (connectPromise) return await connectPromise;
1747
+ connectPromise = (async () => {
1748
+ window.addEventListener("message", onMessage, { passive: true });
1749
+ const result = await rpcRequest(
1750
+ "ui/initialize",
1751
+ {
1752
+ appInfo: { name: "Agent Native Embed", version: "1.0.0" },
1753
+ appCapabilities: {},
1754
+ protocolVersion: "2026-01-26"
1755
+ },
1756
+ nativeBridgeInitializeTimeoutMs
1757
+ );
1758
+ hostContext = objectValue(result);
1759
+ rpcNotify("ui/notifications/initialized", {});
1760
+ if (typeof nativeApp.onhostcontextchanged === "function") {
1761
+ nativeApp.onhostcontextchanged(hostContext);
1762
+ }
1763
+ return hostContext;
1764
+ })().catch((err) => {
1765
+ connectPromise = null;
1766
+ throw err;
1767
+ });
1768
+ return await connectPromise;
1702
1769
  },
1703
1770
  async callServerTool(request) {
1771
+ await nativeApp.connect();
1704
1772
  const record = objectValue(request);
1705
1773
  return await rpcRequest("tools/call", {
1706
1774
  name: record.name,
@@ -1708,6 +1776,7 @@ export function embedApp(options = {}) {
1708
1776
  });
1709
1777
  },
1710
1778
  async updateModelContext(params) {
1779
+ await nativeApp.connect();
1711
1780
  return await rpcRequest("ui/update-model-context", objectValue(params));
1712
1781
  },
1713
1782
  async openLink(params) {
@@ -1722,12 +1791,14 @@ export function embedApp(options = {}) {
1722
1791
  return opened ? { ok: true } : { isError: true };
1723
1792
  },
1724
1793
  async requestDisplayMode(params) {
1794
+ await nativeApp.connect();
1725
1795
  return await rpcRequest("ui/request-display-mode", objectValue(params));
1726
1796
  },
1727
1797
  sendSizeChanged(params) {
1728
1798
  rpcNotify("ui/notifications/size-changed", objectValue(params));
1729
1799
  },
1730
1800
  async sendMessage(params) {
1801
+ await nativeApp.connect();
1731
1802
  return await rpcRequest("ui/message", objectValue(params));
1732
1803
  }
1733
1804
  };
@@ -1771,6 +1842,7 @@ export function embedApp(options = {}) {
1771
1842
 
1772
1843
  async function startNativeMcpAppsBridge() {
1773
1844
  app = createNativeMcpAppsBridge();
1845
+ appConnectPromise = null;
1774
1846
  app.ontoolinput = (params) => {
1775
1847
  toolInput = params.arguments || {};
1776
1848
  };
@@ -1788,7 +1860,8 @@ export function embedApp(options = {}) {
1788
1860
  notifyHostHeight();
1789
1861
  sendHostContext();
1790
1862
  };
1791
- await app.connect();
1863
+ await ensureHostAppConnected();
1864
+ notifyOuterMcpAppReady();
1792
1865
  updateDisplayButton();
1793
1866
  notifyHostHeight();
1794
1867
  sendHostContext();
@@ -1801,6 +1874,7 @@ export function embedApp(options = {}) {
1801
1874
  {},
1802
1875
  { autoResize: false }
1803
1876
  );
1877
+ appConnectPromise = null;
1804
1878
  app.ontoolinput = (params) => {
1805
1879
  toolInput = params.arguments || {};
1806
1880
  };
@@ -1818,7 +1892,8 @@ export function embedApp(options = {}) {
1818
1892
  notifyHostHeight();
1819
1893
  sendHostContext();
1820
1894
  };
1821
- await app.connect();
1895
+ await ensureHostAppConnected();
1896
+ notifyOuterMcpAppReady();
1822
1897
  updateDisplayButton();
1823
1898
  notifyHostHeight();
1824
1899
  sendHostContext();