-
Notifications
You must be signed in to change notification settings - Fork 190
Description
Problem
autoResize: true is the default in the Apps SDK, and it is the #1 source of layout bugs for MCP App developers. We hit this issue four separate times during development of our Mermaid MCP App, each with a different root cause:
| # | Root Cause | Symptom |
|---|---|---|
| 1 | height: 100vh + autoResize: true |
Infinite growth feedback loop: height reported → host adjusts → taller → report again → ∞ |
| 2 | autoResize: true overriding explicit fixed height |
Set height: 500px in CSS, but autoResize kept reporting content height instead |
| 3 | Fullscreen exit with stale hostHeight |
After exiting fullscreen, height stayed at ~900px (the fullscreen value) |
| 4 | useApp() hook ignores autoResize: false |
useApp() internally creates App with autoResize: true always — the option is not exposed in UseAppOptions (removed in v1.0.1). Even @ts-expect-error workarounds don't work at runtime. |
Issue #4 is particularly painful
The recommended useApp() hook cannot be used by any App that needs height control. Developers must drop down to manual new App() construction:
// Cannot use useApp() — it forces autoResize: true
const app = new App(
{ name: "my-app", version: "0.1.0" },
{},
{ autoResize: false } // only available via manual construction
);Proposals
1. Change autoResize default to false
Most MCP Apps with non-trivial UI (diagrams, editors, canvases) need to control their own height. autoResize: true is only appropriate for simple content-driven displays. Making it opt-in would prevent the most common class of layout bugs.
2. Expose autoResize in useApp() hook
// Currently impossible — useApp() doesn't accept autoResize option
const app = useApp({ autoResize: false });3. Document the three height strategies
The SDK should document these patterns explicitly:
| Strategy | When to use | Implementation |
|---|---|---|
| Fixed height (recommended default) | Most Apps | autoResize: false + height: 500px + manual sendSizeChanged() |
| Content-driven with cap | Simple display Apps | autoResize: true + CSS max-height |
| Full viewport | Fullscreen only | requestDisplayMode("fullscreen") + height: 100vh |
With explicit warning: 100vh + autoResize: true = infinite growth loop.
4. Improve fullscreen ↔ inline transitions
When displayMode changes from fullscreen to inline, the host should re-send containerDimensions with inline-mode values. Currently the App must remember its pre-fullscreen height and manually reset — which is error-prone.
An onDisplayModeChanged callback that includes the new dimensions would solve this cleanly:
app.ondisplaymodechanged = ({ mode, containerDimensions }) => {
// mode: "inline" | "fullscreen"
// containerDimensions: the dimensions for the new mode
};Recommended pattern (for docs)
const DEFAULT_HEIGHT = 500;
// Do NOT use useApp() — it forces autoResize: true
const app = new App(
{ name: "my-app", version: "0.1.0" },
{},
{ autoResize: false }
);
// Register handlers BEFORE connect
app.ontoolinput = (params) => { /* ... */ };
app.onhostcontextchanged = (ctx) => {
const dims = ctx.containerDimensions;
if (dims?.height) hostHeight = dims.height;
else if (dims?.maxHeight) hostHeight = Math.min(DEFAULT_HEIGHT, dims.maxHeight);
else hostHeight = DEFAULT_HEIGHT;
};
await app.connect(transport);
// Report initial size (host doesn't know without autoResize)
app.sendSizeChanged({
width: document.documentElement.scrollWidth,
height: DEFAULT_HEIGHT,
});Context
From building 3 production MCP Apps (Mermaid, PlantUML, Music). Height management consumed more debugging time than any other single issue. Every MCP App developer will hit some variant of these bugs.