The Layout Contract
The Host sends layout state inhostContext during ui/initialize and may update it later with onhostcontextchanged.
| Field | Who sets it | What the View should do |
|---|---|---|
displayMode | Host | Switch layout density, controls, and navigation for inline, fullscreen, or pip. |
availableDisplayModes | Host | Only request modes that appear here. |
width or height | Host | Treat the dimension as fixed and fill it. |
maxWidth or maxHeight | Host | Let content size the iframe up to that limit, then scroll or paginate internally. |
| omitted dimension | Host | Let content define that dimension and report size changes. |
safeAreaInsets | Host | Pad fixed controls away from host chrome, notches, and mobile browser UI. |
Fixed vs Flexible Dimensions
Each axis is independent. A host can fix width while letting height grow, or fix both axes in fullscreen.Fixed Dimensions
IfcontainerDimensions.height or containerDimensions.width is set, the Host controls that axis. Fill the available space instead of reporting a larger preferred size.
Flexible Dimensions
If the Host sendsmaxHeight or maxWidth, the View can choose its content size up to that value. This is common for inline chat cards where the host wants the app to fit naturally in the conversation.
Auto-Resize
The Host can only resize flexible iframes when the View reports its content size. The SDK handles this by default:AppenablesautoResize: trueby default.- Auto-resize watches
document.bodyanddocument.documentElementwithResizeObserver. - When content changes, the View sends
ui/notifications/size-changed. - The Host updates iframe dimensions when the corresponding axis is flexible.
sendSizeChanged() only when DOM measurement is not enough, such as canvas rendering, virtualized content, or an animation whose final size is known after a transition.
Display Modes
Views declare supported display modes inMcpUiAppCapabilities. Hosts declare the modes they can provide in hostContext.availableDisplayModes. The View can request a mode, but the Host decides the final mode.
Safe Areas
UsesafeAreaInsets for fixed headers, footers, floating buttons, and mobile layouts. It is host-provided padding in pixels.
CSS Rules That Hold Up Across Hosts
Start with host-neutral document sizing:| Scenario | Recommended behavior |
|---|---|
| Inline card with flexible height | Let content size naturally and rely on auto-resize. |
Inline card with maxHeight | Set max-height and put overflow on the content region. |
Fullscreen with fixed height | Fill the viewport and scroll only the pane that needs it. |
| Canvas or map | Use a stable min-height or aspect ratio, then report the rendered size. |
| Mobile host | Use safe areas and avoid hover-only controls. |
100vh can be much larger than the chat card the Host is willing to show. Use it only when the Host has fixed the height or when your app is fullscreen.
Common Problems
| Problem | Likely cause | Fix |
|---|---|---|
| The iframe clips the bottom of the View | Auto-resize is disabled, or content size changed outside DOM layout. | Keep autoResize: true or call sendSizeChanged() after the change. |
| The app grows taller after every render | The View reports size while also adding layout that depends on the reported iframe size. | Remove feedback loops. In inline mode, let content define height or put overflow inside a fixed pane. |
| Fullscreen shows a tiny card | The View is still using inline max-width or card layout. | Branch on displayMode === "fullscreen" and fill the fixed container. |
| A fullscreen button does nothing | The Host does not expose fullscreen in availableDisplayModes, or it declined the request. | Hide unavailable mode controls and trust the returned mode. |
| Floating controls overlap host chrome | Safe area insets are ignored. | Add safeAreaInsets to fixed-position padding. |
Related
getHostContext()- Read display mode, dimensions, and safe areas.requestDisplayMode()- Ask the Host to switch display modes.sendSizeChanged()- Manually report View dimensions.setupSizeChangedNotifications()- Control auto-resize.useAutoResize- React wrapper for manual auto-resize control.