@@ -44,6 +44,8 @@ import type {
4444 SizeChangedParams ,
4545 CallToolHandler ,
4646 ListToolsHandler ,
47+ UpdateModelContextParams ,
48+ ContainerDimensions ,
4749} from "../types" ;
4850
4951/**
@@ -248,6 +250,7 @@ export class McpAdapter implements ProtocolAdapter {
248250 displayMode ?: unknown ;
249251 availableDisplayModes ?: unknown ;
250252 viewport ?: unknown ;
253+ containerDimensions ?: unknown ;
251254 locale ?: unknown ;
252255 timeZone ?: unknown ;
253256 platform ?: unknown ;
@@ -274,11 +277,22 @@ export class McpAdapter implements ProtocolAdapter {
274277 ? ctx . availableDisplayModes . filter ( ( m ) : m is string => typeof m === "string" )
275278 : base . availableDisplayModes ;
276279
277- const isViewportObject = ( v : unknown ) : v is Record < string , unknown > =>
280+ const isObjectLike = ( v : unknown ) : v is Record < string , unknown > =>
278281 v !== null && typeof v === "object" && ! Array . isArray ( v ) ;
279- const viewport = isViewportObject ( ctx . viewport )
280- ? { ...base . viewport , ...ctx . viewport }
281- : base . viewport ;
282+
283+ // Parse containerDimensions (ext-apps v0.4.0+)
284+ const containerDimensions = isObjectLike ( ctx . containerDimensions )
285+ ? ( ctx . containerDimensions as ContainerDimensions )
286+ : undefined ;
287+
288+ // Derive viewport from containerDimensions for backward compatibility,
289+ // or fall back to explicit viewport or defaults
290+ let viewport = base . viewport ;
291+ if ( containerDimensions ) {
292+ viewport = this . deriveViewportFromContainerDimensions ( containerDimensions , base . viewport ) ;
293+ } else if ( isObjectLike ( ctx . viewport ) ) {
294+ viewport = { ...base . viewport , ...ctx . viewport } ;
295+ }
282296
283297 const locale = typeof ctx . locale === "string" ? ctx . locale : base . locale ;
284298 const timeZone = typeof ctx . timeZone === "string" ? ctx . timeZone : base . timeZone ;
@@ -292,6 +306,7 @@ export class McpAdapter implements ProtocolAdapter {
292306 displayMode,
293307 availableDisplayModes,
294308 viewport,
309+ containerDimensions,
295310 locale,
296311 timeZone,
297312 platform,
@@ -303,6 +318,23 @@ export class McpAdapter implements ProtocolAdapter {
303318 } ;
304319 }
305320
321+ /**
322+ * Derive viewport dimensions from containerDimensions for backward compatibility.
323+ * containerDimensions uses fixed (height/width) vs flexible (maxHeight/maxWidth) semantics.
324+ */
325+ private deriveViewportFromContainerDimensions (
326+ dims : ContainerDimensions ,
327+ defaults : HostContext [ "viewport" ]
328+ ) : HostContext [ "viewport" ] {
329+ const d = dims as Record < string , unknown > ;
330+ return {
331+ width : typeof d . width === "number" ? d . width : defaults . width ,
332+ height : typeof d . height === "number" ? d . height : defaults . height ,
333+ maxWidth : typeof d . maxWidth === "number" ? d . maxWidth : undefined ,
334+ maxHeight : typeof d . maxHeight === "number" ? d . maxHeight : undefined ,
335+ } ;
336+ }
337+
306338 private extractToolMeta ( rawHostContext : unknown ) : Record < string , unknown > | undefined {
307339 if ( rawHostContext === null || typeof rawHostContext !== "object" ) return undefined ;
308340 const hc = rawHostContext as { toolInfo ?: unknown } ;
@@ -388,6 +420,42 @@ export class McpAdapter implements ProtocolAdapter {
388420 } ) ;
389421 }
390422
423+ // === Model Context ===
424+
425+ async updateModelContext ( params : UpdateModelContextParams ) : Promise < void > {
426+ if ( ! this . app ) {
427+ throw new UIError ( UIErrorCode . NOT_CONNECTED , "MCP Apps adapter not connected" ) ;
428+ }
429+
430+ // Map our content blocks to ext-apps format
431+ const content = params . content ?. map ( ( block ) => {
432+ switch ( block . type ) {
433+ case "text" :
434+ return { type : "text" as const , text : block . text ?? "" } ;
435+ case "image" :
436+ return {
437+ type : "image" as const ,
438+ data : block . data ?? "" ,
439+ mimeType : block . mimeType ?? "image/png" ,
440+ } ;
441+ case "audio" :
442+ return {
443+ type : "audio" as const ,
444+ data : block . data ?? "" ,
445+ mimeType : block . mimeType ?? "audio/wav" ,
446+ } ;
447+ default :
448+ // For resource types, fall back to text representation
449+ return { type : "text" as const , text : block . text ?? block . uri ?? "" } ;
450+ }
451+ } ) ;
452+
453+ await this . app . updateModelContext ( {
454+ content,
455+ structuredContent : params . structuredContent ,
456+ } ) ;
457+ }
458+
391459 // === Navigation ===
392460
393461 async openLink ( url : string ) : Promise < void > {
@@ -548,19 +616,19 @@ export class McpAdapter implements ProtocolAdapter {
548616 // Map MCP Apps SDK capabilities to our unified interface.
549617 // MCP SDK already provides: logging, openLinks, serverResources, serverTools
550618 // We augment with common abstraction fields for protocol-agnostic usage.
551- const sdkCaps = mcpCaps as HostCapabilities ;
619+ const sdkCaps = mcpCaps as Record < string , unknown > ;
552620
553621 // Extract available display modes from host context if provided
554622 const hostContext = this . app . getHostContext ( ) ;
555623 const availableModes = hostContext ?. availableDisplayModes as string [ ] | undefined ;
556624
557625 return {
558626 // MCP SDK native capabilities (priority)
559- logging : sdkCaps . logging ,
560- openLinks : sdkCaps . openLinks ,
561- serverResources : sdkCaps . serverResources ,
562- serverTools : sdkCaps . serverTools ,
563- experimental : sdkCaps . experimental ,
627+ logging : sdkCaps . logging as HostCapabilities [ "logging" ] ,
628+ openLinks : sdkCaps . openLinks as HostCapabilities [ "openLinks" ] ,
629+ serverResources : sdkCaps . serverResources as HostCapabilities [ "serverResources" ] ,
630+ serverTools : sdkCaps . serverTools as HostCapabilities [ "serverTools" ] ,
631+ experimental : sdkCaps . experimental as HostCapabilities [ "experimental" ] ,
564632
565633 // Common capabilities derived from host context when available
566634 theming : {
@@ -578,6 +646,11 @@ export class McpAdapter implements ProtocolAdapter {
578646 sizeNotifications : { } ,
579647 partialToolInput : { } ,
580648 appTools : { listChanged : false } ,
649+
650+ // ext-apps v0.4.0+ capabilities
651+ updateModelContext : sdkCaps . updateModelContext as HostCapabilities [ "updateModelContext" ] ,
652+ message : sdkCaps . message as HostCapabilities [ "message" ] ,
653+ sandbox : sdkCaps . sandbox as HostCapabilities [ "sandbox" ] ,
581654 } ;
582655 }
583656
0 commit comments