@agent-native/core 0.22.19 → 0.22.20

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 (47) hide show
  1. package/dist/client/embed-auth.d.ts.map +1 -1
  2. package/dist/client/embed-auth.js +85 -3
  3. package/dist/client/embed-auth.js.map +1 -1
  4. package/dist/client/mcp-apps/McpAppRenderer.d.ts +3 -0
  5. package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -1
  6. package/dist/client/mcp-apps/McpAppRenderer.js +86 -9
  7. package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -1
  8. package/dist/deploy/build.d.ts.map +1 -1
  9. package/dist/deploy/build.js +73 -5
  10. package/dist/deploy/build.js.map +1 -1
  11. package/dist/mcp/build-server.d.ts.map +1 -1
  12. package/dist/mcp/build-server.js +40 -3
  13. package/dist/mcp/build-server.js.map +1 -1
  14. package/dist/mcp/builtin-tools.d.ts.map +1 -1
  15. package/dist/mcp/builtin-tools.js +6 -3
  16. package/dist/mcp/builtin-tools.js.map +1 -1
  17. package/dist/mcp/embed-app.d.ts +2 -2
  18. package/dist/mcp/embed-app.d.ts.map +1 -1
  19. package/dist/mcp/embed-app.js +390 -17
  20. package/dist/mcp/embed-app.js.map +1 -1
  21. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  22. package/dist/server/core-routes-plugin.js +37 -10
  23. package/dist/server/core-routes-plugin.js.map +1 -1
  24. package/dist/server/create-server.d.ts.map +1 -1
  25. package/dist/server/create-server.js +21 -7
  26. package/dist/server/create-server.js.map +1 -1
  27. package/dist/server/embed-route.d.ts.map +1 -1
  28. package/dist/server/embed-route.js +62 -21
  29. package/dist/server/embed-route.js.map +1 -1
  30. package/dist/server/security-headers.d.ts.map +1 -1
  31. package/dist/server/security-headers.js +9 -1
  32. package/dist/server/security-headers.js.map +1 -1
  33. package/dist/server/ssr-handler.d.ts +2 -0
  34. package/dist/server/ssr-handler.d.ts.map +1 -1
  35. package/dist/server/ssr-handler.js +66 -11
  36. package/dist/server/ssr-handler.js.map +1 -1
  37. package/dist/shared/mcp-embed-headers.d.ts +12 -0
  38. package/dist/shared/mcp-embed-headers.d.ts.map +1 -0
  39. package/dist/shared/mcp-embed-headers.js +51 -0
  40. package/dist/shared/mcp-embed-headers.js.map +1 -0
  41. package/dist/vite/client.d.ts.map +1 -1
  42. package/dist/vite/client.js +23 -0
  43. package/dist/vite/client.js.map +1 -1
  44. package/docs/content/actions.md +15 -5
  45. package/docs/content/external-agents.md +53 -27
  46. package/docs/content/mcp-protocol.md +29 -4
  47. package/package.json +1 -1
@@ -2,8 +2,8 @@ import { MCP_APP_CHAT_BRIDGE_QUERY_PARAM } from "../shared/embed-auth.js";
2
2
  const MCP_APP_IMPORT = "https://esm.sh/@modelcontextprotocol/ext-apps@1.7.2/app-with-deps";
3
3
  export const MCP_APP_REQUEST_ORIGIN_CSP_SOURCE = "$requestOrigin";
4
4
  const MCP_APP_WRAPPER_CHROME_HEIGHT = 44;
