Skip to content

Commit ac1d83c

Browse files
committed
Update onsizechange to onheightchange
1 parent ced5954 commit ac1d83c

File tree

10 files changed

+99
-126
lines changed

10 files changed

+99
-126
lines changed

specification/draft/apps.mdx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -638,20 +638,19 @@ Host MUST send this notification if the tool execution was cancelled, for any re
638638
Host MUST send this notification before tearing down the UI resource, for any reason, including user action, resource re-allocation, etc. The Host MAY specify the reason.
639639
Host SHOULD wait for a response before tearing down the resource (to prevent data loss).
640640

641-
`ui/notifications/size-changed` - UI’s size changed
641+
`ui/notifications/height-changed` - UI's height changed
642642

643643
```typescript
644644
{
645645
jsonrpc: "2.0",
646-
method: "ui/notifications/size-changed",
646+
method: "ui/notifications/height-changed",
647647
params: {
648-
width: number, // Viewport width in pixels
649-
height: number // Viewport height in pixels
648+
height: number // Content height in pixels
650649
}
651650
}
652651
```
653652

654-
Guest UI SHOULD send this notification when rendered content body size changes (e.g. using ResizeObserver API to report up to date size).
653+
Guest UI SHOULD send this notification when rendered content height changes (e.g. using ResizeObserver API to report up to date height). This allows the host to dynamically resize the iframe to fit the content.
655654

656655
`ui/notifications/host-context-changed` - Host context has changed
657656

@@ -780,7 +779,7 @@ sequenceDiagram
780779
H --> UI: resources/read response
781780
end
782781
opt UI notifications
783-
UI ->> H: notifications (e.g., ui/notifications/size-changed)
782+
UI ->> H: notifications (e.g., ui/notifications/height-changed)
784783
end
785784
opt Host notifications
786785
H ->> UI: notifications (e.g., ui/notifications/host-context-changed)

src/app-bridge.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -403,16 +403,16 @@ describe("App <-> AppBridge integration", () => {
403403
await bridge.connect(bridgeTransport);
404404
});
405405

