@mcp-ts/sdk 1.3.10 → 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.
Files changed (44) hide show
  1. package/dist/adapters/langchain-adapter.js.map +1 -1
  2. package/dist/adapters/langchain-adapter.mjs.map +1 -1
  3. package/dist/client/index.d.mts +3 -189
  4. package/dist/client/index.d.ts +3 -189
  5. package/dist/client/index.js +218 -54
  6. package/dist/client/index.js.map +1 -1
  7. package/dist/client/index.mjs +215 -55
  8. package/dist/client/index.mjs.map +1 -1
  9. package/dist/client/react.d.mts +21 -14
  10. package/dist/client/react.d.ts +21 -14
  11. package/dist/client/react.js +402 -83
  12. package/dist/client/react.js.map +1 -1
  13. package/dist/client/react.mjs +400 -85
  14. package/dist/client/react.mjs.map +1 -1
  15. package/dist/client/vue.d.mts +3 -2
  16. package/dist/client/vue.d.ts +3 -2
  17. package/dist/client/vue.js +239 -63
  18. package/dist/client/vue.js.map +1 -1
  19. package/dist/client/vue.mjs +236 -64
  20. package/dist/client/vue.mjs.map +1 -1
  21. package/dist/index-CQr9q0bF.d.mts +295 -0
  22. package/dist/index-nE_7Io0I.d.ts +295 -0
  23. package/dist/index.d.mts +2 -1
  24. package/dist/index.d.ts +2 -1
  25. package/dist/index.js +237 -58
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +230 -59
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/server/index.js +15 -4
  30. package/dist/server/index.js.map +1 -1
  31. package/dist/server/index.mjs +15 -4
  32. package/dist/server/index.mjs.map +1 -1
  33. package/package.json +13 -11
  34. package/src/adapters/langchain-adapter.ts +1 -1
  35. package/src/client/core/app-host.ts +252 -65
  36. package/src/client/core/constants.ts +30 -0
  37. package/src/client/index.ts +6 -1
  38. package/src/client/react/index.ts +1 -0
  39. package/src/client/react/use-app-host.ts +8 -15
  40. package/src/client/react/use-mcp-apps.tsx +221 -26
  41. package/src/client/react/use-mcp.ts +23 -12
  42. package/src/client/utils/app-host-utils.ts +62 -0
  43. package/src/client/vue/use-mcp.ts +23 -12
  44. package/src/server/mcp/oauth-client.ts +31 -8
@@ -252,22 +252,88 @@ var SSEClient = class {
252
252
  }
253
253
  }
254
254
  };
