setup notification handlers in App & AppBridge

This commit is contained in:
Olivier Chafik 2025-11-24 14:59:58 +00:00
commit ac3863092a
No known key found for this signature in database
6 changed files with 89 additions and 45 deletions

View file

@ -8,7 +8,7 @@
* <code> * <code>
* npx esbuild src/ui-raw.ts --bundle --outfile=dist/ui-raw.js --minify --sourcemap --platform=browser * npx esbuild src/ui-raw.ts --bundle --outfile=dist/ui-raw.js --minify --sourcemap --platform=browser
* </code> * </code>
* *
* We implement a barebones JSON-RPC message sender/receiver (see `app` object below), * We implement a barebones JSON-RPC message sender/receiver (see `app` object below),
* but without timeouts or runtime type validation of any kind * but without timeouts or runtime type validation of any kind
* (for that, use the Apps SDK / see ui-vanilla.ts or ui-react.ts). * (for that, use the Apps SDK / see ui-vanilla.ts or ui-react.ts).

View file

@ -26,19 +26,9 @@ export function McpClientApp() {
appInfo: APP_INFO, appInfo: APP_INFO,
capabilities: {}, capabilities: {},
onAppCreated: (app) => { onAppCreated: (app) => {
app.setNotificationHandler( app.ontoolresult = async (params) => {
McpUiToolResultNotificationSchema, setToolResults((prev) => [...prev, params]);
async (notification) => { };
setToolResults((prev) => [...prev, notification.params]);
},
);
app.setNotificationHandler(
McpUiSizeChangeNotificationSchema,
async (notification) => {
document.body.style.width = `${notification.params.width}px`;
document.body.style.height = `${notification.params.height}px`;
},
);
}, },
}); });

View file