406-
it("app.sendSizeChanged triggers bridge.onsizechange", async () => {
407-
const receivedSizes: unknown[] = [];
408-
bridge.onsizechange = (params) => {
409-
receivedSizes.push(params);
406+
it("app.sendHeightChanged triggers bridge.onheightchange", async () => {
407+
const receivedHeights: unknown[] = [];
408+
bridge.onheightchange = (params) => {
409+
receivedHeights.push(params);
410410
};
411411

412412
await app.connect(appTransport);
413-
await app.sendSizeChanged({ width: 400, height: 600 });
413+
await app.sendHeightChanged({ height: 600 });
414414

415-
expect(receivedSizes).toEqual([{ width: 400, height: 600 }]);
415+
expect(receivedHeights).toEqual([{ height: 600 }]);
416416
});
417417

418418
it("app.sendLog triggers bridge.onloggingmessage", async () => {

src/app-bridge.ts

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import {
4444
type AppRequest,
4545
type AppResult,
4646
type McpUiSandboxResourceReadyNotification,
47-
type McpUiSizeChangedNotification,
47+
type McpUiHeightChangedNotification,
4848
type McpUiToolCancelledNotification,
4949
type McpUiToolInputNotification,
5050
type McpUiToolInputPartialNotification,
@@ -70,7 +70,7 @@ import {
7070
McpUiResourceTeardownResultSchema,
7171
McpUiSandboxProxyReadyNotification,
7272
McpUiSandboxProxyReadyNotificationSchema,
73-
McpUiSizeChangedNotificationSchema,
73+
McpUiHeightChangedNotificationSchema,
7474
} from "./types";
7575
export * from "./types";
7676
export { RESOURCE_URI_META_KEY, RESOURCE_MIME_TYPE } from "./app";
@@ -294,34 +294,26 @@ export class AppBridge extends Protocol<
294294
onping?: (params: PingRequest["params"], extra: RequestHandlerExtra) => void;
295295

296296
/**
297-
* Register a handler for size change notifications from the Guest UI.
297+
* Register a handler for height change notifications from the Guest UI.
298298
*
299-
* The Guest UI sends `ui/notifications/size-changed` when its rendered content
300-
* size changes, typically via ResizeObserver. Set this callback to dynamically
301-
* adjust the iframe container dimensions based on the Guest UI's content.
302-
*
303-
* Note: This is for Guest UI → Host communication. To notify the Guest UI of
304-
* host viewport changes, use {@link app.App.sendSizeChanged}.
299+
* The Guest UI sends `ui/notifications/height-changed` when its rendered content
300+
* height changes, typically via ResizeObserver. Set this callback to dynamically
301+
* adjust the iframe height based on the Guest UI's content.
305302
*
306303
* @example
307304
* ```typescript
308-
* bridge.onsizechange = ({ width, height }) => {
309-
* if (width != null) {
310-
* iframe.style.width = `${width}px`;
311-
* }
312-
* if (height != null) {
313-
* iframe.style.height = `${height}px`;
314-
* }
305+
* bridge.onheightchange = ({ height }) => {
306+
* iframe.style.height = `${height}px`;
315307
* };
316308
* ```
317309
*
318-
* @see {@link McpUiSizeChangedNotification} for the notification type
319-
* @see {@link app.App.sendSizeChanged} for Host → Guest UI size notifications
310+
* @see {@link McpUiHeightChangedNotification} for the notification type
311+
* @see {@link app.App.sendHeightChanged} for the Guest UI method
320312
*/
321-
set onsizechange(
322-
callback: (params: McpUiSizeChangedNotification["params"]) => void,
313+
set onheightchange(
314+
callback: (params: McpUiHeightChangedNotification["params"]) => void,
323315
) {
324-
this.setNotificationHandler(McpUiSizeChangedNotificationSchema, (n) =>
316+
this.setNotificationHandler(McpUiHeightChangedNotificationSchema, (n) =>
325317
callback(n.params),
326318
);
327319
}

src/app.ts

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import {
3333
McpUiResourceTeardownRequest,
3434
McpUiResourceTeardownRequestSchema,
3535
McpUiResourceTeardownResult,
36-
McpUiSizeChangedNotification,
36+
McpUiHeightChangedNotification,
3737
McpUiToolCancelledNotification,
3838
McpUiToolCancelledNotificationSchema,
3939
McpUiToolInputNotification,
@@ -94,10 +94,10 @@ export const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
9494
*/
9595
type AppOptions = ProtocolOptions & {
9696
/**
97-
* Automatically report size changes to the host using ResizeObserver.
97+
* Automatically report height changes to the host using ResizeObserver.
9898
*
9999
* When enabled, the App monitors `document.body` and `document.documentElement`
100-
* for size changes and automatically sends `ui/notifications/size-changed`
100+
* for size changes and automatically sends `ui/notifications/height-changed`
101101
* notifications to the host.
102102
*
103103
* @default true
@@ -840,37 +840,34 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
840840
}
841841

842842
/**
843-
* Notify the host of UI size changes.
843+
* Notify the host of UI height change.
844844
*
845-
* Apps can manually report size changes to help the host adjust the container.
845+
* Apps can manually report height changes to help the host adjust the iframe.
846846
* If `autoResize` is enabled (default), this is called automatically.
847847
*
848-
* @param params - New width and height in pixels
848+
* @param params - New height in pixels
849849
*
850-
* @example Manually notify host of size change
850+
* @example Manually notify host of height change
851851
* ```typescript
852-
* app.sendSizeChanged({
853-
* width: 400,
854-
* height: 600
855-
* });
852+
* app.sendHeightChanged({ height: 600 });
856853
* ```
857854
*
858855
* @returns Promise that resolves when the notification is sent
859856
*
860-
* @see {@link McpUiSizeChangedNotification} for notification structure
857+
* @see {@link McpUiHeightChangedNotification} for notification structure
861858
*/
862-
sendSizeChanged(params: McpUiSizeChangedNotification["params"]) {
863-
return this.notification(<McpUiSizeChangedNotification>{
864-
method: "ui/notifications/size-changed",
859+
sendHeightChanged(params: McpUiHeightChangedNotification["params"]) {
860+
return this.notification(<McpUiHeightChangedNotification>{
861+
method: "ui/notifications/height-changed",
865862
params,
866863
});
867864
}
868865

869866
/**
870-
* Set up automatic size change notifications using ResizeObserver.
867+
* Set up automatic height change notifications using ResizeObserver.
871868
*
872869
* Observes both `document.documentElement` and `document.body` for size changes
873-
* and automatically sends `ui/notifications/size-changed` notifications to the host.
870+
* and automatically sends `ui/notifications/height-changed` notifications to the host.
874871
* The notifications are debounced using requestAnimationFrame to avoid duplicates.
875872
*
876873
* Note: This method is automatically called by `connect()` if the `autoResize`
@@ -885,18 +882,17 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
885882
* await app.connect(transport);
886883
*
887884
* // Later, enable auto-resize manually
888-
* const cleanup = app.setupSizeChangedNotifications();
885+
* const cleanup = app.setupHeightChangedNotifications();
889886
*
890887
* // Clean up when done
891888
* cleanup();
892889
* ```
893890
*/
894-
setupSizeChangedNotifications() {
891+
setupHeightChangedNotifications() {
895892
let scheduled = false;
896-
let lastWidth = 0;
897893
let lastHeight = 0;
898894

899-
const sendBodySizeChanged = () => {
895+
const sendBodyHeightChanged = () => {
900896
if (scheduled) {
901897
return;
902898
}
@@ -905,36 +901,27 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
905901
scheduled = false;
906902
const html = document.documentElement;
907903

908-
// Measure actual content size by temporarily setting html to fit-content.
904+
// Measure actual content height by temporarily setting html to fit-content.
909905
// This shrinks html to fit body (including body margins), giving us the
910-
// true minimum size needed by the content.
911-
const originalWidth = html.style.width;
906+
// true minimum height needed by the content.
912907
const originalHeight = html.style.height;
913-
html.style.width = "fit-content";
914908
html.style.height = "fit-content";
915909
const rect = html.getBoundingClientRect();
916-
html.style.width = originalWidth;
917910
html.style.height = originalHeight;
918911

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

926-
// Only send if size actually changed (prevents feedback loops from style changes)
927-
if (width !== lastWidth || height !== lastHeight) {
928-
lastWidth = width;
914+
// Only send if height actually changed (prevents feedback loops from style changes)
915+
if (height !== lastHeight) {
929916
lastHeight = height;
930-
this.sendSizeChanged({ width, height });
917+
this.sendHeightChanged({ height });
931918
}
932919
});
933920
};
934921

935-
sendBodySizeChanged();
922+
sendBodyHeightChanged();
936923

937-
const resizeObserver = new ResizeObserver(sendBodySizeChanged);
924+
const resizeObserver = new ResizeObserver(sendBodyHeightChanged);
938925
// Observe both html and body to catch all size changes
939926
resizeObserver.observe(document.documentElement);
940927
resizeObserver.observe(document.body);
@@ -950,7 +937,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
950937
* 2. Sends `ui/initialize` request with app info and capabilities
951938
* 3. Receives host capabilities and context in response
952939
* 4. Sends `ui/notifications/initialized` notification
953-
* 5. Sets up auto-resize using {@link setupSizeChangedNotifications} if enabled (default)
940+
* 5. Sets up auto-resize using {@link setupHeightChangedNotifications} if enabled (default)
954941
*
955942
* If initialization fails, the connection is automatically closed and an error
956943
* is thrown.
@@ -1012,7 +999,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
1012999
});
10131000

10141001
if (this.options?.autoResize) {
1015-
this.setupSizeChangedNotifications();
1002+
this.setupHeightChangedNotifications();
10161003
}
10171004
} catch (error) {
10181005
// Disconnect if initialization fails.

src/generated/schema.json

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,29 @@
4646
}
4747
]
4848
},
49+
"McpUiHeightChangedNotification": {
50+
"$schema": "https://json-schema.org/draft/2020-12/schema",
51+
"type": "object",
52+
"properties": {
53+
"method": {
54+
"type": "string",
55+
"const": "ui/notifications/height-changed"
56+
},
57+
"params": {
58+
"type": "object",
59+
"properties": {
60+
"height": {
61+
"description": "New height in pixels.",
62+
"type": "number"
63+
}
64+
},
65+
"required": ["height"],
66+
"additionalProperties": false
67+
}
68+
},
69+
"required": ["method", "params"],
70+
"additionalProperties": false
71+
},
4972
"McpUiHostCapabilities": {
5073
"$schema": "https://json-schema.org/draft/2020-12/schema",
5174
"type": "object",
@@ -1632,32 +1655,6 @@
16321655
"required": ["method", "params"],
16331656
"additionalProperties": false
16341657
},
1635-
"McpUiSizeChangedNotification": {
1636-
"$schema": "https://json-schema.org/draft/2020-12/schema",
1637-
"type": "object",
1638-
"properties": {
1639-
"method": {
1640-
"type": "string",
1641-
"const": "ui/notifications/size-changed"
1642-
},
1643-
"params": {
1644-
"type": "object",
1645-
"properties": {
1646-
"width": {
1647-
"description": "New width in pixels.",
1648-
"type": "number"
1649-
},
1650-
"height": {
1651-
"description": "New height in pixels.",
1652-
"type": "number"
1653-
}
1654-
},
1655-
"additionalProperties": false
1656-
}
1657-
},
1658-
"required": ["method", "params"],
1659-
"additionalProperties": false
1660-
},
16611658
"McpUiTheme": {
16621659
"$schema": "https://json-schema.org/draft/2020-12/schema",
16631660
"description": "Color theme preference for the host environment.",

src/generated/schema.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ export type McpUiSandboxResourceReadyNotificationSchemaInferredType = z.infer<
3939
typeof generated.McpUiSandboxResourceReadyNotificationSchema
4040
>;
4141

42-
export type McpUiSizeChangedNotificationSchemaInferredType = z.infer<
43-
typeof generated.McpUiSizeChangedNotificationSchema
42+
export type McpUiHeightChangedNotificationSchemaInferredType = z.infer<
43+
typeof generated.McpUiHeightChangedNotificationSchema
4444
>;
4545

4646
export type McpUiToolInputNotificationSchemaInferredType = z.infer<
@@ -137,11 +137,11 @@ expectType<spec.McpUiSandboxResourceReadyNotification>(
137137
expectType<McpUiSandboxResourceReadyNotificationSchemaInferredType>(
138138
{} as spec.McpUiSandboxResourceReadyNotification,
139139
);
140-
expectType<spec.McpUiSizeChangedNotification>(
141-
{} as McpUiSizeChangedNotificationSchemaInferredType,
140+
expectType<spec.McpUiHeightChangedNotification>(
141+
{} as McpUiHeightChangedNotificationSchemaInferredType,
142142
);
143-
expectType<McpUiSizeChangedNotificationSchemaInferredType>(
144-
{} as spec.McpUiSizeChangedNotification,
143+
expectType<McpUiHeightChangedNotificationSchemaInferredType>(
144+
{} as spec.McpUiHeightChangedNotification,
145145
);
146146
expectType<spec.McpUiToolInputNotification>(
147147
{} as McpUiToolInputNotificationSchemaInferredType,

src/generated/schema.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,16 +109,15 @@ export const McpUiSandboxResourceReadyNotificationSchema = z.object({
109109
});
110110

111111
/**
112-
* @description Notification of UI size changes (bidirectional: Guest <-> Host).
113-
* @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI
112+
* @description Notification of UI height change (Guest -> Host).
113+
* Sent when the Guest UI's content height changes, allowing the host to resize the iframe.
114+
* @see {@link app.App.sendHeightChanged} for the method to send this from Guest UI
114115
*/
115-
export const McpUiSizeChangedNotificationSchema = z.object({
116-
method: z.literal("ui/notifications/size-changed"),
116+
export const McpUiHeightChangedNotificationSchema = z.object({
117+
method: z.literal("ui/notifications/height-changed"),
117118
params: z.object({
118-
/** @description New width in pixels. */
119-
width: z.number().optional().describe("New width in pixels."),
120119
/** @description New height in pixels. */
121-
height: z.number().optional().describe("New height in pixels."),
120+
height: z.number().describe("New height in pixels."),
122121
}),
123122
});
124123

0 commit comments

Comments
 (0)