5
- export const DEFAULT_MCP_APP_VIEWPORT_HEIGHT = 720;
6
- export const DEFAULT_MCP_APP_SHELL_HEIGHT = DEFAULT_MCP_APP_VIEWPORT_HEIGHT + MCP_APP_WRAPPER_CHROME_HEIGHT;
5
+ export const DEFAULT_MCP_APP_SHELL_HEIGHT = 560;
6
+ export const DEFAULT_MCP_APP_VIEWPORT_HEIGHT = DEFAULT_MCP_APP_SHELL_HEIGHT - MCP_APP_WRAPPER_CHROME_HEIGHT;
7
7
  function attr(value) {
8
8
  return String(value ?? "")
9
9
  .replace(/&/g, "&")
@@ -19,6 +19,10 @@ export function embedApp(options = {}) {
19
19
  const embedByDefault = options.embedByDefault !== false;
20
20
  const height = Math.max(320, Math.min(900, options.height ?? DEFAULT_MCP_APP_SHELL_HEIGHT));
21
21
  const viewportHeight = height - MCP_APP_WRAPPER_CHROME_HEIGHT;
22
+ const frameDomains = [
23
+ MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,
24
+ ...(options.frameDomains ?? []),
25
+ ];
22
26
  return {
23
27
  title,
24
28
  ...(options.description ? { description: options.description } : {}),
@@ -28,19 +32,19 @@ export function embedApp(options = {}) {
28
32
  <meta charset="utf-8">
29
33
  <meta name="viewport" content="width=device-width, initial-scale=1">
30
34
  <style>
31
- :root { color-scheme: light dark; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: Canvas; color: CanvasText; }
35
+ :root { color-scheme: light dark; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: Canvas; color: CanvasText; --agent-native-shell-height: ${height}px; --agent-native-viewport-height: ${viewportHeight}px; }
32
36
  * { box-sizing: border-box; }
33
37
  body { margin: 0; }
34
- .shell { display: grid; gap: 8px; min-height: ${height}px; padding: 0; }
38
+ .shell { display: grid; gap: 8px; min-height: var(--agent-native-shell-height); padding: 0; }
35
39
  .bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 36px; padding: 6px 8px; border-bottom: 1px solid color-mix(in srgb, CanvasText 12%, Canvas); }
36
40
  .title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 700; color: color-mix(in srgb, CanvasText 72%, Canvas); }
37
41
  .actions { display: flex; align-items: center; gap: 6px; }
38
42
  button { min-height: 28px; border: 1px solid color-mix(in srgb, CanvasText 14%, Canvas); border-radius: 7px; background: Canvas; color: CanvasText; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; padding: 0 9px; }
39
43
  button:disabled { opacity: .55; cursor: default; }
40
- .stage { position: relative; min-height: ${viewportHeight}px; }
41
- iframe { display: block; width: 100%; height: ${viewportHeight}px; border: 0; background: Canvas; }
42
- .message { display: grid; place-items: center; min-height: ${viewportHeight}px; padding: 18px; color: color-mix(in srgb, CanvasText 62%, Canvas); font-size: 13px; line-height: 1.45; text-align: center; }
43
- .fallback { display: grid; align-content: center; justify-items: center; gap: 12px; min-height: ${viewportHeight}px; padding: 24px; background: Canvas; color: CanvasText; text-align: center; }
44
+ .stage { position: relative; min-height: var(--agent-native-viewport-height); }
45
+ iframe { display: block; width: 100%; height: var(--agent-native-viewport-height); border: 0; background: Canvas; }
46
+ .message { display: grid; place-items: center; min-height: var(--agent-native-viewport-height); padding: 18px; color: color-mix(in srgb, CanvasText 62%, Canvas); font-size: 13px; line-height: 1.45; text-align: center; }
47
+ .fallback { display: grid; align-content: center; justify-items: center; gap: 12px; min-height: var(--agent-native-viewport-height); padding: 24px; background: Canvas; color: CanvasText; text-align: center; }
44
48
  .fallback-title { max-width: 440px; font-size: 14px; font-weight: 700; }
45
49
  .fallback-copy { max-width: 520px; color: color-mix(in srgb, CanvasText 64%, Canvas); font-size: 13px; line-height: 1.45; }
46
50
  .fallback-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px; }
@@ -75,7 +79,8 @@ export function embedApp(options = {}) {
75
79
  const startTool = body.dataset.startTool || "create_embed_session";
76
80
  const embedByDefault = body.dataset.embedDefault !== "0";
77
81
  const chatBridgeParam = ${JSON.stringify(MCP_APP_CHAT_BRIDGE_QUERY_PARAM)};
78
- const intrinsicHeight = ${height};
82
+ const defaultIntrinsicHeight = ${height};
83
+ const chromeHeight = ${MCP_APP_WRAPPER_CHROME_HEIGHT};
79
84
  let app = null;
80
85
  let openAiBridge = null;
81
86
  let toolInput = {};
@@ -107,6 +112,40 @@ export function embedApp(options = {}) {
107
112
  : {};
108
113
  }
109
114
 
115
+ function finiteNumber(value) {
116
+ return typeof value === "number" && Number.isFinite(value) && value > 0
117
+ ? value
118
+ : null;
119
+ }
120
+
121
+ function contextMaxHeight(context) {
122
+ if (!context || typeof context !== "object") return null;
123
+ return finiteNumber(context.maxHeight) ||
124
+ finiteNumber(context.containerDimensions && context.containerDimensions.maxHeight);
125
+ }
126
+
127
+ function visibleIntrinsicHeight() {
128
+ const context = hostState().context || {};
129
+ const hostMaxHeight = contextMaxHeight(context);
130
+ if (hostMaxHeight) return Math.floor(hostMaxHeight);
131
+ const viewportHeight = finiteNumber(window.visualViewport && window.visualViewport.height) ||
132
+ finiteNumber(window.innerHeight);
133
+ return Math.floor(viewportHeight || defaultIntrinsicHeight);
134
+ }
135
+
136
+ function applyIntrinsicHeight(nextHeight) {
137
+ const boundedHeight = Math.min(
138
+ defaultIntrinsicHeight,
139
+ Math.floor(nextHeight || defaultIntrinsicHeight)
140
+ );
141
+ const height = Math.max(320, boundedHeight);
142
+ const viewportHeight = Math.max(0, height - chromeHeight);
143
+ document.documentElement.style.setProperty("--agent-native-shell-height", height + "px");
144
+ document.documentElement.style.setProperty("--agent-native-viewport-height", viewportHeight + "px");
145
+ if (appFrame) appFrame.style.height = viewportHeight + "px";
146
+ return height;
147
+ }
148
+
110
149
  function parseToolResult(params) {
111
150
  if (!params) return {};
112
151
  if (params.result && typeof params.result === "object") {
@@ -188,6 +227,270 @@ export function embedApp(options = {}) {
188
227
  }
189
228
  }
190
229
 
230
+ function isEmbedStartUrl(value) {
231
+ if (typeof value !== "string" || !value) return false;
232
+ try {
233
+ const url = new URL(value, window.location.href);
234
+ return /\\/_agent-native\\/embed\\/start$/.test(url.pathname);
235
+ } catch {
236
+ return false;
237
+ }
238
+ }
239
+
240
+ function localPathFromUrl(url, includeToken) {
241
+ const next = new URL(url.href);
242
+ if (!includeToken) next.searchParams.delete("__an_embed_token");
243
+ return next.pathname + next.search + next.hash;
244
+ }
245
+
246
+ function rewriteRootRelativeHtmlUrls(html, appOrigin) {
247
+ return String(html).replace(
248
+ /\\b(src|href|poster|action)\\s*=\\s*(["'])\\/(?!\\/)/gi,
249
+ (_match, name, quote) => String(name) + "=" + quote + appOrigin + "/"
250
+ );
251
+ }
252
+
253
+ function removeHtmlCspMeta(html) {
254
+ return String(html).replace(
255
+ /<meta\\s+[^>]*http-equiv\\s*=\\s*(["'])?content-security-policy\\1?[^>]*>/gi,
256
+ ""
257
+ );
258
+ }
259
+
260
+ function embedConfigForAppUrl(appUrl) {
261
+ const sanitizedTarget = localPathFromUrl(appUrl, false);
262
+ return {
263
+ origin: appUrl.origin,
264
+ href: appUrl.href,
265
+ baseHref: appUrl.origin + appUrl.pathname,
266
+ target: sanitizedTarget,
267
+ token: appUrl.searchParams.get("__an_embed_token") || "",
268
+ chatBridgeActive: appUrl.searchParams.get(chatBridgeParam) === "1",
269
+ chatBridgeParam,
270
+ embedTokenParam: "__an_embed_token",
271
+ embedTargetHeader: "x-agent-native-embed-target"
272
+ };
273
+ }
274
+
275
+ function installExternalEmbedRuntime(config) {
276
+ window.__AGENT_NATIVE_EXTERNAL_EMBED = config;
277
+ try {
278
+ if (config.target) {
279
+ window.history.replaceState(window.history.state, "", config.target);
280
+ }
281
+ } catch (_err) {}
282
+ try {
283
+ if (config.token) {
284
+ sessionStorage.setItem("agent-native:embed-auth-token", config.token);
285
+ }
286
+ if (config.chatBridgeActive && config.token) {
287
+ sessionStorage.setItem("agent-native:mcp-chat-bridge", config.token);
288
+ }
289
+ } catch (_err) {}
290
+ if (window.__agentNativeExternalEmbedRuntimeInstalled) return;
291
+ window.__agentNativeExternalEmbedRuntimeInstalled = true;
292
+ function appOrigin() {
293
+ try {
294
+ return new URL(config.origin).origin;
295
+ } catch (_err) {
296
+ return "";
297
+ }
298
+ }
299
+ function targetPath() {
300
+ return config.target || location.pathname + location.search;
301
+ }
302
+ function rewrittenUrl(value, appendToken) {
303
+ const origin = appOrigin();
304
+ if (!origin) return null;
305
+ let url;
306
+ try {
307
+ url = new URL(value, location.href);
308
+ } catch (_err) {
309
+ return null;
310
+ }
311
+ if (url.origin !== location.origin && url.origin !== origin) return null;
312
+ if (url.origin !== origin) {
313
+ const app = new URL(origin);
314
+ url.protocol = app.protocol;
315
+ url.host = app.host;
316
+ }
317
+ if (appendToken && config.token && url.pathname === "/_agent-native/events") {
318
+ url.searchParams.set(config.embedTokenParam, config.token);
319
+ }
320
+ return url.toString();
321
+ }
322
+ function authHeaders(input, init) {
323
+ const headers = new Headers(
324
+ init && init.headers ? init.headers : input instanceof Request ? input.headers : undefined
325
+ );
326
+ if (config.token && !headers.has("Authorization")) {
327
+ headers.set("Authorization", "Bearer " + config.token);
328
+ }
329
+ if (!headers.has(config.embedTargetHeader)) {
330
+ headers.set(config.embedTargetHeader, targetPath());
331
+ }
332
+ return headers;
333
+ }
334
+ if (typeof fetch === "function") {
335
+ const originalFetch = fetch.bind(window);
336
+ window.fetch = function(input, init) {
337
+ const raw = input instanceof Request ? input.url : String(input);
338
+ const url = rewrittenUrl(raw, false);
339
+ if (!url) return originalFetch(input, init);
340
+ const nextInit = Object.assign({}, init || {}, {
341
+ headers: authHeaders(input, init),
342
+ credentials: "omit"
343
+ });
344
+ if (input instanceof Request) {
345
+ return originalFetch(new Request(url, input), nextInit);
346
+ }
347
+ return originalFetch(url, nextInit);
348
+ };
349
+ }
350
+ if (typeof XMLHttpRequest !== "undefined") {
351
+ const originalOpen = XMLHttpRequest.prototype.open;
352
+ const originalSend = XMLHttpRequest.prototype.send;
353
+ XMLHttpRequest.prototype.open = function(method, url) {
354
+ const rewritten = rewrittenUrl(url, false);
355
+ this.__agentNativeExternalEmbed = !!rewritten;
356
+ return originalOpen.call(
357
+ this,
358
+ method,
359
+ rewritten || url,
360
+ arguments.length > 2 ? arguments[2] : true,
361
+ arguments[3],
362
+ arguments[4]
363
+ );
364
+ };
365
+ XMLHttpRequest.prototype.send = function(body) {
366
+ if (this.__agentNativeExternalEmbed) {
367
+ try {
368
+ if (config.token) this.setRequestHeader("Authorization", "Bearer " + config.token);
369
+ this.setRequestHeader(config.embedTargetHeader, targetPath());
370
+ } catch (_err) {}
371
+ }
372
+ return originalSend.call(this, body);
373
+ };
374
+ }
375
+ if (typeof EventSource !== "undefined") {
376
+ const OriginalEventSource = EventSource;
377
+ window.EventSource = function(url, options) {
378
+ return new OriginalEventSource(rewrittenUrl(url, true) || url, options);
379
+ };
380
+ window.EventSource.prototype = OriginalEventSource.prototype;
381
+ }
382
+ }
383
+
384
+ function copyDocumentElementAttributes(source) {
385
+ const target = document.documentElement;
386
+ for (const attr of Array.from(target.attributes)) {
387
+ target.removeAttribute(attr.name);
388
+ }
389
+ for (const attr of Array.from(source.attributes)) {
390
+ target.setAttribute(attr.name, attr.value);
391
+ }
392
+ }
393
+
394
+ function importChildren(source, target) {
395
+ target.replaceChildren(
396
+ ...Array.from(source.childNodes).map((node) => document.importNode(node, true))
397
+ );
398
+ }
399
+
400
+ function isModuleScript(script) {
401
+ return (script.getAttribute("type") || "").trim().toLowerCase() === "module";
402
+ }
403
+
404
+ function isRunnableClassicScript(script) {
405
+ const type = (script.getAttribute("type") || "").trim().toLowerCase();
406
+ return !type || type === "text/javascript" || type === "application/javascript";
407
+ }
408
+
409
+ function runClassicScript(script) {
410
+ const next = document.createElement("script");
411
+ for (const attr of Array.from(script.attributes)) {
412
+ if (attr.name === "type") continue;
413
+ next.setAttribute(attr.name, attr.value);
414
+ }
415
+ if (script.src) {
416
+ next.src = script.src;
417
+ } else {
418
+ next.textContent = script.textContent || "";
419
+ }
420
+ document.body.appendChild(next);
421
+ next.remove();
422
+ }
423
+
424
+ function rootRelativeSpecifiersToAbsolute(code, appOrigin) {
425
+ return String(code).replace(/(["'])\\/(?!\\/)/g, "$1" + appOrigin + "/");
426
+ }
427
+
428
+ function moduleCodeToClassicAsync(code, appOrigin) {
429
+ return rootRelativeSpecifiersToAbsolute(code, appOrigin)
430
+ .replace(
431
+ /\\bimport\\s+\\*\\s+as\\s+([A-Za-z_$][\\w$]*)\\s+from\\s+(["'][^"']+["'])\\s*;?/g,
432
+ "const $1 = await import($2);"
433
+ )
434
+ .replace(/\\bimport\\s+(["'][^"']+["'])\\s*;?/g, "await import($1);")
435
+ .replace(/\\bimport\\((["'][^"']+["'])\\)\\s*;?/g, "await import($1);");
436
+ }
437
+
438
+ function runModuleScriptAsClassic(script, appOrigin) {
439
+ const code = moduleCodeToClassicAsync(script.textContent || "", appOrigin);
440
+ const runner = document.createElement("script");
441
+ runner.textContent =
442
+ "(async()=>{" +
443
+ code +
444
+ "})().catch((err)=>{console.error('[agent-native] transplanted app module failed',err);document.body.setAttribute('data-agent-native-hydration-error',String(err&&err.message||err));});";
445
+ document.body.appendChild(runner);
446
+ runner.remove();
447
+ }
448
+
449
+ function mountTransplantedHtml(html, appUrl) {
450
+ const config = embedConfigForAppUrl(appUrl);
451
+ installExternalEmbedRuntime(config);
452
+ const parsed = new DOMParser().parseFromString(
453
+ rewriteRootRelativeHtmlUrls(removeHtmlCspMeta(html), appUrl.origin),
454
+ "text/html"
455
+ );
456
+ const scripts = Array.from(parsed.querySelectorAll("script"));
457
+ copyDocumentElementAttributes(parsed.documentElement);
458
+ importChildren(parsed.head, document.head);
459
+ const base = document.createElement("base");
460
+ base.href = config.baseHref;
461
+ document.head.prepend(base);
462
+ importChildren(parsed.body, document.body);
463
+ for (const script of scripts) {
464
+ if (isRunnableClassicScript(script)) runClassicScript(script);
465
+ }
466
+ for (const script of scripts) {
467
+ if (isModuleScript(script)) runModuleScriptAsClassic(script, appUrl.origin);
468
+ }
469
+ }
470
+
471
+ async function transplantAppDocument(src) {
472
+ clearFrameReadyTimer();
473
+ clearFrameLoadTimer();
474
+ appFrame = null;
475
+ lastFrameSrc = src;
476
+ setMessage("Loading app");
477
+ const response = await fetch(src, {
478
+ credentials: "omit",
479
+ redirect: "follow",
480
+ headers: { Accept: "text/html" }
481
+ });
482
+ if (!response.ok) {
483
+ throw new Error("Embedded app returned HTTP " + response.status + ".");
484
+ }
485
+ const html = await response.text();
486
+ const appUrl = new URL(response.url || src);
487
+ try {
488
+ window.history.replaceState(window.history.state, "", localPathFromUrl(appUrl, false));
489
+ } catch {}
490
+ mountTransplantedHtml(html, appUrl);
491
+ notifyHostHeightRepeatedly();
492
+ }
493
+
191
494
  function wantsEmbed() {
192
495
  if (toolInput.embed === false || toolInput.embed === "false") return false;
193
496
  if (embedByDefault) return true;
@@ -336,6 +639,28 @@ export function embedApp(options = {}) {
336
639
  return true;
337
640
  }
338
641
 
642
+ function isClaudeMcpContentHost() {
643
+ try {
644
+ return /(^|\\.)claudemcpcontent\\.com$/i.test(window.location.hostname || "");
645
+ } catch {
646
+ return false;
647
+ }
648
+ }
649
+
650
+ function isChatGptSandboxHost() {
651
+ try {
652
+ const host = window.location.hostname || "";
653
+ const appParam = new URL(window.location.href).searchParams.get("app");
654
+ return /(^|\\.)oaiusercontent\\.com$/i.test(host) || appParam === "chatgpt";
655
+ } catch {
656
+ return false;
657
+ }
658
+ }
659
+
660
+ function shouldRenderControlledAppFrame() {
661
+ return !!openAiBridge || isChatGptSandboxHost();
662
+ }
663
+
339
664
  function navigateToAppFrame(src) {
340
665
  clearFrameReadyTimer();
341
666
  clearFrameLoadTimer();
@@ -382,11 +707,19 @@ export function embedApp(options = {}) {
382
707
  }
383
708
 
384
709
  function notifyHostHeight() {
710
+ const height = applyIntrinsicHeight(visibleIntrinsicHeight());
385
711
  if (!openAiBridge || typeof openAiBridge.notifyIntrinsicHeight !== "function") {
712
+ if (app && typeof app.sendSizeChanged === "function") {
713
+ try {
714
+ app.sendSizeChanged({ height });
715
+ } catch (err) {
716
+ console.warn("[agent-native] MCP host rejected size update", err);
717
+ }
718
+ }
386
719
  return;
387
720
  }
388
721
  try {
389
- openAiBridge.notifyIntrinsicHeight({ height: intrinsicHeight });
722
+ openAiBridge.notifyIntrinsicHeight({ height });
390
723
  } catch (err) {
391
724
  console.warn("[agent-native] ChatGPT rejected intrinsic height update", err);
392
725
  }
@@ -482,6 +815,22 @@ export function embedApp(options = {}) {
482
815
  }
483
816
  });
484
817
 
818
+ function notifyHostHeightSoon() {
819
+ requestAnimationFrame(() => notifyHostHeight());
820
+ }
821
+
822
+ function notifyHostHeightRepeatedly() {
823
+ notifyHostHeight();
824
+ [0, 250, 1000, 2500].forEach((delay) => {
825
+ setTimeout(() => notifyHostHeight(), delay);
826
+ });
827
+ }
828
+
829
+ window.addEventListener("resize", notifyHostHeightSoon, { passive: true });
830
+ if (window.visualViewport) {
831
+ window.visualViewport.addEventListener("resize", notifyHostHeightSoon, { passive: true });
832
+ }
833
+
485
834
  async function launchEmbed() {
486
835
  if (!openUrl) {
487
836
  setMessage("Open link was not available.");
@@ -497,6 +846,20 @@ export function embedApp(options = {}) {
497
846
  try {
498
847
  const selfNavigate = shouldSelfNavigateToApp();
499
848
  const embedUrl = withChatBridgeParam(openUrl);
849
+ if (selfNavigate && isEmbedStartUrl(embedUrl)) {
850
+ if (isClaudeMcpContentHost()) {
851
+ await transplantAppDocument(embedUrl);
852
+ } else if (shouldRenderControlledAppFrame()) {
853
+ renderFrame(embedUrl);
854
+ } else {
855
+ navigateToAppFrame(embedUrl);
856
+ }
857
+ return;
858
+ }
859
+ if (!selfNavigate && isEmbedStartUrl(embedUrl)) {
860
+ renderFrame(embedUrl);
861
+ return;
862
+ }
500
863
  const result = await callEmbedSessionTool({
501
864
  url: embedUrl,
502
865
  chrome: typeof toolInput.chrome === "string" ? toolInput.chrome : "full"
@@ -508,7 +871,13 @@ export function embedApp(options = {}) {
508
871
  return;
509
872
  }
510
873
  if (selfNavigate) {
511
- navigateToAppFrame(data.startUrl);
874
+ if (isClaudeMcpContentHost()) {
875
+ await transplantAppDocument(data.startUrl);
876
+ } else if (shouldRenderControlledAppFrame()) {
877
+ renderFrame(data.startUrl);
878
+ } else {
879
+ navigateToAppFrame(data.startUrl);
880
+ }
512
881
  } else {
513
882
  renderFrame(data.startUrl);
514
883
  }
@@ -618,7 +987,11 @@ export function embedApp(options = {}) {
618
987
 
619
988
  async function startMcpAppsBridge() {
620
989
  const { App } = await import("${MCP_APP_IMPORT}");
621
- app = new App({ name: "Agent Native Embed", version: "1.0.0" }, {});
990
+ app = new App(
991
+ { name: "Agent Native Embed", version: "1.0.0" },
992
+ {},
993
+ { autoResize: false }
994
+ );
622
995
  app.ontoolinput = (params) => {
623
996
  toolInput = params.arguments || {};
624
997
  };
@@ -631,10 +1004,12 @@ export function embedApp(options = {}) {
631
1004
  };
632
1005
  app.onhostcontextchanged = () => {
633
1006
  updateDisplayButton();
1007
+ notifyHostHeight();
634
1008
  sendHostContext();
635
1009
  };
636
1010
  await app.connect();
637
1011
  updateDisplayButton();
1012
+ notifyHostHeight();
638
1013
  sendHostContext();
639
1014
  }
640
1015
 
@@ -646,16 +1021,14 @@ export function embedApp(options = {}) {
646
1021
  </body>
647
1022
  </html>`,
648
1023
  csp: {
649
- connectDomains: ["https://esm.sh"],
1024
+ connectDomains: ["https://esm.sh", MCP_APP_REQUEST_ORIGIN_CSP_SOURCE],
650
1025
  resourceDomains: [
651
1026
  "https://esm.sh",
652
1027
  MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,
653
1028
  ...(options.frameDomains ?? []),
654
1029
  ],
655
- frameDomains: [
656
- MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,
657
- ...(options.frameDomains ?? []),
658
- ],
1030
+ baseUriDomains: [MCP_APP_REQUEST_ORIGIN_CSP_SOURCE],
1031
+ frameDomains,
659
1032
  },
660
1033
  prefersBorder: false,
661
1034
  };