Skip to content

Commit 95bd5ec

Browse files
Add ui/close-resource request for UI to initiate termination
1 parent db1b485 commit 95bd5ec

7 files changed

Lines changed: 132 additions & 1 deletion

File tree

src/app-bridge.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ import {
7070
McpUiOpenLinkResult,
7171
McpUiResourceTeardownRequest,
7272
McpUiResourceTeardownResultSchema,
73+
McpUiCloseResourceRequest,
74+
McpUiCloseResourceRequestSchema,
7375
McpUiSandboxProxyReadyNotification,
7476
McpUiSandboxProxyReadyNotificationSchema,
7577
McpUiSizeChangedNotificationSchema,
@@ -586,6 +588,40 @@ export class AppBridge extends Protocol<
586588
);
587589
}
588590

591+
/**
592+
* Register a handler for app-initiated close notifications from the Guest UI.
593+
*
594+
* The Guest UI sends `ui/close-resource` when it wants to close itself.
595+
* This is the app-initiated counterpart to the host-initiated `ui/resource-teardown`.
596+
* Since the app initiates this, it has already performed any necessary cleanup
597+
* before sending the message.
598+
*
599+
* This is a fire-and-forget event - the host should immediately unmount
600+
* the app iframe upon receiving this request. No response are expected since the
601+
* host will immediately unmount the app upon receiving this request.
602+
*
603+
* @param callback - Handler that receives close params
604+
* - params - Empty object (reserved for future use)
605+
*
606+
* @example
607+
* ```typescript
608+
* bridge.oncloseresource = (params) => {
609+
* console.log("App requested close");
610+
* // Unmount the iframe
611+
* iframe.remove();
612+
* };
613+
* ```
614+
*
615+
* @see {@link McpUiCloseResourceRequest} for the notification type
616+
*/
617+
set oncloseresource(
618+
callback: (params: McpUiCloseResourceRequest["params"]) => void,
619+
) {
620+
this.setNotificationHandler(McpUiCloseResourceRequestSchema, (request) =>
621+
callback(request.params),
622+
);
623+
}
624+
589625
/**
590626
* Register a handler for display mode change requests from the Guest UI.
591627
*

src/app.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
McpUiResourceTeardownRequest,
3737
McpUiResourceTeardownRequestSchema,
3838
McpUiResourceTeardownResult,
39+
McpUiCloseResourceRequest,
3940
McpUiSizeChangedNotification,
4041
McpUiToolCancelledNotification,
4142
McpUiToolCancelledNotificationSchema,
@@ -906,6 +907,43 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
906907
/** @deprecated Use {@link openLink} instead */
907908
sendOpenLink: App["openLink"] = this.openLink;
908909

910+
/**
911+
* Signal the host to close this app.
912+
*
913+
* Apps call this method to initiate their own termination. The host will
914+
* close/unmount the app iframe upon receiving this notification. Since the app
915+
* is initiating the close, it should perform any necessary cleanup (save state,
916+
* close connections, etc.) before calling this method.
917+
*
918+
* This is a fire-and-forget request - no response is expected since the
919+
* host will immediately unmount the app upon receiving this payload.
920+
*
921+
* Unlike host-initiated teardown (`ui/resource-teardown`), the app has already
922+
* done its cleanup when it calls this method, so no teardown request is
923+
* sent back to the app.
924+
*
925+
* @param params - Empty params object (reserved for future use)
926+
* @returns Promise that resolves when the message is sent
927+
*
928+
* @example App-initiated close after user action
929+
* ```typescript
930+
* // User clicks "Done" button in the app
931+
* async function handleDoneClick() {
932+
* await saveState();
933+
* await app.closeResource();
934+
* // App will be unmounted by host
935+
* }
936+
* ```
937+
*
938+
* @see {@link McpUiCloseResourceRequest} for notification structure
939+
*/
940+
closeResource(params: McpUiCloseResourceRequest["params"] = {}) {
941+
return this.notification(<McpUiCloseResourceRequest>{
942+
method: "ui/close-resource",
943+
params,
944+
});
945+
}
946+
909947
/**
910948
* Request a change to the display mode.
911949
*

src/generated/schema.json

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/generated/schema.test.ts

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/generated/schema.ts

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/spec.types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,19 @@ export interface McpUiSupportedContentBlockModalities {
441441
structuredContent?: {};
442442
}
443443

444+
/**
445+
* @description Request for app-initiated termination (Guest UI -> Host).
446+
* Apps send this to signal the host to close/unmount them.
447+
* Since the app initiates this, it has already performed any necessary cleanup.
448+
* This is fire-and-forget - no response is expected since the host will
449+
* immediately unmount the app upon receiving this notification.
450+
* @see {@link app.App.closeResource} for the app method that sends this
451+
*/
452+
export interface McpUiCloseResourceRequest {
453+
method: "ui/close-resource";
454+
params: {};
455+
}
456+
444457
/**
445458
* @description Capabilities supported by the host application.
446459
* @see {@link McpUiInitializeResult} for the initialization result that includes these capabilities

src/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export {
4949
type McpUiHostContextChangedNotification,
5050
type McpUiResourceTeardownRequest,
5151
type McpUiResourceTeardownResult,
52+
type McpUiCloseResourceRequest,
5253
type McpUiHostCapabilities,
5354
type McpUiAppCapabilities,
5455
type McpUiInitializeRequest,
@@ -80,6 +81,7 @@ import type {
8081
McpUiInitializedNotification,
8182
McpUiSizeChangedNotification,
8283
McpUiSandboxProxyReadyNotification,
84+
McpUiCloseResourceRequest,
8385
McpUiInitializeResult,
8486
McpUiOpenLinkResult,
8587
McpUiMessageResult,
@@ -110,6 +112,7 @@ export {
110112
McpUiHostContextChangedNotificationSchema,
111113
McpUiResourceTeardownRequestSchema,
112114
McpUiResourceTeardownResultSchema,
115+
McpUiCloseResourceRequestSchema,
113116
McpUiHostCapabilitiesSchema,
114117
McpUiAppCapabilitiesSchema,
115118
McpUiInitializeRequestSchema,
@@ -180,7 +183,7 @@ export type AppRequest =
180183
* - Sandbox resource ready
181184
*
182185
* App to host:
183-
* - Initialized, size-changed, sandbox-proxy-ready
186+
* - Initialized, size-changed, sandbox-proxy-ready, close-resource
184187
* - Logging messages
185188
*/
186189
export type AppNotification =
@@ -198,6 +201,7 @@ export type AppNotification =
198201
| McpUiInitializedNotification
199202
| McpUiSizeChangedNotification
200203
| McpUiSandboxProxyReadyNotification
204+
| McpUiCloseResourceRequest
201205
| LoggingMessageNotification;
202206

203207
/**

0 commit comments

Comments
 (0)