1+ // Copy of examples/basic-host/src/implementation.ts
2+
13import {
24 RESOURCE_MIME_TYPE ,
35 getToolUiResourceUri ,
@@ -318,7 +320,10 @@ export function newAppBridge(
318320
319321 // Per spec, the host SHOULD notify the view when container dimensions
320322 // change. A ResizeObserver on the iframe covers window resize, layout
321- // shifts, and the inline↔fullscreen panel toggle.
323+ // shifts, and the inline↔fullscreen panel toggle (which React applies
324+ // a tick after onrequestdisplaymode returns — sending containerDimensions
325+ // alongside displayMode there would race the layout). Height stays
326+ // flexible (maxHeight) so the view can keep driving it via sendSizeChanged.
322327 const iframeResizeObserver = new ResizeObserver ( ( [ entry ] ) => {
323328 const width = Math . round ( entry . contentRect . width ) ;
324329 if ( width > 0 ) {
@@ -366,16 +371,26 @@ export function newAppBridge(
366371 } ;
367372
368373 appBridge . onsizechange = async ( { width, height } ) => {
374+ // The MCP App has requested a `width` and `height`, but if
375+ // `box-sizing: border-box` is applied to the outer iframe element, then we
376+ // must add border thickness to `width` and `height` to compute the actual
377+ // necessary width and height (in order to prevent a resize feedback loop).
369378 const style = getComputedStyle ( iframe ) ;
370379 const isBorderBox = style . boxSizing === 'border-box' ;
371380
381+ // Animate the change for a smooth transition.
372382 const from : Keyframe = { } ;
373383 const to : Keyframe = { } ;
374384
375385 if ( width !== undefined ) {
376386 if ( isBorderBox ) {
377387 width += parseFloat ( style . borderLeftWidth ) + parseFloat ( style . borderRightWidth ) ;
378388 }
389+ // Use min-width instead of width to allow responsive growing.
390+ // With auto-resize (the default), the app reports its minimum content
391+ // width; we honor that as a floor but allow the iframe to expand when
392+ // the host layout allows. And we use `min(..., 100%)` so that the iframe
393+ // shrinks with its container.
379394 from [ 'minWidth' ] = `${ iframe . offsetWidth } px` ;
380395 iframe . style . minWidth = to [ 'minWidth' ] = `min(${ width } px, 100%)` ;
381396 }
@@ -394,7 +409,11 @@ export function newAppBridge(
394409 appBridge . onrequestdisplaymode = async ( params ) => {
395410 log . info ( 'Display mode request from MCP App:' , params ) ;
396411 const newMode = params . mode === 'fullscreen' ? 'fullscreen' : 'inline' ;
397- appBridge . sendHostContextChange ( { displayMode : newMode } ) ;
412+ // Update host context and notify the app
413+ appBridge . sendHostContextChange ( {
414+ displayMode : newMode ,
415+ } ) ;
416+ // Notify the host UI (via callback)
398417 callbacks ?. onDisplayModeChange ?.( newMode ) ;
399418 return { mode : newMode } ;
400419 } ;
0 commit comments