Skip to content

Commit 04b60b9

Browse files
martinalongclaude
andcommitted
Restore app sending both width and height for backwards compatibility
The SDK App class now sends both width and height in size-changed notifications to maintain backwards compatibility with older hosts. Hosts only use the height value but receive both. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 754c227 commit 04b60b9

File tree

4 files changed

+24
-14
lines changed

4 files changed

+24
-14
lines changed

src/app.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -850,11 +850,11 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
850850
* Apps can manually report size changes to help the host adjust the iframe.
851851
* If `autoResize` is enabled (default), this is called automatically.
852852
*
853-
* @param params - New height in pixels
853+
* @param params - New width and/or height in pixels
854854
*
855855
* @example Manually notify host of size change
856856
* ```typescript
857-
* app.sendSizeChanged({ height: 600 });
857+
* app.sendSizeChanged({ width: 400, height: 600 });
858858
* ```
859859
*
860860
* @returns Promise that resolves when the notification is sent
@@ -895,6 +895,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
895895
*/
896896
setupSizeChangedNotifications() {
897897
let scheduled = false;
898+
let lastWidth = 0;
898899
let lastHeight = 0;
899900

900901
const sendBodySizeChanged = () => {
@@ -909,8 +910,6 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
909910
// Measure actual content size by temporarily setting html to fit-content.
910911
// This shrinks html to fit body (including body margins), giving us the
911912
// true minimum size needed by the content.
912-
// Note: We must set both width and height to fit-content for accurate
913-
// measurement, as setting only height can cause incorrect layout calculation.
914913
const originalWidth = html.style.width;
915914
const originalHeight = html.style.height;
916915
html.style.width = "fit-content";
@@ -919,12 +918,18 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
919918
html.style.width = originalWidth;
920919
html.style.height = originalHeight;
921920

921+
// Compensate for scrollbar width on Linux/Windows where scrollbars consume space.
922+
// On systems with overlay scrollbars (macOS), this will be 0.
923+
const scrollbarWidth = window.innerWidth - html.clientWidth;
924+
925+
const width = Math.ceil(rect.width + scrollbarWidth);
922926
const height = Math.ceil(rect.height);
923927

924-
// Only send if height actually changed (prevents feedback loops from style changes)
925-
if (height !== lastHeight) {
928+
// Only send if size actually changed (prevents feedback loops from style changes)
929+
if (width !== lastWidth || height !== lastHeight) {
930+
lastWidth = width;
926931
lastHeight = height;
927-
this.sendSizeChanged({ height });
932+
this.sendSizeChanged({ width, height });
928933
}
929934
});
930935
};

src/generated/schema.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2943,12 +2943,15 @@
29432943
"params": {
29442944
"type": "object",
29452945
"properties": {
2946+
"width": {
2947+
"description": "New width in pixels.",
2948+
"type": "number"
2949+
},
29462950
"height": {
29472951
"description": "New height in pixels.",
29482952
"type": "number"
29492953
}
29502954
},
2951-
"required": ["height"],
29522955
"additionalProperties": false
29532956
}
29542957
},

src/generated/schema.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,15 +216,16 @@ export const McpUiSandboxResourceReadyNotificationSchema = z.object({
216216
});
217217

218218
/**
219-
* @description Notification of UI size change (Guest -> Host).
220-
* Sent when the Guest UI's content height changes, allowing the host to resize the iframe.
219+
* @description Notification of UI size changes (bidirectional: Guest <-> Host).
221220
* @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI
222221
*/
223222
export const McpUiSizeChangedNotificationSchema = z.object({
224223
method: z.literal("ui/notifications/size-changed"),
225224
params: z.object({
225+
/** @description New width in pixels. */
226+
width: z.number().optional().describe("New width in pixels."),
226227
/** @description New height in pixels. */
227-
height: z.number().describe("New height in pixels."),
228+
height: z.number().optional().describe("New height in pixels."),
228229
}),
229230
});
230231

src/spec.types.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,16 @@ export interface McpUiSandboxResourceReadyNotification {
227227
}
228228

229229
/**
230-
* @description Notification of UI size change (Guest -> Host).
231-
* Sent when the Guest UI's content height changes, allowing the host to resize the iframe.
230+
* @description Notification of UI size changes (bidirectional: Guest <-> Host).
232231
* @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI
233232
*/
234233
export interface McpUiSizeChangedNotification {
235234
method: "ui/notifications/size-changed";
236235
params: {
236+
/** @description New width in pixels. */
237+
width?: number;
237238
/** @description New height in pixels. */
238-
height: number;
239+
height?: number;
239240
};
240241
}
241242

0 commit comments

Comments
 (0)