@ -36,28 +36,17 @@ window.addEventListener("load", async () => {
version: "1.0.0", version: "1.0.0",
}); });
app.setNotificationHandler( app.ontoolinput = (params) => {
McpUiToolInputNotificationSchema, appendText(`Tool call input received: ${JSON.stringify(params.arguments)}`);
async ({ params }) => { };
appendText( app.ontoolresult = ({ content, structuredContent, isError }) => {
`Tool call input received: ${JSON.stringify(params.arguments)}`, appendText(
); `Tool call result received: isError=${isError}, content=${content}, structuredContent=${JSON.stringify(structuredContent)}`,
}, );
); };
app.setNotificationHandler( app.onhostcontextchanged = (params) => {
McpUiToolResultNotificationSchema, appendText(`Host context changed: ${JSON.stringify(params)}`);
async ({ params: { content, structuredContent, isError } }) => { };
appendText(
`Tool call result received: isError=${isError}, content=${content}, structuredContent=${JSON.stringify(structuredContent)}`,
);
},
);
app.setNotificationHandler(
McpUiHostContextChangedNotificationSchema,
async (params) => {
appendText(`Host context changed: ${JSON.stringify(params)}`);
},
);
document.body.addEventListener("resize", () => { document.body.addEventListener("resize", () => {
app.sendSizeChange({ app.sendSizeChange({

View file

@ -13,6 +13,7 @@ import {
ListResourceTemplatesRequestSchema, ListResourceTemplatesRequestSchema,
ListResourceTemplatesResultSchema, ListResourceTemplatesResultSchema,
Notification, Notification,
PingRequest,
PingRequestSchema, PingRequestSchema,
PromptListChangedNotificationSchema, PromptListChangedNotificationSchema,
ResourceListChangedNotificationSchema, ResourceListChangedNotificationSchema,
@ -34,12 +35,16 @@ import {
LATEST_PROTOCOL_VERSION, LATEST_PROTOCOL_VERSION,
McpUiAppCapabilities, McpUiAppCapabilities,
McpUiHostCapabilities, McpUiHostCapabilities,
McpUiInitializedNotification,
McpUiInitializedNotificationSchema, McpUiInitializedNotificationSchema,
McpUiInitializeRequest, McpUiInitializeRequest,
McpUiInitializeRequestSchema, McpUiInitializeRequestSchema,
McpUiInitializeResult, McpUiInitializeResult,
McpUiResourceTeardownRequest, McpUiResourceTeardownRequest,
McpUiResourceTeardownResultSchema, McpUiResourceTeardownResultSchema,
McpUiSandboxProxyReadyNotification,
McpUiSandboxProxyReadyNotificationSchema,
McpUiSizeChangeNotificationSchema,
} from "./types"; } from "./types";
export * from "./types"; export * from "./types";
export { PostMessageTransport } from "./message-transport"; export { PostMessageTransport } from "./message-transport";
@ -48,9 +53,11 @@ type HostOptions = ProtocolOptions;
export const SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION]; export const SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION];
export class AppBridge extends Protocol<Request, Notification, Result> { type RequestExtra = Parameters<
oninitialized?: () => void; Parameters<AppBridge["setRequestHandler"]>[1]
>[1];
export class AppBridge extends Protocol<Request, Notification, Result> {
private _appCapabilities?: McpUiAppCapabilities; private _appCapabilities?: McpUiAppCapabilities;
constructor( constructor(
@ -64,16 +71,37 @@ export class AppBridge extends Protocol<Request, Notification, Result> {
this.setRequestHandler(McpUiInitializeRequestSchema, (request) => this.setRequestHandler(McpUiInitializeRequestSchema, (request) =>
this._oninitialize(request), this._oninitialize(request),
); );
this.setNotificationHandler(McpUiInitializedNotificationSchema, () =>
this.oninitialized?.(),
);
this.setRequestHandler(PingRequestSchema, (request) => { this.setRequestHandler(PingRequestSchema, (request, extra) => {
console.log("Received ping:", request.params); this.onping?.(request.params, extra);
return {}; return {};
}); });
} }
onping?: (params: PingRequest["params"], extra: RequestExtra) => void;
set onsizechange(
callback: (params: McpUiSizeChangeNotification["params"]) => void,
) {
this.setNotificationHandler(McpUiSizeChangeNotificationSchema, (n) =>
callback(n.params),
);
}
set onsandboxready(
callback: (params: McpUiSandboxProxyReadyNotification["params"]) => void,
) {
this.setNotificationHandler(McpUiSandboxProxyReadyNotificationSchema, (n) =>
callback(n.params),
);
}
set oninitialized(
callback: (params: McpUiInitializedNotification["params"]) => void,
) {
this.setNotificationHandler(McpUiInitializedNotificationSchema, (n) =>
callback(n.params),
);
}
assertCapabilityForMethod(method: Request["method"]): void { assertCapabilityForMethod(method: Request["method"]): void {
// TODO // TODO
} }

View file

@ -19,6 +19,8 @@ import {
LATEST_PROTOCOL_VERSION, LATEST_PROTOCOL_VERSION,
McpUiAppCapabilities, McpUiAppCapabilities,
McpUiHostCapabilities, McpUiHostCapabilities,
McpUiHostContextChangedNotification,
McpUiHostContextChangedNotificationSchema,
McpUiInitializedNotification, McpUiInitializedNotification,
McpUiInitializeRequest, McpUiInitializeRequest,
McpUiInitializeResultSchema, McpUiInitializeResultSchema,
@ -27,6 +29,12 @@ import {
McpUiOpenLinkRequest, McpUiOpenLinkRequest,
McpUiOpenLinkResultSchema, McpUiOpenLinkResultSchema,
McpUiSizeChangeNotification, McpUiSizeChangeNotification,
McpUiToolInputNotification,
McpUiToolInputNotificationSchema,
McpUiToolInputPartialNotification,
McpUiToolInputPartialNotificationSchema,
McpUiToolResultNotification,
McpUiToolResultNotificationSchema,
} from "./types"; } from "./types";
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js"; import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
@ -54,6 +62,36 @@ export class App extends Protocol<Request, Notification, Result> {
}); });
} }
set ontoolinput(
callback: (params: McpUiToolInputNotification["params"]) => void,
) {
this.setNotificationHandler(McpUiToolInputNotificationSchema, (n) =>
callback(n.params),
);
}
set ontoolinputpartial(
callback: (params: McpUiToolInputPartialNotification["params"]) => void,
) {
this.setNotificationHandler(McpUiToolInputPartialNotificationSchema, (n) =>
callback(n.params),
);
}
set ontoolresult(
callback: (params: McpUiToolResultNotification["params"]) => void,
) {
this.setNotificationHandler(McpUiToolResultNotificationSchema, (n) =>
callback(n.params),
);
}
set onhostcontextchanged(
callback: (params: McpUiHostContextChangedNotification["params"]) => void,
) {
this.setNotificationHandler(
McpUiHostContextChangedNotificationSchema,
(n) => callback(n.params),
);
}
assertCapabilityForMethod(method: Request["method"]): void { assertCapabilityForMethod(method: Request["method"]): void {
// TODO // TODO
} }

View file

@ -9,8 +9,7 @@ export interface UseAppOptions {
capabilities: McpUiAppCapabilities; capabilities: McpUiAppCapabilities;
/** /**
* Called after client is created but before connection. * Called after client is created but before connection.
* Use this to register request/notification handlers via * Use this to register handlers via app.ontoolinput, app.toolresult, etc.
* client.setRequestHandler() and client.setNotificationHandler().
*/ */
onAppCreated?: (app: App) => void; onAppCreated?: (app: App) => void;
} }