255
- var HOST_INFO = { name: "mcp-ts-host", version: "1.0.0" };
256
- var SANDBOX_PERMISSIONS = [
257
- "allow-scripts",
258
- // Required for app JavaScript execution
259
- "allow-forms",
260
- // Required for form submissions
261
- "allow-same-origin",
262
- // Required for Blob URL correctness
263
- "allow-modals",
264
- // Required for dialogs/alerts
265
- "allow-popups",
266
- // Required for opening links
267
- "allow-downloads"
268
- // Required for file downloads
269
- ].join(" ");
270
- var MCP_URI_SCHEMES = ["ui://", "mcp-app://"];
255
+
256
+ // src/client/core/constants.ts
257
+ var SANDBOX_PROXY_READY_METHOD = "ui/notifications/sandbox-proxy-ready";
258
+ var SANDBOX_RESOURCE_READY_METHOD = "ui/notifications/sandbox-resource-ready";
259
+ var APP_HOST_DEFAULTS = {
260
+ /** Default timeout for waiting for the sandbox proxy to be ready (ms). */
261
+ SANDBOX_TIMEOUT_MS: 1e4,
262
+ /** Default host info reported to guest apps. */
263
+ HOST_INFO: { name: "mcp-ts-host", version: "1.0.0" },
264
+ /** Supported MCP App URI schemes. */
265
+ URI_SCHEMES: ["ui://", "mcp-app://"],
266
+ /** Default theme for the host context. */
267
+ THEME: "dark",
268
+ /** Default platform for the host context. */
269
+ PLATFORM: "web",
270
+ /** Default max height for the iframe container (px). */
271
+ MAX_HEIGHT: 6e3
272
+ };
273
+
274
+ // src/client/utils/app-host-utils.ts
275
+ var DEFAULT_SANDBOX_TIMEOUT_MS = APP_HOST_DEFAULTS.SANDBOX_TIMEOUT_MS;
276
+ async function setupSandboxProxyIframe(iframe, sandboxProxyUrl) {
277
+ iframe.style.width = "100%";
278
+ iframe.style.height = "100%";
279
+ iframe.style.border = "none";
280
+ iframe.style.backgroundColor = "transparent";
281
+ iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-downloads");
282
+ const onReady = new Promise((resolve, reject) => {
283
+ let settled = false;
284
+ const cleanup = () => {
285
+ window.removeEventListener("message", messageListener);
286
+ iframe.removeEventListener("error", errorListener);
287
+ };
288
+ const timeoutId = setTimeout(() => {
289
+ if (!settled) {
290
+ settled = true;
291
+ cleanup();
292
+ reject(new Error("Timed out waiting for sandbox proxy iframe to be ready"));
293
+ }
294
+ }, DEFAULT_SANDBOX_TIMEOUT_MS);
295
+ const messageListener = (event) => {
296
+ if (event.source === iframe.contentWindow) {
297
+ if (event.data?.method === SANDBOX_PROXY_READY_METHOD) {
298
+ if (!settled) {
299
+ settled = true;
300
+ clearTimeout(timeoutId);
301
+ cleanup();
302
+ resolve();
303
+ }
304
+ }
305
+ }
306
+ };
307
+ const errorListener = () => {
308
+ if (!settled) {
309
+ settled = true;
310
+ clearTimeout(timeoutId);
311
+ cleanup();
312
+ reject(new Error("Failed to load sandbox proxy iframe"));
313
+ }
314
+ };
315
+ window.addEventListener("message", messageListener);
316
+ iframe.addEventListener("error", errorListener);
317
+ });
318
+ iframe.src = sandboxProxyUrl.href;
319
+ return { onReady };
320
+ }
321
+
322
+ // src/client/core/app-host.ts
323
+ var DEFAULT_MCP_APP_CSP = {
324
+ "default-src": "'self'",
325
+ "script-src": "'self' 'unsafe-inline' 'unsafe-eval' https: blob:",
326
+ "style-src": "'self' 'unsafe-inline' https:",
327
+ "connect-src": "'self' https: wss:",
328
+ "img-src": "'self' data: https: blob:",
329
+ "font-src": "'self' data: https:",
330
+ "media-src": "'self' https: blob:",
331
+ "frame-src": "'none'",
332
+ "object-src": "'none'",
333
+ "base-uri": "'self'"
334
+ };
335
+ var HOST_INFO = APP_HOST_DEFAULTS.HOST_INFO;
336
+ var MCP_URI_SCHEMES = APP_HOST_DEFAULTS.URI_SCHEMES;
271
337
  var AppHost = class {
272
338
  constructor(client, iframe, options) {
273
339
  this.client = client;
@@ -276,10 +342,12 @@ var AppHost = class {
276
342
  __publicField(this, "sessionId");
277
343
  __publicField(this, "resourceCache", /* @__PURE__ */ new Map());
278
344
  __publicField(this, "debug");
279
- /** Callback for app messages (e.g., chat messages from the app) */
345
+ __publicField(this, "sandboxConfig");
346
+ __publicField(this, "options");
280
347
  __publicField(this, "onAppMessage");
281
- this.debug = options?.debug ?? false;
282
- this.configureSandbox();
348
+ this.options = options || {};
349
+ this.debug = this.options.debug ?? false;
350
+ this.sandboxConfig = this.options.sandbox;
283
351
  this.bridge = this.initializeBridge();
284
352
  }
285
353
  // ============================================
@@ -306,19 +374,35 @@ var AppHost = class {
306
374
  }
307
375
  }
308
376
  /**
309
- * Launch an MCP App from a URL or MCP resource URI.
377
+ * Launch an MCP App from a URL, MCP resource URI, or RAW HTML.
310
378
  * Loads the HTML first, then establishes bridge connection.
311
379
  */
312
- async launch(url, sessionId) {
380
+ async launch(source, sessionId) {
313
381
  if (sessionId) this.sessionId = sessionId;
314
382
  const initializedPromise = this.onAppReady();
315
- if (this.isMcpUri(url)) {
316
- await this.launchMcpApp(url);
317
- } else {
318
- this.iframe.src = url;
383
+ let htmlToRender = source.html;
384
+ if (!htmlToRender && source.uri) {
385
+ if (this.isMcpUri(source.uri)) {
386
+ htmlToRender = await this.readMcpAppHtml(source.uri);
387
+ }
388
+ }
389
+ if (!htmlToRender && source.uri && !this.isMcpUri(source.uri)) {
390
+ this.iframe.setAttribute("sandbox", "allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-downloads");
391
+ this.iframe.src = source.uri;
392
+ await this.onIframeReady();
393
+ await this.connectBridge();
394
+ } else if (htmlToRender) {
395
+ if (!this.sandboxConfig) {
396
+ throw new Error("Sandbox configuration requires a proxy URL to render HTML safely.");
397
+ }
398
+ await this.launchSandboxedHtml(htmlToRender, this.sandboxConfig);
399
+ await this.connectBridge();
400
+ this.log("Sending HTML resource to sandbox proxy (MCP Apps notification)");
401
+ await this.bridge.sendSandboxResourceReady({
402
+ html: htmlToRender,
403
+ csp: this.sandboxConfig.csp
404
+ });
319
405
  }
320
- await this.onIframeReady();
321
- await this.connectBridge();
322
406
  this.log("Waiting for app initialization");
323
407
  await Promise.race([
324
408
  initializedPromise,
@@ -329,6 +413,19 @@ var AppHost = class {
329
413
  ]);
330
414
  this.log("App launched and ready");
331
415
  }
416
+ // Set host context manually
417
+ setHostContext(context) {
418
+ this.options.hostContext = context;
419
+ if (this.bridge) {
420
+ this.bridge.setHostContext(context);
421
+ }
422
+ }
423
+ // Send streaming inputs manually
424
+ sendToolInputPartial(params) {
425
+ if (this.bridge) {
426
+ this.bridge.sendToolInputPartial(params);
427
+ }
428
+ }
332
429
  /**
333
430
  * Wait for app to signal initialization complete
334
431
  */
@@ -379,14 +476,17 @@ var AppHost = class {
379
476
  this.log("Sending tool cancellation to app");
380
477
  this.bridge.sendToolCancelled({ reason });
381
478
  }
479
+ /**
480
+ * Tell the guest UI the resource is being torn down (unload / cleanup).
481
+ * Forwards to {@link AppBridge.teardownResource} on `@modelcontextprotocol/ext-apps/app-bridge`.
482
+ */
483
+ teardownResource(params = {}) {
484
+ this.log("Sending resource teardown to app");
485
+ this.bridge.teardownResource(params);
486
+ }
382
487
  // ============================================
383
488
  // Private: Initialization
384
489
  // ============================================
385
- configureSandbox() {
386
- if (this.iframe.sandbox.value !== SANDBOX_PERMISSIONS) {
387
- this.iframe.sandbox.value = SANDBOX_PERMISSIONS;
388
- }
389
- }
390
490
  initializeBridge() {
391
491
  const bridge = new AppBridge(
392
492
  null,
@@ -395,12 +495,10 @@ var AppHost = class {
395
495
  openLinks: {},
396
496
  serverTools: {},
397
497
  logging: {},
398
- // Declare support for model context updates
399
498
  updateModelContext: { text: {} }
400
499
  },
401
500
  {
402
- // Initial host context
403
- hostContext: {
501
+ hostContext: this.options.hostContext || {
404
502
  theme: "dark",
405
503
  platform: "web",
406
504
  containerDimensions: { maxHeight: 6e3 },
@@ -409,19 +507,56 @@ var AppHost = class {
409
507
  }
410
508
  }
411
509
  );
510
+ bridge.fallbackRequestHandler = this.options.onFallbackRequest;
412
511
  bridge.oncalltool = (params) => this.handleToolCall(params);
413
- bridge.onopenlink = this.handleOpenLink.bind(this);
414
- bridge.onmessage = this.handleMessage.bind(this);
415
- bridge.onloggingmessage = (params) => this.log(`App log [${params.level}]: ${params.data}`);
512
+ if (this.options.onReadResource) {
513
+ bridge.onreadresource = async (params) => {
514
+ const resp = await this.options.onReadResource(params.uri);
515
+ return {
516
+ contents: resp.contents.map((c) => ({
517
+ uri: params.uri,
518
+ text: c.text,
519
+ blob: c.blob
520
+ }))
521
+ };
522
+ };
523
+ }
524
+ bridge.onopenlink = async (params, extra) => {
525
+ if (this.options.onOpenLink) {
526
+ return await this.options.onOpenLink(params, extra);
527
+ }
528
+ return this.handleOpenLink(params);
529
+ };
530
+ bridge.onmessage = async (params, extra) => {
531
+ if (this.options.onMessage) {
532
+ return await this.options.onMessage(params, extra);
533
+ }
534
+ return this.handleMessage(params);
535
+ };
536
+ bridge.onloggingmessage = (params) => {
537
+ this.log(`App log [${params.level}]: ${params.data}`);
538
+ if (this.options.onLoggingMessage) {
539
+ this.options.onLoggingMessage(params);
540
+ }
541
+ };
416
542
  bridge.onupdatemodelcontext = async () => ({});
417
- bridge.onsizechange = async ({ width, height }) => {
418
- if (height !== void 0) this.iframe.style.height = `${height}px`;
419
- if (width !== void 0) this.iframe.style.minWidth = `min(${width}px, 100%)`;
543
+ bridge.onsizechange = async (params) => {
544
+ const { width, height } = params;
545
+ if (height !== void 0 && height > 0) {
546
+ this.iframe.style.height = `${height}px`;
547
+ }
548
+ if (width !== void 0 && width > 0) this.iframe.style.minWidth = `min(${width}px, 100%)`;
549
+ if (this.options.onSizeChanged) {
550
+ this.options.onSizeChanged(params);
551
+ }
420
552
  return {};
421
553
  };
422
- bridge.onrequestdisplaymode = async (params) => ({
423
- mode: params.mode === "fullscreen" ? "fullscreen" : "inline"
424
- });
554
+ bridge.onrequestdisplaymode = async (params, extra) => {
555
+ if (this.options.onRequestDisplayMode) {
556
+ return await this.options.onRequestDisplayMode(params, extra);
557
+ }
558
+ return { mode: params.mode === "fullscreen" ? "fullscreen" : "inline" };
559
+ };
425
560
  return bridge;
426
561
  }
427
562
  async connectBridge() {
@@ -435,6 +570,9 @@ var AppHost = class {
435
570
  this.log("Bridge connected successfully");
436
571
  } catch (error) {
437
572
  this.log("Bridge connection failed", "error");
573
+ if (this.options.onError) {
574
+ this.options.onError(error instanceof Error ? error : new Error(String(error)));
575
+ }
438
576
  throw error;
439
577
  }
440
578
  }
@@ -442,8 +580,11 @@ var AppHost = class {
442
580
  // Private: Bridge Event Handlers
443
581
  // ============================================
444
582
  async handleToolCall(params) {
445
- if (!this.client.isConnected()) {
446
- throw new Error("Client disconnected");
583
+ if (this.options.onCallTool) {
584
+ return await this.options.onCallTool(params);
585
+ }
586
+ if (!this.client || !this.client.isConnected()) {
587
+ throw new Error("Client disconnected or not provided");
447
588
  }
448
589
  const sessionId = await this.getSessionId();
449
590
  if (!sessionId) {
@@ -467,13 +608,19 @@ var AppHost = class {
467
608
  // ============================================
468
609
  // Private: Resource Loading
469
610
  // ============================================
470
- async launchMcpApp(uri) {
471
- if (!this.client.isConnected()) {
472
- throw new Error("Client must be connected");
611
+ async launchSandboxedHtml(html, config) {
612
+ const sandboxUrlString = config.url instanceof URL ? config.url.href : config.url;
613
+ const url = new URL(sandboxUrlString, globalThis.location?.href);
614
+ if (config.csp && Object.keys(config.csp).length > 0) {
615
+ url.searchParams.set("csp", JSON.stringify(config.csp));
473
616
  }
617
+ const { onReady } = await setupSandboxProxyIframe(this.iframe, url);
618
+ await onReady;
619
+ }
620
+ async readMcpAppHtml(uri) {
474
621
  const sessionId = await this.getSessionId();
475
- if (!sessionId) {
476
- throw new Error("No active session");
622
+ if (!sessionId && !this.options.onReadResource) {
623
+ throw new Error("No active session.");
477
624
  }
478
625
  const response = await this.fetchResourceWithCache(sessionId, uri);
479
626
  if (!response?.contents?.length) {
@@ -484,10 +631,18 @@ var AppHost = class {
484
631
  if (!html) {
485
632
  throw new Error(`Invalid content in resource: ${uri}`);
486
633
  }
487
- const blob = new Blob([html], { type: "text/html" });
488
- this.iframe.src = URL.createObjectURL(blob);
634
+ return html;
489
635
  }
490
636
  async fetchResourceWithCache(sessionId, uri) {
637
+ if (this.options.onReadResource) {
638
+ return await this.options.onReadResource(uri);
639
+ }
640
+ if (!sessionId) {
641
+ throw new Error("No active session");
642
+ }
643
+ if (!this.client) {
644
+ throw new Error("No client to read resource from");
645
+ }
491
646
  if (this.hasClientCache()) {
492
647
  return this.client.getOrFetchResource(sessionId, uri);
493
648
  }
@@ -500,8 +655,11 @@ var AppHost = class {
500
655
  }
501
656
  async preloadResource(uri) {
502
657
  try {
658
+ if (this.options.onReadResource) {
659
+ return await this.options.onReadResource(uri);
660
+ }
503
661
  const sessionId = await this.getSessionId();
504
- if (!sessionId) return null;
662
+ if (!sessionId || !this.client) return null;
505
663
  return await this.client.readResource(sessionId, uri);
506
664
  } catch (error) {
507
665
  this.log(`Preload failed for ${uri}`, "warn");
@@ -513,6 +671,7 @@ var AppHost = class {
513
671
  // ============================================
514
672
  async getSessionId() {
515
673
  if (this.sessionId) return this.sessionId;
674
+ if (!this.client) return void 0;
516
675
  const result = await this.client.getSessions();
517
676
  return result.sessions?.[0]?.sessionId;
518
677
  }
@@ -520,6 +679,7 @@ var AppHost = class {
520
679
  return MCP_URI_SCHEMES.some((scheme) => url.startsWith(scheme));
521
680
  }
522
681
  hasClientCache() {
682
+ if (!this.client) return false;
523
683
  return "getOrFetchResource" in this.client && typeof this.client.getOrFetchResource === "function";
524
684
  }
525
685
  extractUiResourceUri(tool) {
@@ -549,6 +709,6 @@ var AppHost = class {
549
709
  }
550
710
  };
551
711
 
552
- export { AppHost, SSEClient };
712
+ export { APP_HOST_DEFAULTS, AppHost, DEFAULT_MCP_APP_CSP, SANDBOX_PROXY_READY_METHOD, SANDBOX_RESOURCE_READY_METHOD, SSEClient };
553
713
  //# sourceMappingURL=index.mjs.map
554
714
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/core/sse-client.ts","../../src/client/core/app-host.ts"],"names":["data"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Stateless RPC-over-stream client for MCP connections.\n *\n * Uses single POST requests with `Accept: text/event-stream` for every RPC call.\n * Progress events and the final rpc-response are delivered in the same response.\n */\n\nimport { nanoid } from 'nanoid';\nimport type {\n McpConnectionEvent,\n McpObservabilityEvent,\n McpAppsUIEvent\n} from '../../shared/events.js';\nimport type {\n McpRpcRequest,\n McpRpcResponse,\n McpRpcMethod,\n McpRpcParams,\n ConnectParams,\n SessionListResult,\n ConnectResult,\n DisconnectResult,\n RestoreSessionResult,\n FinishAuthResult,\n ListToolsRpcResult,\n ListPromptsResult,\n ListResourcesResult,\n} from '../../shared/types.js';\n\nexport interface SSEClientOptions {\n /** MCP endpoint URL */\n url: string;\n\n /** User/Client identifier */\n identity: string;\n\n /** Optional auth token for authenticated requests */\n authToken?: string;\n\n /** Callback for MCP connection state changes */\n onConnectionEvent?: (event: McpConnectionEvent) => void;\n\n /** Callback for observability/logging events */\n onObservabilityEvent?: (event: McpObservabilityEvent) => void;\n\n /** Callback for connection status changes */\n onStatusChange?: (status: ConnectionStatus) => void;\n\n /** Callback for MCP App UI events */\n onEvent?: (event: McpAppsUIEvent) => void;\n\n /** Enable debug logging @default false */\n debug?: boolean;\n}\n\nexport type ConnectionStatus = 'connecting' | 'connected' | 'disconnected' | 'error';\n\nconst CONNECTION_EVENT_INTERVAL_MS = 300;\n\ninterface ToolUiMetadata {\n resourceUri?: string;\n uri?: string;\n visibility?: string[];\n}\n\nexport class SSEClient {\n private resourceCache = new Map<string, Promise<unknown>>();\n private connected = false;\n\n constructor(private readonly options: SSEClientOptions) {}\n\n connect(): void {\n if (this.connected) {\n return;\n }\n this.connected = true;\n this.options.onStatusChange?.('connected');\n this.log('RPC mode: post_stream');\n }\n\n disconnect(): void {\n this.connected = false;\n this.options.onStatusChange?.('disconnected');\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n async getSessions(): Promise<SessionListResult> {\n return this.sendRequest<SessionListResult>('getSessions');\n }\n\n async connectToServer(params: ConnectParams): Promise<ConnectResult> {\n return this.sendRequest<ConnectResult>('connect', params);\n }\n\n async disconnectFromServer(sessionId: string): Promise<DisconnectResult> {\n return this.sendRequest<DisconnectResult>('disconnect', { sessionId });\n }\n\n async listTools(sessionId: string): Promise<ListToolsRpcResult> {\n return this.sendRequest<ListToolsRpcResult>('listTools', { sessionId });\n }\n\n async callTool(\n sessionId: string,\n toolName: string,\n toolArgs: Record<string, unknown>\n ): Promise<unknown> {\n const result = await this.sendRequest('callTool', { sessionId, toolName, toolArgs });\n this.emitUiEventIfPresent(result, sessionId, toolName);\n return result;\n }\n\n async restoreSession(sessionId: string): Promise<RestoreSessionResult> {\n return this.sendRequest<RestoreSessionResult>('restoreSession', { sessionId });\n }\n\n async finishAuth(sessionId: string, code: string): Promise<FinishAuthResult> {\n return this.sendRequest<FinishAuthResult>('finishAuth', { sessionId, code });\n }\n\n async listPrompts(sessionId: string): Promise<ListPromptsResult> {\n return this.sendRequest<ListPromptsResult>('listPrompts', { sessionId });\n }\n\n async getPrompt(sessionId: string, name: string, args?: Record<string, string>): Promise<unknown> {\n return this.sendRequest('getPrompt', { sessionId, name, args });\n }\n\n async listResources(sessionId: string): Promise<ListResourcesResult> {\n return this.sendRequest<ListResourcesResult>('listResources', { sessionId });\n }\n\n async readResource(sessionId: string, uri: string): Promise<unknown> {\n return this.sendRequest('readResource', { sessionId, uri });\n }\n\n preloadToolUiResources(sessionId: string, tools: Array<{ name: string; _meta?: unknown }>): void {\n for (const tool of tools) {\n const uri = this.extractUiResourceUri(tool);\n if (!uri || this.resourceCache.has(uri)) continue;\n const promise = this.sendRequest('readResource', { sessionId, uri }).catch((err) => {\n this.log(`Failed to preload resource ${uri}: ${err.message}`, 'warn');\n this.resourceCache.delete(uri);\n return null;\n });\n this.resourceCache.set(uri, promise);\n }\n }\n\n getOrFetchResource(sessionId: string, uri: string): Promise<unknown> {\n const cached = this.resourceCache.get(uri);\n if (cached) return cached;\n const promise = this.sendRequest('readResource', { sessionId, uri });\n this.resourceCache.set(uri, promise);\n return promise;\n }\n\n hasPreloadedResource(uri: string): boolean {\n return this.resourceCache.has(uri);\n }\n\n clearResourceCache(): void {\n this.resourceCache.clear();\n }\n\n private async sendRequest<T = unknown>(method: McpRpcMethod, params?: McpRpcParams): Promise<T> {\n if (!this.connected) {\n this.connect();\n }\n\n this.log(`RPC request via post_stream: ${method}`);\n\n const request: McpRpcRequest = {\n id: `rpc_${nanoid(10)}`,\n method,\n params,\n };\n\n const response = await fetch(this.buildUrl(), {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const contentType = (response.headers.get('content-type') || '').toLowerCase();\n if (!contentType.includes('text/event-stream')) {\n const data = await response.json() as McpRpcResponse;\n return this.parseRpcResponse<T>(data);\n }\n\n const data = await this.readRpcResponseFromStream(response, {\n delayConnectionEvents:\n method === 'connect' ||\n method === 'restoreSession' ||\n method === 'finishAuth',\n });\n return this.parseRpcResponse<T>(data);\n }\n\n private async readRpcResponseFromStream(\n response: Response,\n options: { delayConnectionEvents?: boolean } = {}\n ): Promise<McpRpcResponse> {\n if (!response.body) {\n throw new Error('Streaming response body is missing');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let rpcResponse: McpRpcResponse | null = null;\n\n const dispatchBlock = async (block: string) => {\n const lines = block.split('\\n');\n let eventName = 'message';\n const dataLines: string[] = [];\n\n for (const rawLine of lines) {\n const line = rawLine.replace(/\\r$/, '');\n if (!line || line.startsWith(':')) continue;\n if (line.startsWith('event:')) {\n eventName = line.slice('event:'.length).trim();\n continue;\n }\n if (line.startsWith('data:')) {\n dataLines.push(line.slice('data:'.length).trimStart());\n }\n }\n\n if (!dataLines.length) return;\n const payloadText = dataLines.join('\\n');\n let payload: unknown = payloadText;\n try {\n payload = JSON.parse(payloadText);\n } catch {\n // Keep raw text\n }\n\n switch (eventName) {\n case 'connected':\n this.options.onStatusChange?.('connected');\n break;\n case 'connection':\n this.options.onConnectionEvent?.(payload as McpConnectionEvent);\n if (options.delayConnectionEvents) {\n await this.sleep(CONNECTION_EVENT_INTERVAL_MS);\n }\n break;\n case 'observability':\n this.options.onObservabilityEvent?.(payload as McpObservabilityEvent);\n break;\n case 'rpc-response':\n rpcResponse = payload as McpRpcResponse;\n break;\n default:\n break;\n }\n };\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n let separatorMatch = buffer.match(/\\r?\\n\\r?\\n/);\n while (separatorMatch && separatorMatch.index !== undefined) {\n const separatorIndex = separatorMatch.index;\n const separatorLength = separatorMatch[0].length;\n const block = buffer.slice(0, separatorIndex);\n buffer = buffer.slice(separatorIndex + separatorLength);\n await dispatchBlock(block);\n separatorMatch = buffer.match(/\\r?\\n\\r?\\n/);\n }\n }\n\n if (buffer.trim()) {\n await dispatchBlock(buffer);\n }\n\n if (!rpcResponse) {\n throw new Error('Missing rpc-response event in streamed RPC result');\n }\n\n return rpcResponse;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n private parseRpcResponse<T>(data: McpRpcResponse): T {\n if ('result' in data) {\n return data.result as T;\n }\n if ('error' in data && data.error) {\n throw new Error(data.error.message || 'Unknown RPC error');\n }\n // JSON omits `result` when it is `undefined` (response becomes `{ id: ... }`).\n // Treat that shape as a successful void result.\n if (data && typeof data === 'object' && 'id' in data) {\n return undefined as T;\n }\n throw new Error('Invalid RPC response format');\n }\n\n private buildUrl(): string {\n const url = new URL(this.options.url, globalThis.location?.origin);\n url.searchParams.set('identity', this.options.identity);\n if (this.options.authToken) {\n url.searchParams.set('token', this.options.authToken);\n }\n return url.toString();\n }\n\n private buildHeaders(): HeadersInit {\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'Accept': 'text/event-stream',\n };\n if (this.options.authToken) {\n headers['Authorization'] = `Bearer ${this.options.authToken}`;\n }\n return headers;\n }\n\n private extractUiResourceUri(tool: { name: string; _meta?: unknown }): string | undefined {\n const meta = (tool._meta as { ui?: ToolUiMetadata })?.ui;\n if (!meta || typeof meta !== 'object') return undefined;\n if (meta.visibility && !meta.visibility.includes('app')) return undefined;\n return meta.resourceUri ?? meta.uri;\n }\n\n private emitUiEventIfPresent(result: unknown, sessionId: string, toolName: string): void {\n const meta = (result as { _meta?: { ui?: ToolUiMetadata } })?._meta;\n const resourceUri = meta?.ui?.resourceUri ?? (meta as any)?.['ui/resourceUri'];\n\n if (resourceUri) {\n this.options.onEvent?.({\n type: 'mcp-apps-ui',\n sessionId,\n resourceUri,\n toolName,\n result,\n timestamp: Date.now(),\n });\n }\n }\n\n private log(message: string, level: 'info' | 'warn' | 'error' = 'info'): void {\n if (!this.options.debug && level === 'info') return;\n\n const prefix = '[SSEClient]';\n switch (level) {\n case 'warn':\n console.warn(prefix, message);\n break;\n case 'error':\n console.error(prefix, message);\n break;\n default:\n console.log(prefix, message);\n }\n }\n}\n","/**\n * MCP App Host\n *\n * Bridges the gap between an iframe (MCP App) and the SSEClient (MCP Server).\n * Handles secure iframe sandboxing, resource loading, and bi-directional\n * communication via the AppBridge protocol.\n *\n * Key features:\n * - Secure iframe sandboxing with minimal permissions\n * - Resource preloading for instant MCP App UI loading\n * - Cache-aware resource fetching (SSEClient cache → local cache → direct fetch)\n * - Support for ui:// and mcp-app:// resource URIs\n */\n\nimport { AppBridge, PostMessageTransport } from '@modelcontextprotocol/ext-apps/app-bridge';\nimport type { AppHostClient } from './types';\n\n// ============================================\n// Types & Interfaces\n// ============================================\n\nexport interface AppHostOptions {\n /** Enable debug logging @default false */\n debug?: boolean;\n}\n\nexport interface AppMessageParams {\n role: string;\n content: unknown;\n}\n\ninterface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\ninterface ResourceContent {\n blob?: string;\n text?: string;\n}\n\ninterface ResourceResponse {\n contents: ResourceContent[];\n}\n\n// ============================================\n// Constants\n// ============================================\n\nconst HOST_INFO = { name: 'mcp-ts-host', version: '1.0.0' };\n\n/** Sandbox permissions - minimal set required for MCP Apps to function */\nconst SANDBOX_PERMISSIONS = [\n 'allow-scripts', // Required for app JavaScript execution\n 'allow-forms', // Required for form submissions\n 'allow-same-origin', // Required for Blob URL correctness\n 'allow-modals', // Required for dialogs/alerts\n 'allow-popups', // Required for opening links\n 'allow-downloads' // Required for file downloads\n].join(' ');\n\n/** Supported MCP App URI schemes */\nconst MCP_URI_SCHEMES = ['ui://', 'mcp-app://'] as const;\n\n// ============================================\n// AppHost Class\n// ============================================\n\n/**\n * Host for MCP Apps embedded in iframes.\n * Manages secure communication between the app and the MCP server.\n */\nexport class AppHost {\n private bridge: AppBridge;\n private sessionId?: string;\n private resourceCache = new Map<string, Promise<ResourceResponse | null>>();\n private debug: boolean;\n\n /** Callback for app messages (e.g., chat messages from the app) */\n public onAppMessage?: (params: AppMessageParams) => void;\n\n constructor(\n private readonly client: AppHostClient,\n private readonly iframe: HTMLIFrameElement,\n options?: AppHostOptions\n ) {\n this.debug = options?.debug ?? false;\n this.configureSandbox();\n this.bridge = this.initializeBridge();\n }\n\n // ============================================\n // Public API\n // ============================================\n\n /**\n * Start the host. This prepares the bridge handlers but doesn't connect yet.\n * The actual connection happens in launch() after HTML is loaded.\n * @returns Promise that resolves immediately (bridge connects during launch)\n */\n async start(): Promise<void> {\n // Bridge handlers are already registered in constructor.\n // Connection happens in launch() after HTML is loaded.\n this.log('Host started, ready to launch');\n }\n\n /**\n * Preload UI resources to enable instant app loading.\n * Call this when tools are discovered to cache their UI resources.\n */\n preload(tools: Array<{ _meta?: unknown }>): void {\n for (const tool of tools) {\n const uri = this.extractUiResourceUri(tool);\n if (!uri || this.resourceCache.has(uri)) continue;\n\n const promise = this.preloadResource(uri);\n this.resourceCache.set(uri, promise);\n }\n }\n\n /**\n * Launch an MCP App from a URL or MCP resource URI.\n * Loads the HTML first, then establishes bridge connection.\n */\n async launch(url: string, sessionId?: string): Promise<void> {\n if (sessionId) this.sessionId = sessionId;\n\n // Set up initialization promise BEFORE connecting\n const initializedPromise = this.onAppReady();\n\n // Load HTML into iframe first\n if (this.isMcpUri(url)) {\n await this.launchMcpApp(url);\n } else {\n this.iframe.src = url;\n }\n\n // Wait for iframe to load before connecting bridge\n await this.onIframeReady();\n\n // Connect the bridge (HTML is loaded, contentWindow is ready)\n await this.connectBridge();\n\n // Wait for app to signal it's initialized (with timeout)\n this.log('Waiting for app initialization');\n await Promise.race([\n initializedPromise,\n new Promise<void>((resolve) => setTimeout(() => {\n this.log('Initialization timeout - continuing anyway', 'warn');\n resolve();\n }, 3000))\n ]);\n this.log('App launched and ready');\n }\n\n /**\n * Wait for app to signal initialization complete\n */\n private onAppReady(): Promise<void> {\n return new Promise<void>((resolve) => {\n const originalHandler = this.bridge.oninitialized;\n this.bridge.oninitialized = (...args) => {\n this.log('App initialized');\n resolve();\n this.bridge.oninitialized = originalHandler;\n originalHandler?.(...args);\n };\n });\n }\n\n /**\n * Wait for iframe to finish loading\n */\n private onIframeReady(): Promise<void> {\n return new Promise((resolve) => {\n if (this.iframe.contentDocument?.readyState === 'complete') {\n resolve();\n return;\n }\n this.iframe.addEventListener('load', () => resolve(), { once: true });\n });\n }\n\n /**\n * Send tool input arguments to the MCP App.\n * Call this after launch() when tool input is available.\n */\n sendToolInput(args: Record<string, unknown>): void {\n this.log('Sending tool input to app');\n this.bridge.sendToolInput({ arguments: args });\n }\n\n /**\n * Send tool result to the MCP App.\n * Call this when the tool call completes.\n */\n sendToolResult(result: unknown): void {\n this.log('Sending tool result to app');\n this.bridge.sendToolResult(result as any);\n }\n\n /**\n * Send tool cancellation to the MCP App.\n * Call this when the tool call is cancelled or fails.\n */\n sendToolCancelled(reason: string): void {\n this.log('Sending tool cancellation to app');\n this.bridge.sendToolCancelled({ reason });\n }\n\n // ============================================\n // Private: Initialization\n // ============================================\n\n private configureSandbox(): void {\n if (this.iframe.sandbox.value !== SANDBOX_PERMISSIONS) {\n this.iframe.sandbox.value = SANDBOX_PERMISSIONS;\n }\n }\n\n private initializeBridge(): AppBridge {\n const bridge = new AppBridge(\n null,\n HOST_INFO,\n {\n openLinks: {},\n serverTools: {},\n logging: {},\n // Declare support for model context updates\n updateModelContext: { text: {} },\n },\n {\n // Initial host context\n hostContext: {\n theme: 'dark',\n platform: 'web',\n containerDimensions: { maxHeight: 6000 },\n displayMode: 'inline',\n availableDisplayModes: ['inline', 'fullscreen'],\n },\n }\n );\n\n // Register handlers - must be done BEFORE connect()\n bridge.oncalltool = (params) => this.handleToolCall(params);\n bridge.onopenlink = this.handleOpenLink.bind(this);\n bridge.onmessage = this.handleMessage.bind(this);\n bridge.onloggingmessage = (params) => this.log(`App log [${params.level}]: ${params.data}`);\n bridge.onupdatemodelcontext = async () => ({});\n bridge.onsizechange = async ({ width, height }) => {\n if (height !== undefined) this.iframe.style.height = `${height}px`;\n if (width !== undefined) this.iframe.style.minWidth = `min(${width}px, 100%)`;\n return {};\n };\n bridge.onrequestdisplaymode = async (params) => ({\n mode: params.mode === 'fullscreen' ? 'fullscreen' : 'inline'\n });\n\n return bridge;\n }\n\n private async connectBridge(): Promise<void> {\n this.log('Connecting bridge to iframe');\n\n const transport = new PostMessageTransport(\n this.iframe.contentWindow!,\n this.iframe.contentWindow!\n );\n\n try {\n await this.bridge.connect(transport);\n this.log('Bridge connected successfully');\n } catch (error) {\n this.log('Bridge connection failed', 'error');\n throw error;\n }\n }\n\n // ============================================\n // Private: Bridge Event Handlers\n // ============================================\n\n private async handleToolCall(params: ToolCallParams) {\n if (!this.client.isConnected()) {\n throw new Error('Client disconnected');\n }\n\n const sessionId = await this.getSessionId();\n if (!sessionId) {\n throw new Error('No active session');\n }\n\n const result = await this.client.callTool(\n sessionId,\n params.name,\n params.arguments ?? {}\n );\n return result as any;\n }\n\n private async handleOpenLink(params: { url: string }): Promise<Record<string, never>> {\n window.open(params.url, '_blank', 'noopener,noreferrer');\n return {};\n }\n\n private async handleMessage(params: AppMessageParams): Promise<Record<string, never>> {\n this.onAppMessage?.(params);\n return {};\n }\n\n // ============================================\n // Private: Resource Loading\n // ============================================\n\n private async launchMcpApp(uri: string): Promise<void> {\n if (!this.client.isConnected()) {\n throw new Error('Client must be connected');\n }\n\n const sessionId = await this.getSessionId();\n if (!sessionId) {\n throw new Error('No active session');\n }\n\n // Fetch resource using cache hierarchy: SSEClient cache → local cache → direct fetch\n const response = await this.fetchResourceWithCache(sessionId, uri);\n if (!response?.contents?.length) {\n throw new Error(`Empty resource: ${uri}`);\n }\n\n const content = response.contents[0];\n const html = this.decodeContent(content);\n if (!html) {\n throw new Error(`Invalid content in resource: ${uri}`);\n }\n\n // Render via Blob URL for clean isolation\n const blob = new Blob([html], { type: 'text/html' });\n this.iframe.src = URL.createObjectURL(blob);\n }\n\n private async fetchResourceWithCache(sessionId: string, uri: string): Promise<ResourceResponse> {\n // Priority 1: SSEClient's built-in cache (best performance)\n if (this.hasClientCache()) {\n return (this.client as any).getOrFetchResource(sessionId, uri);\n }\n\n // Priority 2: Local preload cache\n const cached = this.resourceCache.get(uri);\n if (cached) {\n const result = await cached;\n if (result) return result;\n }\n\n // Priority 3: Direct fetch\n return this.client.readResource(sessionId, uri) as Promise<ResourceResponse>;\n }\n\n private async preloadResource(uri: string): Promise<ResourceResponse | null> {\n try {\n const sessionId = await this.getSessionId();\n if (!sessionId) return null;\n return await this.client.readResource(sessionId, uri) as ResourceResponse;\n } catch (error) {\n this.log(`Preload failed for ${uri}`, 'warn');\n return null;\n }\n }\n\n // ============================================\n // Private: Utilities\n // ============================================\n\n private async getSessionId(): Promise<string | undefined> {\n if (this.sessionId) return this.sessionId;\n const result = await this.client.getSessions();\n return result.sessions?.[0]?.sessionId;\n }\n\n private isMcpUri(url: string): boolean {\n return MCP_URI_SCHEMES.some(scheme => url.startsWith(scheme));\n }\n\n private hasClientCache(): boolean {\n return 'getOrFetchResource' in this.client &&\n typeof (this.client as any).getOrFetchResource === 'function';\n }\n\n private extractUiResourceUri(tool: { _meta?: unknown }): string | undefined {\n const meta = tool._meta as { ui?: { resourceUri?: string; uri?: string } } | undefined;\n if (!meta?.ui) return undefined;\n return meta.ui.resourceUri ?? meta.ui.uri;\n }\n\n private decodeContent(content: ResourceContent): string | undefined {\n if (content.blob) {\n return atob(content.blob);\n }\n return content.text;\n }\n\n private log(message: string, level: 'info' | 'warn' | 'error' = 'info'): void {\n if (!this.debug && level === 'info') return;\n\n const prefix = '[AppHost]';\n switch (level) {\n case 'warn':\n console.warn(prefix, message);\n break;\n case 'error':\n console.error(prefix, message);\n break;\n default:\n console.log(prefix, message);\n }\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/client/core/sse-client.ts","../../src/client/core/constants.ts","../../src/client/utils/app-host-utils.ts","../../src/client/core/app-host.ts"],"names":["data"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Stateless RPC-over-stream client for MCP connections.\n *\n * Uses single POST requests with `Accept: text/event-stream` for every RPC call.\n * Progress events and the final rpc-response are delivered in the same response.\n */\n\nimport { nanoid } from 'nanoid';\nimport type {\n McpConnectionEvent,\n McpObservabilityEvent,\n McpAppsUIEvent\n} from '../../shared/events.js';\nimport type {\n McpRpcRequest,\n McpRpcResponse,\n McpRpcMethod,\n McpRpcParams,\n ConnectParams,\n SessionListResult,\n ConnectResult,\n DisconnectResult,\n RestoreSessionResult,\n FinishAuthResult,\n ListToolsRpcResult,\n ListPromptsResult,\n ListResourcesResult,\n} from '../../shared/types.js';\n\nexport interface SSEClientOptions {\n /** MCP endpoint URL */\n url: string;\n\n /** User/Client identifier */\n identity: string;\n\n /** Optional auth token for authenticated requests */\n authToken?: string;\n\n /** Callback for MCP connection state changes */\n onConnectionEvent?: (event: McpConnectionEvent) => void;\n\n /** Callback for observability/logging events */\n onObservabilityEvent?: (event: McpObservabilityEvent) => void;\n\n /** Callback for connection status changes */\n onStatusChange?: (status: ConnectionStatus) => void;\n\n /** Callback for MCP App UI events */\n onEvent?: (event: McpAppsUIEvent) => void;\n\n /** Enable debug logging @default false */\n debug?: boolean;\n}\n\nexport type ConnectionStatus = 'connecting' | 'connected' | 'disconnected' | 'error';\n\nconst CONNECTION_EVENT_INTERVAL_MS = 300;\n\ninterface ToolUiMetadata {\n resourceUri?: string;\n uri?: string;\n visibility?: string[];\n}\n\nexport class SSEClient {\n private resourceCache = new Map<string, Promise<unknown>>();\n private connected = false;\n\n constructor(private readonly options: SSEClientOptions) {}\n\n connect(): void {\n if (this.connected) {\n return;\n }\n this.connected = true;\n this.options.onStatusChange?.('connected');\n this.log('RPC mode: post_stream');\n }\n\n disconnect(): void {\n this.connected = false;\n this.options.onStatusChange?.('disconnected');\n }\n\n isConnected(): boolean {\n return this.connected;\n }\n\n async getSessions(): Promise<SessionListResult> {\n return this.sendRequest<SessionListResult>('getSessions');\n }\n\n async connectToServer(params: ConnectParams): Promise<ConnectResult> {\n return this.sendRequest<ConnectResult>('connect', params);\n }\n\n async disconnectFromServer(sessionId: string): Promise<DisconnectResult> {\n return this.sendRequest<DisconnectResult>('disconnect', { sessionId });\n }\n\n async listTools(sessionId: string): Promise<ListToolsRpcResult> {\n return this.sendRequest<ListToolsRpcResult>('listTools', { sessionId });\n }\n\n async callTool(\n sessionId: string,\n toolName: string,\n toolArgs: Record<string, unknown>\n ): Promise<unknown> {\n const result = await this.sendRequest('callTool', { sessionId, toolName, toolArgs });\n this.emitUiEventIfPresent(result, sessionId, toolName);\n return result;\n }\n\n async restoreSession(sessionId: string): Promise<RestoreSessionResult> {\n return this.sendRequest<RestoreSessionResult>('restoreSession', { sessionId });\n }\n\n async finishAuth(sessionId: string, code: string): Promise<FinishAuthResult> {\n return this.sendRequest<FinishAuthResult>('finishAuth', { sessionId, code });\n }\n\n async listPrompts(sessionId: string): Promise<ListPromptsResult> {\n return this.sendRequest<ListPromptsResult>('listPrompts', { sessionId });\n }\n\n async getPrompt(sessionId: string, name: string, args?: Record<string, string>): Promise<unknown> {\n return this.sendRequest('getPrompt', { sessionId, name, args });\n }\n\n async listResources(sessionId: string): Promise<ListResourcesResult> {\n return this.sendRequest<ListResourcesResult>('listResources', { sessionId });\n }\n\n async readResource(sessionId: string, uri: string): Promise<unknown> {\n return this.sendRequest('readResource', { sessionId, uri });\n }\n\n preloadToolUiResources(sessionId: string, tools: Array<{ name: string; _meta?: unknown }>): void {\n for (const tool of tools) {\n const uri = this.extractUiResourceUri(tool);\n if (!uri || this.resourceCache.has(uri)) continue;\n const promise = this.sendRequest('readResource', { sessionId, uri }).catch((err) => {\n this.log(`Failed to preload resource ${uri}: ${err.message}`, 'warn');\n this.resourceCache.delete(uri);\n return null;\n });\n this.resourceCache.set(uri, promise);\n }\n }\n\n getOrFetchResource(sessionId: string, uri: string): Promise<unknown> {\n const cached = this.resourceCache.get(uri);\n if (cached) return cached;\n const promise = this.sendRequest('readResource', { sessionId, uri });\n this.resourceCache.set(uri, promise);\n return promise;\n }\n\n hasPreloadedResource(uri: string): boolean {\n return this.resourceCache.has(uri);\n }\n\n clearResourceCache(): void {\n this.resourceCache.clear();\n }\n\n private async sendRequest<T = unknown>(method: McpRpcMethod, params?: McpRpcParams): Promise<T> {\n if (!this.connected) {\n this.connect();\n }\n\n this.log(`RPC request via post_stream: ${method}`);\n\n const request: McpRpcRequest = {\n id: `rpc_${nanoid(10)}`,\n method,\n params,\n };\n\n const response = await fetch(this.buildUrl(), {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify(request),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const contentType = (response.headers.get('content-type') || '').toLowerCase();\n if (!contentType.includes('text/event-stream')) {\n const data = await response.json() as McpRpcResponse;\n return this.parseRpcResponse<T>(data);\n }\n\n const data = await this.readRpcResponseFromStream(response, {\n delayConnectionEvents:\n method === 'connect' ||\n method === 'restoreSession' ||\n method === 'finishAuth',\n });\n return this.parseRpcResponse<T>(data);\n }\n\n private async readRpcResponseFromStream(\n response: Response,\n options: { delayConnectionEvents?: boolean } = {}\n ): Promise<McpRpcResponse> {\n if (!response.body) {\n throw new Error('Streaming response body is missing');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let rpcResponse: McpRpcResponse | null = null;\n\n const dispatchBlock = async (block: string) => {\n const lines = block.split('\\n');\n let eventName = 'message';\n const dataLines: string[] = [];\n\n for (const rawLine of lines) {\n const line = rawLine.replace(/\\r$/, '');\n if (!line || line.startsWith(':')) continue;\n if (line.startsWith('event:')) {\n eventName = line.slice('event:'.length).trim();\n continue;\n }\n if (line.startsWith('data:')) {\n dataLines.push(line.slice('data:'.length).trimStart());\n }\n }\n\n if (!dataLines.length) return;\n const payloadText = dataLines.join('\\n');\n let payload: unknown = payloadText;\n try {\n payload = JSON.parse(payloadText);\n } catch {\n // Keep raw text\n }\n\n switch (eventName) {\n case 'connected':\n this.options.onStatusChange?.('connected');\n break;\n case 'connection':\n this.options.onConnectionEvent?.(payload as McpConnectionEvent);\n if (options.delayConnectionEvents) {\n await this.sleep(CONNECTION_EVENT_INTERVAL_MS);\n }\n break;\n case 'observability':\n this.options.onObservabilityEvent?.(payload as McpObservabilityEvent);\n break;\n case 'rpc-response':\n rpcResponse = payload as McpRpcResponse;\n break;\n default:\n break;\n }\n };\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n\n let separatorMatch = buffer.match(/\\r?\\n\\r?\\n/);\n while (separatorMatch && separatorMatch.index !== undefined) {\n const separatorIndex = separatorMatch.index;\n const separatorLength = separatorMatch[0].length;\n const block = buffer.slice(0, separatorIndex);\n buffer = buffer.slice(separatorIndex + separatorLength);\n await dispatchBlock(block);\n separatorMatch = buffer.match(/\\r?\\n\\r?\\n/);\n }\n }\n\n if (buffer.trim()) {\n await dispatchBlock(buffer);\n }\n\n if (!rpcResponse) {\n throw new Error('Missing rpc-response event in streamed RPC result');\n }\n\n return rpcResponse;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n private parseRpcResponse<T>(data: McpRpcResponse): T {\n if ('result' in data) {\n return data.result as T;\n }\n if ('error' in data && data.error) {\n throw new Error(data.error.message || 'Unknown RPC error');\n }\n // JSON omits `result` when it is `undefined` (response becomes `{ id: ... }`).\n // Treat that shape as a successful void result.\n if (data && typeof data === 'object' && 'id' in data) {\n return undefined as T;\n }\n throw new Error('Invalid RPC response format');\n }\n\n private buildUrl(): string {\n const url = new URL(this.options.url, globalThis.location?.origin);\n url.searchParams.set('identity', this.options.identity);\n if (this.options.authToken) {\n url.searchParams.set('token', this.options.authToken);\n }\n return url.toString();\n }\n\n private buildHeaders(): HeadersInit {\n const headers: HeadersInit = {\n 'Content-Type': 'application/json',\n 'Accept': 'text/event-stream',\n };\n if (this.options.authToken) {\n headers['Authorization'] = `Bearer ${this.options.authToken}`;\n }\n return headers;\n }\n\n private extractUiResourceUri(tool: { name: string; _meta?: unknown }): string | undefined {\n const meta = (tool._meta as { ui?: ToolUiMetadata })?.ui;\n if (!meta || typeof meta !== 'object') return undefined;\n if (meta.visibility && !meta.visibility.includes('app')) return undefined;\n return meta.resourceUri ?? meta.uri;\n }\n\n private emitUiEventIfPresent(result: unknown, sessionId: string, toolName: string): void {\n const meta = (result as { _meta?: { ui?: ToolUiMetadata } })?._meta;\n const resourceUri = meta?.ui?.resourceUri ?? (meta as any)?.['ui/resourceUri'];\n\n if (resourceUri) {\n this.options.onEvent?.({\n type: 'mcp-apps-ui',\n sessionId,\n resourceUri,\n toolName,\n result,\n timestamp: Date.now(),\n });\n }\n }\n\n private log(message: string, level: 'info' | 'warn' | 'error' = 'info'): void {\n if (!this.options.debug && level === 'info') return;\n\n const prefix = '[SSEClient]';\n switch (level) {\n case 'warn':\n console.warn(prefix, message);\n break;\n case 'error':\n console.error(prefix, message);\n break;\n default:\n console.log(prefix, message);\n }\n }\n}\n","/**\n * Default configuration values for the App Host.\n *\n * `SANDBOX_*_READY_METHOD` match `@modelcontextprotocol/ext-apps` (see\n * https://github.com/modelcontextprotocol/ext-apps/blob/main/src/types.ts ).\n * Duplicated here because the package root `app.d.ts` often omits these value exports under\n * `moduleResolution: \"NodeNext\"`.\n */\nexport const SANDBOX_PROXY_READY_METHOD = 'ui/notifications/sandbox-proxy-ready' as const;\nexport const SANDBOX_RESOURCE_READY_METHOD = 'ui/notifications/sandbox-resource-ready' as const;\n\nexport const APP_HOST_DEFAULTS = {\n /** Default timeout for waiting for the sandbox proxy to be ready (ms). */\n SANDBOX_TIMEOUT_MS: 10000,\n \n /** Default host info reported to guest apps. */\n HOST_INFO: { name: 'mcp-ts-host', version: '1.0.0' },\n\n /** Supported MCP App URI schemes. */\n URI_SCHEMES: ['ui://', 'mcp-app://'] as const,\n\n /** Default theme for the host context. */\n THEME: 'dark',\n\n /** Default platform for the host context. */\n PLATFORM: 'web',\n\n /** Default max height for the iframe container (px). */\n MAX_HEIGHT: 6000,\n} as const;\n","import { APP_HOST_DEFAULTS, SANDBOX_PROXY_READY_METHOD } from '../core/constants.js';\n\nconst DEFAULT_SANDBOX_TIMEOUT_MS = APP_HOST_DEFAULTS.SANDBOX_TIMEOUT_MS;\n\nexport async function setupSandboxProxyIframe(\n iframe: HTMLIFrameElement,\n sandboxProxyUrl: URL\n): Promise<{\n onReady: Promise<void>;\n}> {\n iframe.style.width = '100%';\n iframe.style.height = '100%';\n iframe.style.border = 'none';\n iframe.style.backgroundColor = 'transparent';\n iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-downloads');\n\n const onReady = new Promise<void>((resolve, reject) => {\n let settled = false;\n\n const cleanup = () => {\n window.removeEventListener('message', messageListener);\n iframe.removeEventListener('error', errorListener);\n };\n\n const timeoutId = setTimeout(() => {\n if (!settled) {\n settled = true;\n cleanup();\n reject(new Error('Timed out waiting for sandbox proxy iframe to be ready'));\n }\n }, DEFAULT_SANDBOX_TIMEOUT_MS);\n\n const messageListener = (event: MessageEvent) => {\n if (event.source === iframe.contentWindow) {\n if (event.data?.method === SANDBOX_PROXY_READY_METHOD) {\n if (!settled) {\n settled = true;\n clearTimeout(timeoutId);\n cleanup();\n resolve();\n }\n }\n }\n };\n\n const errorListener = () => {\n if (!settled) {\n settled = true;\n clearTimeout(timeoutId);\n cleanup();\n reject(new Error('Failed to load sandbox proxy iframe'));\n }\n };\n\n window.addEventListener('message', messageListener);\n iframe.addEventListener('error', errorListener);\n });\n\n iframe.src = sandboxProxyUrl.href;\n\n return { onReady };\n}\n","/**\n * MCP App Host\n *\n * Bridges the gap between an iframe (MCP App) and the SSEClient (MCP Server).\n * Handles secure iframe sandboxing, resource loading, and bi-directional\n * communication via the AppBridge protocol.\n *\n * Key features:\n * - Secure iframe sandboxing with minimal permissions (proxy-based)\n * - Resource preloading for instant MCP App UI loading\n * - Cache-aware resource fetching (SSEClient cache → local cache → direct fetch)\n * - Support for ui:// and mcp-app:// resource URIs\n */\n\nimport { \n AppBridge, \n PostMessageTransport\n} from '@modelcontextprotocol/ext-apps/app-bridge';\nimport type { LoggingMessageNotification } from '@modelcontextprotocol/sdk/types.js';\nimport type { AppHostClient } from './types';\nimport { setupSandboxProxyIframe } from '../utils/app-host-utils.js';\nimport { APP_HOST_DEFAULTS } from './constants.js';\n\nexport type McpUiResourceCsp = Record<string, string>;\nexport type McpUiHostContext = Record<string, unknown>;\n\n// Define types dynamically from AppBridge properties instead of direct imports\n// which seem to fail in this tsconfig environment\ntype OnMessageHandler = NonNullable<AppBridge['onmessage']>;\nexport type McpUiMessageParams = Parameters<OnMessageHandler>[0];\nexport type RequestHandlerExtra = Parameters<OnMessageHandler>[1];\nexport type McpUiMessageResult = ReturnType<OnMessageHandler> extends Promise<infer R> ? R : never;\n\ntype OnOpenLinkHandler = NonNullable<AppBridge['onopenlink']>;\nexport type McpUiOpenLinkParams = Parameters<OnOpenLinkHandler>[0];\nexport type McpUiOpenLinkResult = ReturnType<OnOpenLinkHandler> extends Promise<infer R> ? R : never;\n\ntype OnSizeChangeHandler = NonNullable<AppBridge['onsizechange']>;\nexport type McpUiSizeChangedParams = Parameters<OnSizeChangeHandler>[0];\n\ntype OnRequestDisplayModeHandler = NonNullable<AppBridge['onrequestdisplaymode']>;\nexport type McpUiRequestDisplayModeParams = Parameters<OnRequestDisplayModeHandler>[0];\nexport type McpUiRequestDisplayModeResult = ReturnType<OnRequestDisplayModeHandler> extends Promise<infer R> ? R : never;\n\n\n// ============================================\n// Types & Interfaces\n// ============================================\n\nexport interface SandboxConfig {\n url: URL | string;\n permissions?: string;\n csp?: McpUiResourceCsp;\n}\n\n/**\n * Default Content-Security-Policy for MCP App iframes.\n *\n * Allows inline scripts/styles (required by most MCP App frameworks),\n * outbound network connections, and common asset sources, while blocking\n * nested frames and plugin objects.\n *\n * Pass this (or a spread of it) as `sandbox.csp` to enforce it:\n * @example\n * sandbox={{ url: '/sandbox.html', csp: DEFAULT_MCP_APP_CSP }}\n * // or to extend:\n * sandbox={{ url: '/sandbox.html', csp: { ...DEFAULT_MCP_APP_CSP, 'connect-src': \"'self' https://api.example.com\" } }}\n */\nexport const DEFAULT_MCP_APP_CSP: McpUiResourceCsp = {\n 'default-src': \"'self'\",\n 'script-src': \"'self' 'unsafe-inline' 'unsafe-eval' https: blob:\",\n 'style-src': \"'self' 'unsafe-inline' https:\",\n 'connect-src': \"'self' https: wss:\",\n 'img-src': \"'self' data: https: blob:\",\n 'font-src': \"'self' data: https:\",\n 'media-src': \"'self' https: blob:\",\n 'frame-src': \"'none'\",\n 'object-src': \"'none'\",\n 'base-uri': \"'self'\",\n};\n\nexport interface AppHostOptions {\n /** Enable debug logging @default false */\n debug?: boolean;\n /** Sandbox proxy configuration */\n sandbox?: SandboxConfig;\n /** Host context for theming, viewport, locale */\n hostContext?: McpUiHostContext;\n /** Custom handler for call tool requests, overriding automatic client forwarding */\n onCallTool?: (params: ToolCallParams) => Promise<unknown>;\n /** Custom handler for resources/read */\n onReadResource?: (uri: string) => Promise<ResourceResponse>;\n /** Custom handler for fallback JSON-RPC requests */\n onFallbackRequest?: (request: any) => Promise<any>;\n \n /** Handler for open-link requests from the guest UI */\n onOpenLink?: (\n params: McpUiOpenLinkParams,\n extra: RequestHandlerExtra,\n ) => Promise<McpUiOpenLinkResult>;\n\n /** Handler for message requests from the guest UI */\n onMessage?: (\n params: McpUiMessageParams,\n extra: RequestHandlerExtra,\n ) => Promise<McpUiMessageResult>;\n\n /** Handler for logging messages from the guest UI */\n onLoggingMessage?: (params: LoggingMessageNotification['params']) => void;\n\n /** Handler for size change notifications from the guest UI */\n onSizeChanged?: (params: McpUiSizeChangedParams) => void;\n\n /** Callback invoked when an error occurs during setup or message handling */\n onError?: (error: Error) => void;\n\n /** Handler for display mode change requests from the guest UI */\n onRequestDisplayMode?: (\n params: McpUiRequestDisplayModeParams,\n extra: RequestHandlerExtra,\n ) => Promise<McpUiRequestDisplayModeResult>;\n}\n\nexport interface AppMessageParams {\n role: string;\n content: unknown;\n}\n\ninterface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\ninterface ResourceContent {\n blob?: string;\n text?: string;\n}\n\ninterface ResourceResponse {\n contents: ResourceContent[];\n}\n\n// ============================================\n// Constants\n// ============================================\n\nconst HOST_INFO = APP_HOST_DEFAULTS.HOST_INFO;\n\n\n/** Supported MCP App URI schemes */\nconst MCP_URI_SCHEMES = APP_HOST_DEFAULTS.URI_SCHEMES;\n\n// ============================================\n// AppHost Class\n// ============================================\n\n/**\n * Host for MCP Apps embedded in iframes.\n * Manages secure communication between the app and the MCP server.\n */\nexport class AppHost {\n private bridge: AppBridge;\n private sessionId?: string;\n private resourceCache = new Map<string, Promise<ResourceResponse | null>>();\n private debug: boolean;\n\n private sandboxConfig?: SandboxConfig;\n private options: AppHostOptions;\n public onAppMessage?: (params: AppMessageParams) => void;\n\n constructor(\n private readonly client: AppHostClient | null,\n private readonly iframe: HTMLIFrameElement,\n options?: AppHostOptions\n ) {\n this.options = options || {};\n this.debug = this.options.debug ?? false;\n this.sandboxConfig = this.options.sandbox;\n\n this.bridge = this.initializeBridge();\n }\n\n // ============================================\n // Public API\n // ============================================\n\n /**\n * Start the host. This prepares the bridge handlers but doesn't connect yet.\n * The actual connection happens in launch() after HTML is loaded.\n * @returns Promise that resolves immediately (bridge connects during launch)\n */\n async start(): Promise<void> {\n // Bridge handlers are already registered in constructor.\n // Connection happens in launch() after HTML is loaded.\n this.log('Host started, ready to launch');\n }\n\n /**\n * Preload UI resources to enable instant app loading.\n * Call this when tools are discovered to cache their UI resources.\n */\n preload(tools: Array<{ _meta?: unknown }>): void {\n for (const tool of tools) {\n const uri = this.extractUiResourceUri(tool);\n if (!uri || this.resourceCache.has(uri)) continue;\n\n const promise = this.preloadResource(uri);\n this.resourceCache.set(uri, promise);\n }\n }\n\n /**\n * Launch an MCP App from a URL, MCP resource URI, or RAW HTML.\n * Loads the HTML first, then establishes bridge connection.\n */\n async launch(source: { uri?: string; html?: string }, sessionId?: string): Promise<void> {\n if (sessionId) this.sessionId = sessionId;\n\n const initializedPromise = this.onAppReady();\n\n let htmlToRender = source.html;\n\n if (!htmlToRender && source.uri) {\n if (this.isMcpUri(source.uri)) {\n htmlToRender = await this.readMcpAppHtml(source.uri);\n }\n }\n\n if (!htmlToRender && source.uri && !this.isMcpUri(source.uri)) {\n // Fallback for regular urls without proxy\n this.iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-forms allow-modals allow-popups allow-downloads');\n this.iframe.src = source.uri;\n await this.onIframeReady();\n await this.connectBridge();\n } else if (htmlToRender) {\n if (!this.sandboxConfig) {\n throw new Error(\"Sandbox configuration requires a proxy URL to render HTML safely.\");\n }\n await this.launchSandboxedHtml(htmlToRender, this.sandboxConfig);\n await this.connectBridge();\n\n this.log('Sending HTML resource to sandbox proxy (MCP Apps notification)');\n await this.bridge.sendSandboxResourceReady({\n html: htmlToRender,\n csp: this.sandboxConfig.csp,\n });\n }\n\n this.log('Waiting for app initialization');\n await Promise.race([\n initializedPromise,\n new Promise<void>((resolve) => setTimeout(() => {\n this.log('Initialization timeout - continuing anyway', 'warn');\n resolve();\n }, 3000))\n ]);\n this.log('App launched and ready');\n }\n\n // Set host context manually\n setHostContext(context: McpUiHostContext): void {\n this.options.hostContext = context;\n if (this.bridge) {\n this.bridge.setHostContext(context);\n }\n }\n\n // Send streaming inputs manually\n sendToolInputPartial(params: any): void {\n if (this.bridge) {\n (this.bridge as any).sendToolInputPartial(params);\n }\n }\n\n /**\n * Wait for app to signal initialization complete\n */\n private onAppReady(): Promise<void> {\n return new Promise<void>((resolve) => {\n const originalHandler = this.bridge.oninitialized;\n this.bridge.oninitialized = (...args) => {\n this.log('App initialized');\n resolve();\n this.bridge.oninitialized = originalHandler;\n originalHandler?.(...args);\n };\n });\n }\n\n /**\n * Wait for iframe to finish loading\n */\n private onIframeReady(): Promise<void> {\n return new Promise((resolve) => {\n if (this.iframe.contentDocument?.readyState === 'complete') {\n resolve();\n return;\n }\n this.iframe.addEventListener('load', () => resolve(), { once: true });\n });\n }\n\n /**\n * Send tool input arguments to the MCP App.\n * Call this after launch() when tool input is available.\n */\n sendToolInput(args: Record<string, unknown>): void {\n this.log('Sending tool input to app');\n this.bridge.sendToolInput({ arguments: args });\n }\n\n /**\n * Send tool result to the MCP App.\n * Call this when the tool call completes.\n */\n sendToolResult(result: unknown): void {\n this.log('Sending tool result to app');\n this.bridge.sendToolResult(result as any);\n }\n\n /**\n * Send tool cancellation to the MCP App.\n * Call this when the tool call is cancelled or fails.\n */\n sendToolCancelled(reason: string): void {\n this.log('Sending tool cancellation to app');\n this.bridge.sendToolCancelled({ reason });\n }\n\n /**\n * Tell the guest UI the resource is being torn down (unload / cleanup).\n * Forwards to {@link AppBridge.teardownResource} on `@modelcontextprotocol/ext-apps/app-bridge`.\n */\n teardownResource(params: Record<string, unknown> = {}): void {\n this.log('Sending resource teardown to app');\n this.bridge.teardownResource(params as never);\n }\n\n // ============================================\n // Private: Initialization\n // ============================================\n\n\n private initializeBridge(): AppBridge {\n const bridge = new AppBridge(\n null,\n HOST_INFO,\n {\n openLinks: {},\n serverTools: {},\n logging: {},\n updateModelContext: { text: {} },\n },\n {\n hostContext: this.options.hostContext || {\n theme: 'dark',\n platform: 'web',\n containerDimensions: { maxHeight: 6000 },\n displayMode: 'inline',\n availableDisplayModes: ['inline', 'fullscreen'],\n },\n }\n );\n\n ;(bridge as any).fallbackRequestHandler = this.options.onFallbackRequest;\n \n bridge.oncalltool = (params) => this.handleToolCall(params);\n if (this.options.onReadResource) {\n bridge.onreadresource = async (params) => {\n const resp = await this.options.onReadResource!(params.uri);\n return { \n contents: resp.contents.map(c => ({\n uri: params.uri,\n text: c.text as string,\n blob: c.blob as string,\n }))\n };\n };\n }\n\n bridge.onopenlink = async (params, extra) => {\n if (this.options.onOpenLink) {\n return await this.options.onOpenLink(params, extra as any);\n }\n return this.handleOpenLink(params);\n };\n bridge.onmessage = async (params, extra) => {\n if (this.options.onMessage) {\n return await this.options.onMessage(params, extra as any);\n }\n return this.handleMessage(params as any);\n };\n bridge.onloggingmessage = (params) => {\n this.log(`App log [${params.level}]: ${params.data}`);\n if (this.options.onLoggingMessage) {\n this.options.onLoggingMessage(params);\n }\n };\n bridge.onupdatemodelcontext = async () => ({});\n bridge.onsizechange = async (params) => {\n const { width, height } = params;\n // Guard: ignore transient 0px resize events (e.g. fired by guest during viewport transitions)\n if (height !== undefined && height > 0) {\n this.iframe.style.height = `${height}px`;\n }\n if (width !== undefined && width > 0) this.iframe.style.minWidth = `min(${width}px, 100%)`;\n if (this.options.onSizeChanged) {\n this.options.onSizeChanged(params);\n }\n return {};\n };\n bridge.onrequestdisplaymode = async (params, extra) => {\n if (this.options.onRequestDisplayMode) {\n return await this.options.onRequestDisplayMode(params, extra as any);\n }\n return { mode: params.mode === 'fullscreen' ? 'fullscreen' : 'inline' };\n };\n\n return bridge;\n }\n\n private async connectBridge(): Promise<void> {\n this.log('Connecting bridge to iframe');\n\n const transport = new PostMessageTransport(\n this.iframe.contentWindow!,\n this.iframe.contentWindow!\n );\n\n try {\n await this.bridge.connect(transport);\n this.log('Bridge connected successfully');\n } catch (error) {\n this.log('Bridge connection failed', 'error');\n if (this.options.onError) {\n this.options.onError(error instanceof Error ? error : new Error(String(error)));\n }\n throw error;\n }\n }\n\n // ============================================\n // Private: Bridge Event Handlers\n // ============================================\n\n private async handleToolCall(params: ToolCallParams) {\n if (this.options.onCallTool) {\n return await this.options.onCallTool(params);\n }\n \n if (!this.client || !this.client.isConnected()) {\n throw new Error('Client disconnected or not provided');\n }\n\n const sessionId = await this.getSessionId();\n if (!sessionId) {\n throw new Error('No active session');\n }\n\n const result = await this.client.callTool(\n sessionId,\n params.name,\n params.arguments ?? {}\n );\n return result as any;\n }\n\n private async handleOpenLink(params: { url: string }): Promise<Record<string, never>> {\n window.open(params.url, '_blank', 'noopener,noreferrer');\n return {};\n }\n\n private async handleMessage(params: AppMessageParams): Promise<Record<string, never>> {\n this.onAppMessage?.(params);\n return {};\n }\n\n // ============================================\n // Private: Resource Loading\n // ============================================\n\n private async launchSandboxedHtml(html: string, config: SandboxConfig): Promise<void> {\n const sandboxUrlString = config.url instanceof URL ? config.url.href : config.url;\n const url = new URL(sandboxUrlString, globalThis.location?.href);\n if (config.csp && Object.keys(config.csp).length > 0) {\n url.searchParams.set('csp', JSON.stringify(config.csp));\n }\n\n const { onReady } = await setupSandboxProxyIframe(this.iframe, url);\n await onReady;\n }\n\n\n private async readMcpAppHtml(uri: string): Promise<string> {\n const sessionId = await this.getSessionId();\n if (!sessionId && !this.options.onReadResource) {\n throw new Error('No active session.');\n }\n const response = await this.fetchResourceWithCache(sessionId, uri);\n if (!response?.contents?.length) {\n throw new Error(`Empty resource: ${uri}`);\n }\n \n const content = response.contents[0];\n const html = this.decodeContent(content);\n if (!html) {\n throw new Error(`Invalid content in resource: ${uri}`);\n }\n return html;\n }\n\n private async fetchResourceWithCache(sessionId: string | undefined, uri: string): Promise<ResourceResponse> {\n if (this.options.onReadResource) {\n return await this.options.onReadResource(uri);\n }\n \n if (!sessionId) {\n throw new Error('No active session');\n }\n\n if (!this.client) {\n throw new Error('No client to read resource from');\n }\n \n // Priority 1: SSEClient's built-in cache (best performance)\n if (this.hasClientCache()) {\n return (this.client as any).getOrFetchResource(sessionId, uri);\n }\n\n // Priority 2: Local preload cache\n const cached = this.resourceCache.get(uri);\n if (cached) {\n const result = await cached;\n if (result) return result;\n }\n\n // Priority 3: Direct fetch\n return this.client.readResource(sessionId, uri) as Promise<ResourceResponse>;\n }\n\n private async preloadResource(uri: string): Promise<ResourceResponse | null> {\n try {\n if (this.options.onReadResource) {\n return await this.options.onReadResource(uri);\n }\n const sessionId = await this.getSessionId();\n if (!sessionId || !this.client) return null;\n return await this.client.readResource(sessionId, uri) as ResourceResponse;\n } catch (error) {\n this.log(`Preload failed for ${uri}`, 'warn');\n return null;\n }\n }\n\n // ============================================\n // Private: Utilities\n // ============================================\n\n private async getSessionId(): Promise<string | undefined> {\n if (this.sessionId) return this.sessionId;\n if (!this.client) return undefined;\n const result = await this.client.getSessions();\n return result.sessions?.[0]?.sessionId;\n }\n\n private isMcpUri(url: string): boolean {\n return MCP_URI_SCHEMES.some(scheme => url.startsWith(scheme));\n }\n\n private hasClientCache(): boolean {\n if (!this.client) return false;\n return 'getOrFetchResource' in this.client &&\n typeof (this.client as any).getOrFetchResource === 'function';\n }\n\n private extractUiResourceUri(tool: { _meta?: unknown }): string | undefined {\n const meta = tool._meta as { ui?: { resourceUri?: string; uri?: string } } | undefined;\n if (!meta?.ui) return undefined;\n return meta.ui.resourceUri ?? meta.ui.uri;\n }\n\n private decodeContent(content: ResourceContent): string | undefined {\n if (content.blob) {\n return atob(content.blob);\n }\n return content.text;\n }\n\n private log(message: string, level: 'info' | 'warn' | 'error' = 'info'): void {\n if (!this.debug && level === 'info') return;\n\n const prefix = '[AppHost]';\n switch (level) {\n case 'warn':\n console.warn(prefix, message);\n break;\n case 'error':\n console.error(prefix, message);\n break;\n default:\n console.log(prefix, message);\n }\n }\n}\n"]}