Skip to content

Commit 2c6227b

Browse files
Add ui/close-resource request for UI to initiate termination
1 parent 2411c71 commit 2c6227b

7 files changed

Lines changed: 131 additions & 1 deletion

File tree

src/app-bridge.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ import {
6868
McpUiResourceTeardownRequest,
6969
McpUiResourceTeardownResult,
7070
McpUiResourceTeardownResultSchema,
71+
McpUiCloseResourceNotification,
72+
McpUiCloseResourceNotificationSchema,
7173
McpUiSandboxProxyReadyNotification,
7274
McpUiSandboxProxyReadyNotificationSchema,
7375
McpUiSizeChangedNotificationSchema,
@@ -549,6 +551,39 @@ export class AppBridge extends Protocol<
549551
);
550552
}
551553

554+
/**
555+
* Register a handler for app-initiated close notifications from the Guest UI.
556+
*
557+
* The Guest UI sends `ui/notifications/close-resource` when it wants to close itself.
558+
* This is the app-initiated counterpart to the host-initiated `ui/resource-teardown`.
559+
* Since the app initiates this, it has already performed any necessary cleanup
560+
* before sending the notification.
561+
*
562+
* This is a fire-and-forget notification - the host should immediately unmount
563+
* the app iframe upon receiving this notification.
564+
*
565+
* @param callback - Handler that receives close params
566+
* - params - Empty object (reserved for future use)
567+
*
568+
* @example
569+
* ```typescript
570+
* bridge.oncloseresource = (params) => {
571+
* console.log("App requested close");
572+
* // Unmount the iframe
573+
* iframe.remove();
574+
* };
575+
* ```
576+
*
577+
* @see {@link McpUiCloseResourceNotification} for the notification type
578+
*/
579+
set oncloseresource(
580+
callback: (params: McpUiCloseResourceNotification["params"]) => void,
581+
) {
582+
this.setNotificationHandler(McpUiCloseResourceNotificationSchema, (n) =>
583+
callback(n.params),
584+
);
585+
}
586+
552587
/**
553588
* Register a handler for display mode change requests from the Guest UI.
554589
*

src/app.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
McpUiResourceTeardownRequest,
3535
McpUiResourceTeardownRequestSchema,
3636
McpUiResourceTeardownResult,
37+
McpUiCloseResourceNotification,
3738
McpUiSizeChangedNotification,
3839
McpUiToolCancelledNotification,
3940
McpUiToolCancelledNotificationSchema,
@@ -848,6 +849,43 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
848849
/** @deprecated Use {@link openLink} instead */
849850
sendOpenLink: App["openLink"] = this.openLink;
850851

852+
/**
853+
* Signal the host to close this app.
854+
*
855+
* Apps call this method to initiate their own termination. The host will
856+
* close/unmount the app iframe upon receiving this notification. Since the app
857+
* is initiating the close, it should perform any necessary cleanup (save state,
858+
* close connections, etc.) before calling this method.
859+
*
860+
* This is a fire-and-forget notification - no response is expected since the
861+
* host will immediately unmount the app upon receiving this notification.
862+
*
863+
* Unlike host-initiated teardown (`ui/resource-teardown`), the app has already
864+
* done its cleanup when it calls this method, so no teardown request is
865+
* sent back to the app.
866+
*
867+
* @param params - Empty params object (reserved for future use)
868+
* @returns Promise that resolves when the notification is sent
869+
*
870+
* @example App-initiated close after user action
871+
* ```typescript
872+
* // User clicks "Done" button in the app
873+
* async function handleDoneClick() {
874+
* await saveState();
875+
* app.closeResource();
876+
* // App will be unmounted by host
877+
* }
878+
* ```
879+
*
880+
* @see {@link McpUiCloseResourceNotification} for notification structure
881+
*/
882+
closeResource(params: McpUiCloseResourceNotification["params"] = {}) {
883+
return this.notification(<McpUiCloseResourceNotification>{
884+
method: "ui/notifications/close-resource",
885+
params,
886+
});
887+
}
888+
851889
/**
852890
* Request a change to the display mode.
853891
*

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
@@ -407,6 +407,19 @@ export interface McpUiResourceTeardownResult {
407407
[key: string]: unknown;
408408
}
409409

410+
/**
411+
* @description Notification for app-initiated termination (Guest UI -> Host).
412+
* Apps send this to signal the host to close/unmount them.
413+
* Since the app initiates this, it has already performed any necessary cleanup.
414+
* This is fire-and-forget - no response is expected since the host will
415+
* immediately unmount the app upon receiving this notification.
416+
* @see {@link app.App.closeResource} for the app method that sends this
417+
*/
418+
export interface McpUiCloseResourceNotification {
419+
method: "ui/notifications/close-resource";
420+
params: {};
421+
}
422+
410423
/**
411424
* @description Capabilities supported by the host application.
412425
* @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
@@ -33,6 +33,7 @@ export {
3333
type McpUiHostContextChangedNotification,
3434
type McpUiResourceTeardownRequest,
3535
type McpUiResourceTeardownResult,
36+
type McpUiCloseResourceNotification,
3637
type McpUiHostCapabilities,
3738
type McpUiAppCapabilities,
3839
type McpUiInitializeRequest,
@@ -62,6 +63,7 @@ import type {
6263
McpUiInitializedNotification,
6364
McpUiSizeChangedNotification,
6465
McpUiSandboxProxyReadyNotification,
66+
McpUiCloseResourceNotification,
6567
McpUiInitializeResult,
6668
McpUiOpenLinkResult,
6769
McpUiMessageResult,
@@ -90,6 +92,7 @@ export {
9092
McpUiHostContextChangedNotificationSchema,
9193
McpUiResourceTeardownRequestSchema,
9294
McpUiResourceTeardownResultSchema,
95+
McpUiCloseResourceNotificationSchema,
9396
McpUiHostCapabilitiesSchema,
9497
McpUiAppCapabilitiesSchema,
9598
McpUiInitializeRequestSchema,
@@ -157,7 +160,7 @@ export type AppRequest =
157160
* - Sandbox resource ready
158161
*
159162
* App to host:
160-
* - Initialized, size-changed, sandbox-proxy-ready
163+
* - Initialized, size-changed, sandbox-proxy-ready, close-resource
161164
* - Logging messages
162165
*/
163166
export type AppNotification =
@@ -175,6 +178,7 @@ export type AppNotification =
175178
| McpUiInitializedNotification
176179
| McpUiSizeChangedNotification
177180
| McpUiSandboxProxyReadyNotification
181+
| McpUiCloseResourceNotification
178182
| LoggingMessageNotification;
179183

180184
/**

0 commit comments

Comments
 (0)