import { type RequestOptions, ProtocolOptions } from "@modelcontextprotocol/sdk/shared/protocol.js"; import { CallToolRequest, CallToolResult, CreateMessageRequest, CreateMessageResult, CreateMessageResultWithTools, Implementation, ListResourcesRequest, ListResourcesResult, ListToolsRequest, ListToolsResult, LoggingMessageNotification, ReadResourceRequest, ReadResourceResult, ToolAnnotations, ToolListChangedNotification } from "@modelcontextprotocol/sdk/types.js"; import { AppNotification, AppRequest, AppResult } from "./types"; import { ProtocolWithEvents } from "./events"; export { ProtocolWithEvents }; import { McpUiAppCapabilities, McpUiUpdateModelContextRequest, McpUiHostCapabilities, McpUiHostContext, McpUiHostContextChangedNotification, McpUiMessageRequest, McpUiOpenLinkRequest, McpUiDownloadFileRequest, McpUiResourceTeardownRequest, McpUiResourceTeardownResult, McpUiRequestTeardownNotification, McpUiSizeChangedNotification, McpUiToolCancelledNotification, McpUiToolInputNotification, McpUiToolInputPartialNotification, McpUiToolResultNotification, McpUiRequestDisplayModeRequest } from "./types"; import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js"; import { StandardSchemaV1 } from "./standard-schema"; import { z } from "zod/v4"; export type { StandardSchemaV1, StandardSchemaWithJSON, } from "./standard-schema"; export { PostMessageTransport } from "./message-transport"; export * from "./types"; export { applyHostStyleVariables, applyHostFonts, getDocumentTheme, applyDocumentTheme, } from "./styles"; /** * Metadata key for associating a UI resource URI with a tool. * * MCP servers include this key in tool definition metadata (via `tools/list`) * to indicate which UI resource should be displayed when the tool is called. * When hosts see a tool with this metadata, they fetch and render the * corresponding {@link App `App`}. * * **Note**: This constant is provided for reference and backwards compatibility. * Server developers should use {@link server-helpers!registerAppTool `registerAppTool`} * with the `_meta.ui.resourceUri` format instead. Host developers must check both * formats for compatibility. * * @example Modern format (server-side, not in Apps) * ```ts source="./app.examples.ts#RESOURCE_URI_META_KEY_modernFormat" * // Preferred: Use registerAppTool with nested ui.resourceUri * registerAppTool( * server, * "weather", * { * description: "Get weather forecast", * _meta: { * ui: { resourceUri: "ui://weather/forecast" }, * }, * }, * handler, * ); * ``` * * @example Legacy format (deprecated, for backwards compatibility) * ```ts source="./app.examples.ts#RESOURCE_URI_META_KEY_legacyFormat" * // Deprecated: Direct use of RESOURCE_URI_META_KEY * server.registerTool( * "weather", * { * description: "Get weather forecast", * _meta: { * [RESOURCE_URI_META_KEY]: "ui://weather/forecast", * }, * }, * handler, * ); * ``` * * @example How hosts check for this metadata (must support both formats) * ```ts source="./app.examples.ts#RESOURCE_URI_META_KEY_hostSide" * // Hosts should check both modern and legacy formats * const meta = tool._meta; * const uiMeta = meta?.ui as McpUiToolMeta | undefined; * const legacyUri = meta?.[RESOURCE_URI_META_KEY] as string | undefined; * const uiUri = uiMeta?.resourceUri ?? legacyUri; * if (typeof uiUri === "string" && uiUri.startsWith("ui://")) { * // Fetch the resource and display the UI * } * ``` */ export declare const RESOURCE_URI_META_KEY = "ui/resourceUri"; /** * MIME type for MCP UI resources. * * Identifies HTML content as an MCP App UI resource. * * Used by {@link server-helpers!registerAppResource `registerAppResource`} as the default MIME type for app resources. */ export declare const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app"; /** * Options for configuring {@link App `App`} behavior. * * Extends `ProtocolOptions` from the MCP SDK with `App`-specific configuration. * * @see `ProtocolOptions` from @modelcontextprotocol/sdk for inherited options */ export type AppOptions = ProtocolOptions & { /** * Automatically report size changes to the host using `ResizeObserver`. * * When enabled, the {@link App `App`} monitors `document.body` and `document.documentElement` * for size changes and automatically sends `ui/notifications/size-changed` * notifications to the host. * * @default true */ autoResize?: boolean; /** * Throw on detected misuse instead of logging a console warning. * * Currently this affects calling host-bound methods (e.g. * {@link App.callServerTool `callServerTool`}, {@link App.sendMessage `sendMessage`}) * before {@link App.connect `connect`} has completed the `ui/initialize` * handshake. With `strict: false` (default) a `console.warn` is emitted; * with `strict: true` an `Error` is thrown. * * @remarks Throwing will become the default in a future release. * @default false */ strict?: boolean; /** * Allow code paths that require CSP `unsafe-eval` (e.g. `new Function()`). * * Views typically run under a strict CSP without `unsafe-eval`. Zod's JIT * object parser uses `new Function()` and throws on the first message parse * under such a policy. By default (`allowUnsafeEval: false`) the * {@link App `App`} constructor sets `z.config({ jitless: true })` so the * SDK works out of the box under the spec's default CSP. Set * `allowUnsafeEval: true` to skip that and keep the faster JIT path when * the host's CSP permits `unsafe-eval`. * * @default false */ allowUnsafeEval?: boolean; }; type RequestHandlerExtra = Parameters[1]>[1]; /** * Result of an app-registered tool callback. When `Out` is provided, * `structuredContent` is required and typed (unless `isError: true`). */ export type AppToolResult = Out extends StandardSchemaV1 ? (CallToolResult & { structuredContent: StandardSchemaV1.InferOutput; isError?: false; }) | (CallToolResult & { isError: true; }) : CallToolResult; /** * Callback for an app-registered tool. When `In` is provided, `args` is the * validated/parsed input; when `In` is `undefined`, the callback receives only * `extra`. When `Out` is provided, the return's `structuredContent` is typed. * * Mirrors `ToolCallback` from `@modelcontextprotocol/sdk/server/mcp.js` but is * parameterized over {@link StandardSchemaV1} instead of zod, so any * Standard-Schema-compatible library (Zod, ArkType, Valibot, …) can be used. */ export type AppToolCallback = In extends StandardSchemaV1 ? (args: StandardSchemaV1.InferOutput, extra: RequestHandlerExtra) => AppToolResult | Promise> : (extra: RequestHandlerExtra) => AppToolResult | Promise>; /** * Handle returned by {@link App.registerTool}. Mirrors `RegisteredTool` from * `@modelcontextprotocol/sdk/server/mcp.js` but stores * {@link StandardSchemaV1} schemas. */ export type RegisteredAppTool = { title?: string; description?: string; inputSchema?: StandardSchemaV1; outputSchema?: StandardSchemaV1; annotations?: ToolAnnotations; _meta?: Record; enabled: boolean; enable(): void; disable(): void; remove(): void; update(updates: Partial>): void; /** @internal */ handler: (args: unknown, extra: RequestHandlerExtra) => Promise; }; /** * Maps DOM-style event names to their notification `params` types. * * Used by {@link App `App`} (which extends {@link ProtocolWithEvents `ProtocolWithEvents`}) * to provide type-safe `addEventListener` / `removeEventListener` and * singular `on*` handler support. */ export type AppEventMap = { toolinput: McpUiToolInputNotification["params"]; toolinputpartial: McpUiToolInputPartialNotification["params"]; toolresult: McpUiToolResultNotification["params"]; toolcancelled: McpUiToolCancelledNotification["params"]; hostcontextchanged: McpUiHostContextChangedNotification["params"]; }; /** * Main class for MCP Apps to communicate with their host. * * The `App` class provides a framework-agnostic way to build interactive MCP Apps * that run inside host applications. It extends the MCP SDK's `Protocol` class and * handles the connection lifecycle, initialization handshake, and bidirectional * communication with the host. * * ## Architecture * * Views (Apps) act as MCP clients connecting to the host via {@link PostMessageTransport `PostMessageTransport`}. * The host proxies requests to the actual MCP server and forwards * responses back to the App. * * ## Lifecycle * * 1. **Create**: Instantiate App with info and capabilities * 2. **Connect**: Call `connect()` to establish transport and perform handshake * 3. **Interactive**: Send requests, receive notifications, call tools * 4. **Teardown**: Host sends teardown request before unmounting * * ## Inherited Methods * * As a subclass of {@link ProtocolWithEvents `ProtocolWithEvents`}, `App` inherits: * - `setRequestHandler()` - Register handlers for requests from host * - `setNotificationHandler()` - Register handlers for notifications from host * - `addEventListener()` - Append a listener for a notification event (multi-listener) * - `removeEventListener()` - Remove a previously added listener * * @see {@link ProtocolWithEvents `ProtocolWithEvents`} for the DOM-model event system * * ## Notification Setters (DOM-model `on*` handlers) * * For common notifications, the `App` class provides getter/setter properties * that follow DOM-model replace semantics (like `el.onclick`): * - `ontoolinput` - Complete tool arguments from host * - `ontoolinputpartial` - Streaming partial tool arguments * - `ontoolresult` - Tool execution results * - `ontoolcancelled` - Tool execution was cancelled by user or host * - `onhostcontextchanged` - Host context changes (theme, locale, etc.) * * Assigning replaces the previous handler; assigning `undefined` clears it. * Use `addEventListener` to attach multiple listeners without replacing. * * @example Basic usage with PostMessageTransport * ```ts source="./app.examples.ts#App_basicUsage" * const app = new App( * { name: "WeatherApp", version: "1.0.0" }, * {}, // capabilities * ); * * // Register handlers before connecting to ensure no notifications are missed * app.ontoolinput = (params) => { * console.log("Tool arguments:", params.arguments); * }; * * await app.connect(); * ``` */ export declare class App extends ProtocolWithEvents { private _appInfo; private _capabilities; private options; private _hostCapabilities?; private _hostInfo?; private _hostContext?; private _registeredTools; private _initializedSent; /** * Warn if a host-bound method is called before {@link connect `connect`} has * completed the `ui/initialize` → `ui/notifications/initialized` handshake. * * Calling these methods early can race the handshake on strict hosts and * leave the iframe permanently hidden. See * {@link https://github.com/anthropics/claude-ai-mcp/issues/61 claude-ai-mcp#61} / * {@link https://github.com/anthropics/claude-ai-mcp/issues/149 #149}. * * @remarks This will become a thrown `Error` in a future minor release. */ private _assertInitialized; protected readonly eventSchemas: { toolinput: z.ZodObject<{ method: z.ZodLiteral<"ui/notifications/tool-input">; params: z.ZodObject<{ arguments: z.ZodOptional>; }, z.core.$strip>; }, z.core.$strip>; toolinputpartial: z.ZodObject<{ method: z.ZodLiteral<"ui/notifications/tool-input-partial">; params: z.ZodObject<{ arguments: z.ZodOptional>; }, z.core.$strip>; }, z.core.$strip>; toolresult: z.ZodObject<{ method: z.ZodLiteral<"ui/notifications/tool-result">; params: z.ZodObject<{ _meta: z.ZodOptional>; "io.modelcontextprotocol/related-task": z.ZodOptional>; }, z.core.$loose>>; content: z.ZodDefault; text: z.ZodString; annotations: z.ZodOptional>>; priority: z.ZodOptional; lastModified: z.ZodOptional; }, z.core.$strip>>; _meta: z.ZodOptional>; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"image">; data: z.ZodString; mimeType: z.ZodString; annotations: z.ZodOptional>>; priority: z.ZodOptional; lastModified: z.ZodOptional; }, z.core.$strip>>; _meta: z.ZodOptional>; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"audio">; data: z.ZodString; mimeType: z.ZodString; annotations: z.ZodOptional>>; priority: z.ZodOptional; lastModified: z.ZodOptional; }, z.core.$strip>>; _meta: z.ZodOptional>; }, z.core.$strip>, z.ZodObject<{ uri: z.ZodString; description: z.ZodOptional; mimeType: z.ZodOptional; size: z.ZodOptional; annotations: z.ZodOptional>>; priority: z.ZodOptional; lastModified: z.ZodOptional; }, z.core.$strip>>; _meta: z.ZodOptional>; icons: z.ZodOptional; sizes: z.ZodOptional>; theme: z.ZodOptional>; }, z.core.$strip>>>; name: z.ZodString; title: z.ZodOptional; type: z.ZodLiteral<"resource_link">; }, z.core.$strip>, z.ZodObject<{ type: z.ZodLiteral<"resource">; resource: z.ZodUnion; _meta: z.ZodOptional>; text: z.ZodString; }, z.core.$strip>, z.ZodObject<{ uri: z.ZodString; mimeType: z.ZodOptional; _meta: z.ZodOptional>; blob: z.ZodString; }, z.core.$strip>]>; annotations: z.ZodOptional>>; priority: z.ZodOptional; lastModified: z.ZodOptional; }, z.core.$strip>>; _meta: z.ZodOptional>; }, z.core.$strip>]>>>; structuredContent: z.ZodOptional>; isError: z.ZodOptional; }, z.core.$loose>; }, z.core.$strip>; toolcancelled: z.ZodObject<{ method: z.ZodLiteral<"ui/notifications/tool-cancelled">; params: z.ZodObject<{ reason: z.ZodOptional; }, z.core.$strip>; }, z.core.$strip>; hostcontextchanged: z.ZodObject<{ method: z.ZodLiteral<"ui/notifications/host-context-changed">; params: z.ZodObject<{ toolInfo: z.ZodOptional>; tool: z.ZodObject<{ description: z.ZodOptional; inputSchema: z.ZodObject<{ type: z.ZodLiteral<"object">; properties: z.ZodOptional>>; required: z.ZodOptional>; }, z.core.$catchall>; outputSchema: z.ZodOptional; properties: z.ZodOptional>>; required: z.ZodOptional>; }, z.core.$catchall>>; annotations: z.ZodOptional; readOnlyHint: z.ZodOptional; destructiveHint: z.ZodOptional; idempotentHint: z.ZodOptional; openWorldHint: z.ZodOptional; }, z.core.$strip>>; execution: z.ZodOptional>; }, z.core.$strip>>; _meta: z.ZodOptional>; icons: z.ZodOptional; sizes: z.ZodOptional>; theme: z.ZodOptional>; }, z.core.$strip>>>; name: z.ZodString; title: z.ZodOptional; }, z.core.$strip>; }, z.core.$strip>>; theme: z.ZodOptional, z.ZodLiteral<"dark">]>>; styles: z.ZodOptional, z.ZodLiteral<"--color-background-secondary">, z.ZodLiteral<"--color-background-tertiary">, z.ZodLiteral<"--color-background-inverse">, z.ZodLiteral<"--color-background-ghost">, z.ZodLiteral<"--color-background-info">, z.ZodLiteral<"--color-background-danger">, z.ZodLiteral<"--color-background-success">, z.ZodLiteral<"--color-background-warning">, z.ZodLiteral<"--color-background-disabled">, z.ZodLiteral<"--color-text-primary">, z.ZodLiteral<"--color-text-secondary">, z.ZodLiteral<"--color-text-tertiary">, z.ZodLiteral<"--color-text-inverse">, z.ZodLiteral<"--color-text-ghost">, z.ZodLiteral<"--color-text-info">, z.ZodLiteral<"--color-text-danger">, z.ZodLiteral<"--color-text-success">, z.ZodLiteral<"--color-text-warning">, z.ZodLiteral<"--color-text-disabled">, z.ZodLiteral<"--color-border-primary">, z.ZodLiteral<"--color-border-secondary">, z.ZodLiteral<"--color-border-tertiary">, z.ZodLiteral<"--color-border-inverse">, z.ZodLiteral<"--color-border-ghost">, z.ZodLiteral<"--color-border-info">, z.ZodLiteral<"--color-border-danger">, z.ZodLiteral<"--color-border-success">, z.ZodLiteral<"--color-border-warning">, z.ZodLiteral<"--color-border-disabled">, z.ZodLiteral<"--color-ring-primary">, z.ZodLiteral<"--color-ring-secondary">, z.ZodLiteral<"--color-ring-inverse">, z.ZodLiteral<"--color-ring-info">, z.ZodLiteral<"--color-ring-danger">, z.ZodLiteral<"--color-ring-success">, z.ZodLiteral<"--color-ring-warning">, z.ZodLiteral<"--font-sans">, z.ZodLiteral<"--font-mono">, z.ZodLiteral<"--font-weight-normal">, z.ZodLiteral<"--font-weight-medium">, z.ZodLiteral<"--font-weight-semibold">, z.ZodLiteral<"--font-weight-bold">, z.ZodLiteral<"--font-text-xs-size">, z.ZodLiteral<"--font-text-sm-size">, z.ZodLiteral<"--font-text-md-size">, z.ZodLiteral<"--font-text-lg-size">, z.ZodLiteral<"--font-heading-xs-size">, z.ZodLiteral<"--font-heading-sm-size">, z.ZodLiteral<"--font-heading-md-size">, z.ZodLiteral<"--font-heading-lg-size">, z.ZodLiteral<"--font-heading-xl-size">, z.ZodLiteral<"--font-heading-2xl-size">, z.ZodLiteral<"--font-heading-3xl-size">, z.ZodLiteral<"--font-text-xs-line-height">, z.ZodLiteral<"--font-text-sm-line-height">, z.ZodLiteral<"--font-text-md-line-height">, z.ZodLiteral<"--font-text-lg-line-height">, z.ZodLiteral<"--font-heading-xs-line-height">, z.ZodLiteral<"--font-heading-sm-line-height">, z.ZodLiteral<"--font-heading-md-line-height">, z.ZodLiteral<"--font-heading-lg-line-height">, z.ZodLiteral<"--font-heading-xl-line-height">, z.ZodLiteral<"--font-heading-2xl-line-height">, z.ZodLiteral<"--font-heading-3xl-line-height">, z.ZodLiteral<"--border-radius-xs">, z.ZodLiteral<"--border-radius-sm">, z.ZodLiteral<"--border-radius-md">, z.ZodLiteral<"--border-radius-lg">, z.ZodLiteral<"--border-radius-xl">, z.ZodLiteral<"--border-radius-full">, z.ZodLiteral<"--border-width-regular">, z.ZodLiteral<"--shadow-hairline">, z.ZodLiteral<"--shadow-sm">, z.ZodLiteral<"--shadow-md">, z.ZodLiteral<"--shadow-lg">]>, z.ZodUnion>>; css: z.ZodOptional; }, z.core.$strip>>; }, z.core.$strip>>; displayMode: z.ZodOptional, z.ZodLiteral<"fullscreen">, z.ZodLiteral<"pip">]>>; availableDisplayModes: z.ZodOptional, z.ZodLiteral<"fullscreen">, z.ZodLiteral<"pip">]>>>; containerDimensions: z.ZodOptional, z.ZodObject<{ maxHeight: z.ZodOptional>; }, z.core.$strip>]>, z.ZodUnion, z.ZodObject<{ maxWidth: z.ZodOptional>; }, z.core.$strip>]>>>; locale: z.ZodOptional; timeZone: z.ZodOptional; userAgent: z.ZodOptional; platform: z.ZodOptional, z.ZodLiteral<"desktop">, z.ZodLiteral<"mobile">]>>; deviceCapabilities: z.ZodOptional; hover: z.ZodOptional; }, z.core.$strip>>; safeAreaInsets: z.ZodOptional>; }, z.core.$loose>; }, z.core.$strip>; }; /** * Events the host typically sends once, shortly after the handshake. * Registering a handler for one of these *after* {@link connect `connect`} * resolves risks missing the notification entirely. */ private static readonly ONE_SHOT_EVENTS; /** * One-shot events that have had at least one handler registered (via `on*` * setter or `addEventListener`) at any point. Once an event is in this set, * subsequent late registrations are not flagged — only the *first* handler * matters for the missed-notification race, and re-registration (e.g. React * `useEffect` cleanup → re-add on dep change) is a legitimate pattern. */ private readonly _everHadListener; /** * Warn (or throw under `strict`) when the *first* handler for a one-shot * event is registered after the `ui/initialize` → `ui/notifications/initialized` * handshake has completed. The host may have already fired the notification * by then. Subsequent registrations for the same event are not flagged. * * Mirrors {@link _assertInitialized `_assertInitialized`} (the outbound-side guard). */ private _assertHandlerTiming; protected setEventHandler(event: K, handler: ((params: AppEventMap[K]) => void) | undefined): void; addEventListener(event: K, handler: (params: AppEventMap[K]) => void): void; protected onEventDispatch(event: K, params: AppEventMap[K]): void; /** * Create a new MCP App instance. * * @param _appInfo - App identification (name and version) * @param _capabilities - Features and capabilities this app provides * @param options - Configuration options including `autoResize` behavior * * @example * ```ts source="./app.examples.ts#App_constructor_basic" * const app = new App( * { name: "MyApp", version: "1.0.0" }, * { tools: { listChanged: true } }, // capabilities * { autoResize: true }, // options * ); * ``` */ constructor(_appInfo: Implementation, _capabilities?: McpUiAppCapabilities, options?: AppOptions); private registerCapabilities; registerTool(name: string, config: { title?: string; description?: string; inputSchema?: InputArgs; outputSchema?: OutputArgs; annotations?: ToolAnnotations; _meta?: Record; }, cb: AppToolCallback): RegisteredAppTool; private _toolHandlersInitialized; private ensureToolHandlersInitialized; sendToolListChanged(params?: ToolListChangedNotification["params"]): Promise; /** * Get the host's capabilities discovered during initialization. * * Returns the capabilities that the host advertised during the * {@link connect `connect`} handshake. Returns `undefined` if called before * connection is established. * * @returns Host capabilities, or `undefined` if not yet connected * * @example Check host capabilities after connection * ```ts source="./app.examples.ts#App_getHostCapabilities_checkAfterConnection" * await app.connect(); * if (app.getHostCapabilities()?.serverTools) { * console.log("Host supports server tool calls"); * } * ``` * * @see {@link connect `connect`} for the initialization handshake * @see {@link McpUiHostCapabilities `McpUiHostCapabilities`} for the capabilities structure */ getHostCapabilities(): McpUiHostCapabilities | undefined; /** * Get the host's implementation info discovered during initialization. * * Returns the host's name and version as advertised during the * {@link connect `connect`} handshake. Returns `undefined` if called before * connection is established. * * @returns Host implementation info, or `undefined` if not yet connected * * @example Log host information after connection * ```ts source="./app.examples.ts#App_getHostVersion_logAfterConnection" * await app.connect(transport); * const { name, version } = app.getHostVersion() ?? {}; * console.log(`Connected to ${name} v${version}`); * ``` * * @see {@link connect `connect`} for the initialization handshake */ getHostVersion(): Implementation | undefined; /** * Get the host context discovered during initialization. * * Returns the host context that was provided in the initialization response, * including tool info, theme, locale, and other environment details. * This context is automatically updated when the host sends * `ui/notifications/host-context-changed` notifications. * * Returns `undefined` if called before connection is established. * * @returns Host context, or `undefined` if not yet connected * * @example Access host context after connection * ```ts source="./app.examples.ts#App_getHostContext_accessAfterConnection" * await app.connect(transport); * const context = app.getHostContext(); * if (context?.theme === "dark") { * document.body.classList.add("dark-theme"); * } * if (context?.toolInfo) { * console.log("Tool:", context.toolInfo.tool.name); * } * ``` * * @see {@link connect `connect`} for the initialization handshake * @see {@link onhostcontextchanged `onhostcontextchanged`} for context change notifications * @see {@link McpUiHostContext `McpUiHostContext`} for the context structure */ getHostContext(): McpUiHostContext | undefined; /** * Convenience handler for receiving complete tool input from the host. * * Set this property to register a handler that will be called when the host * sends a tool's complete arguments. This is sent after a tool call begins * and before the tool result is available. * * Assigning replaces the previous handler; assigning `undefined` clears it. * Use {@link addEventListener `addEventListener`} to attach multiple listeners * without replacing. * * Register handlers before calling {@link connect `connect`} to avoid missing notifications. * * @example * ```ts source="./app.examples.ts#App_ontoolinput_setter" * // Register before connecting to ensure no notifications are missed * app.ontoolinput = (params) => { * console.log("Tool:", params.arguments); * // Update your UI with the tool arguments * }; * await app.connect(); * ``` * * @deprecated Use {@link addEventListener `addEventListener("toolinput", handler)`} instead — it composes with other listeners and supports cleanup via {@link removeEventListener `removeEventListener`}. * @see {@link McpUiToolInputNotification `McpUiToolInputNotification`} for the notification structure */ get ontoolinput(): ((params: McpUiToolInputNotification["params"]) => void) | undefined; set ontoolinput(callback: ((params: McpUiToolInputNotification["params"]) => void) | undefined); /** * Convenience handler for receiving streaming partial tool input from the host. * * Set this property to register a handler that will be called as the host * streams partial tool arguments during tool call initialization. This enables * progressive rendering of tool arguments before they're complete. * * **Important:** Partial arguments are "healed" JSON — the host closes unclosed * brackets/braces to produce valid JSON. This means objects may be incomplete * (e.g., the last item in an array may be truncated). Use partial data only * for preview UI, not for critical operations. * * Assigning replaces the previous handler; assigning `undefined` clears it. * Use {@link addEventListener `addEventListener`} to attach multiple listeners * without replacing. * * Register handlers before calling {@link connect `connect`} to avoid missing notifications. * * @example Progressive rendering of tool arguments * ```ts source="./app.examples.ts#App_ontoolinputpartial_progressiveRendering" * const codePreview = document.querySelector("#code-preview")!; * const canvas = document.querySelector("#canvas")!; * * app.ontoolinputpartial = (params) => { * codePreview.textContent = (params.arguments?.code as string) ?? ""; * codePreview.style.display = "block"; * canvas.style.display = "none"; * }; * * app.ontoolinput = (params) => { * codePreview.style.display = "none"; * canvas.style.display = "block"; * render(params.arguments?.code as string); * }; * ``` * * @deprecated Use {@link addEventListener `addEventListener("toolinputpartial", handler)`} instead — it composes with other listeners and supports cleanup via {@link removeEventListener `removeEventListener`}. * @see {@link McpUiToolInputPartialNotification `McpUiToolInputPartialNotification`} for the notification structure * @see {@link ontoolinput `ontoolinput`} for the complete tool input handler */ get ontoolinputpartial(): ((params: McpUiToolInputPartialNotification["params"]) => void) | undefined; set ontoolinputpartial(callback: ((params: McpUiToolInputPartialNotification["params"]) => void) | undefined); /** * Convenience handler for receiving tool execution results from the host. * * Set this property to register a handler that will be called when the host * sends the result of a tool execution. This is sent after the tool completes * on the MCP server, allowing your app to display the results or update its state. * * Assigning replaces the previous handler; assigning `undefined` clears it. * Use {@link addEventListener `addEventListener`} to attach multiple listeners * without replacing. * * Register handlers before calling {@link connect `connect`} to avoid missing notifications. * * @example Display tool execution results * ```ts source="./app.examples.ts#App_ontoolresult_displayResults" * app.ontoolresult = (params) => { * if (params.isError) { * console.error("Tool execution failed:", params.content); * } else if (params.content) { * console.log("Tool output:", params.content); * } * }; * ``` * * @deprecated Use {@link addEventListener `addEventListener("toolresult", handler)`} instead — it composes with other listeners and supports cleanup via {@link removeEventListener `removeEventListener`}. * @see {@link McpUiToolResultNotification `McpUiToolResultNotification`} for the notification structure * @see {@link ontoolinput `ontoolinput`} for the initial tool input handler */ get ontoolresult(): ((params: McpUiToolResultNotification["params"]) => void) | undefined; set ontoolresult(callback: ((params: McpUiToolResultNotification["params"]) => void) | undefined); /** * Convenience handler for receiving tool cancellation notifications from the host. * * Set this property to register a handler that will be called when the host * notifies that tool execution was cancelled. This can occur for various reasons * including user action, sampling error, classifier intervention, or other * interruptions. Apps should update their state and display appropriate feedback. * * Assigning replaces the previous handler; assigning `undefined` clears it. * Use {@link addEventListener `addEventListener`} to attach multiple listeners * without replacing. * * Register handlers before calling {@link connect `connect`} to avoid missing notifications. * * @example Handle tool cancellation * ```ts source="./app.examples.ts#App_ontoolcancelled_handleCancellation" * app.ontoolcancelled = (params) => { * console.log("Tool cancelled:", params.reason); * // Update your UI to show cancellation state * }; * ``` * * @deprecated Use {@link addEventListener `addEventListener("toolcancelled", handler)`} instead — it composes with other listeners and supports cleanup via {@link removeEventListener `removeEventListener`}. * @see {@link McpUiToolCancelledNotification `McpUiToolCancelledNotification`} for the notification structure * @see {@link ontoolresult `ontoolresult`} for successful tool completion */ get ontoolcancelled(): ((params: McpUiToolCancelledNotification["params"]) => void) | undefined; set ontoolcancelled(callback: ((params: McpUiToolCancelledNotification["params"]) => void) | undefined); /** * Convenience handler for host context changes (theme, locale, etc.). * * Set this property to register a handler that will be called when the host's * context changes, such as theme switching (light/dark), locale changes, or * other environmental updates. Apps should respond by updating their UI * accordingly. * * Assigning replaces the previous handler; assigning `undefined` clears it. * Use {@link addEventListener `addEventListener`} to attach multiple listeners * without replacing. * * Notification params are automatically merged into the internal host context * via {@link onEventDispatch `onEventDispatch`} before any handler or listener * fires. This means {@link getHostContext `getHostContext`} will return the * updated values even before your callback runs. * * Register handlers before calling {@link connect `connect`} to avoid missing notifications. * * @example Respond to theme changes * ```ts source="./app.examples.ts#App_onhostcontextchanged_respondToTheme" * app.onhostcontextchanged = (ctx) => { * if (ctx.theme === "dark") { * document.body.classList.add("dark-theme"); * } else { * document.body.classList.remove("dark-theme"); * } * }; * ``` * * @deprecated Use {@link addEventListener `addEventListener("hostcontextchanged", handler)`} instead — it composes with other listeners and supports cleanup via {@link removeEventListener `removeEventListener`}. * @see {@link McpUiHostContextChangedNotification `McpUiHostContextChangedNotification`} for the notification structure * @see {@link McpUiHostContext `McpUiHostContext`} for the full context structure */ get onhostcontextchanged(): ((params: McpUiHostContextChangedNotification["params"]) => void) | undefined; set onhostcontextchanged(callback: ((params: McpUiHostContextChangedNotification["params"]) => void) | undefined); /** * Convenience handler for graceful shutdown requests from the host. * * Set this property to register a handler that will be called when the host * requests the app to prepare for teardown. This allows the app to perform * cleanup operations (save state, close connections, etc.) before being unmounted. * * The handler can be sync or async. The host will wait for the returned promise * to resolve before proceeding with teardown. * * Assigning replaces the previous handler; assigning `undefined` clears it. * * Register handlers before calling {@link connect `connect`} to avoid missing requests. * * @param callback - Function called when teardown is requested. * Must return `McpUiResourceTeardownResult` (can be an empty object `{}`) or a Promise resolving to it. * * @example Perform cleanup before teardown * ```ts source="./app.examples.ts#App_onteardown_performCleanup" * app.onteardown = async () => { * await saveState(); * closeConnections(); * console.log("App ready for teardown"); * return {}; * }; * ``` * * @see {@link McpUiResourceTeardownRequest `McpUiResourceTeardownRequest`} for the request structure */ private _onteardown?; get onteardown(): ((params: McpUiResourceTeardownRequest["params"], extra: RequestHandlerExtra) => McpUiResourceTeardownResult | Promise) | undefined; set onteardown(callback: ((params: McpUiResourceTeardownRequest["params"], extra: RequestHandlerExtra) => McpUiResourceTeardownResult | Promise) | undefined); /** * Convenience handler for tool call requests from the host. * * Set this property to register a handler that will be called when the host * requests this app to execute a tool. This enables apps to provide their own * tools that can be called by the host or LLM. * * The app must declare tool capabilities in the constructor to use this handler. * * Assigning replaces the previous handler; assigning `undefined` clears it. * * Register handlers before calling {@link connect `connect`} to avoid missing requests. * * @param callback - Async function that executes the tool and returns the result. * The callback will only be invoked if the app declared tool capabilities * in the constructor. * * @example Handle tool calls from the host * ```ts source="./app.examples.ts#App_oncalltool_handleFromHost" * app.oncalltool = async (params, extra) => { * if (params.name === "greet") { * const name = params.arguments?.name ?? "World"; * return { content: [{ type: "text", text: `Hello, ${name}!` }] }; * } * throw new Error(`Unknown tool: ${params.name}`); * }; * ``` */ private _oncalltool?; get oncalltool(): ((params: CallToolRequest["params"], extra: RequestHandlerExtra) => Promise) | undefined; set oncalltool(callback: ((params: CallToolRequest["params"], extra: RequestHandlerExtra) => Promise) | undefined); /** * Convenience handler for listing available tools. * * Set this property to register a handler that will be called when the host * requests a list of tools this app provides. This enables dynamic tool * discovery by the host or LLM. * * The app must declare tool capabilities in the constructor to use this handler. * * Assigning replaces the previous handler; assigning `undefined` clears it. * * Register handlers before calling {@link connect `connect`} to avoid missing requests. * * @param callback - Async function that returns a {@link ListToolsResult `ListToolsResult`}. * Registration is always allowed; capability validation occurs when handlers * are invoked. * * @example Return available tools * ```ts source="./app.examples.ts#App_onlisttools_returnTools" * app.onlisttools = async (params, extra) => { * return { * tools: [ * { * name: "greet", * description: "Greet the user", * inputSchema: { type: "object" as const }, * }, * { * name: "calculate", * description: "Perform a calculation", * inputSchema: { type: "object" as const }, * }, * { * name: "format", * description: "Format text", * inputSchema: { type: "object" as const }, * }, * ], * }; * }; * ``` * * @see {@link oncalltool `oncalltool`} for handling tool execution */ private _onlisttools?; get onlisttools(): ((params: ListToolsRequest["params"], extra: RequestHandlerExtra) => Promise) | undefined; set onlisttools(callback: ((params: ListToolsRequest["params"], extra: RequestHandlerExtra) => Promise) | undefined); /** * Verify that the host supports the capability required for the given request method. * @internal */ assertCapabilityForMethod(method: AppRequest["method"]): void; /** * Verify that the app declared the capability required for the given request method. * @internal */ assertRequestHandlerCapability(method: AppRequest["method"]): void; /** * Verify that the app supports the capability required for the given notification method. * @internal */ assertNotificationCapability(_method: AppNotification["method"]): void; /** * Verify that task creation is supported for the given request method. * @internal */ protected assertTaskCapability(_method: string): void; /** * Verify that task handler is supported for the given method. * @internal */ protected assertTaskHandlerCapability(_method: string): void; /** * Call a tool on the originating MCP server (proxied through the host). * * Apps can call tools to fetch fresh data or trigger server-side actions. * The host proxies the request to the actual MCP server and returns the result. * * @param params - Tool name and arguments * @param options - Request options (timeout, etc.) * @returns Tool execution result * * @throws {Error} If the tool does not exist on the server * @throws {Error} If the request times out or the connection is lost * @throws {Error} If the host rejects the request * * Note: Tool-level execution errors are returned in the result with `isError: true` * rather than throwing exceptions. Always check `result.isError` to distinguish * between transport failures (thrown) and tool execution failures (returned). * * @example Fetch updated weather data * ```ts source="./app.examples.ts#App_callServerTool_fetchWeather" * try { * const result = await app.callServerTool({ * name: "get_weather", * arguments: { location: "Tokyo" }, * }); * if (result.isError) { * console.error("Tool returned error:", result.content); * } else { * console.log(result.content); * } * } catch (error) { * console.error("Tool call failed:", error); * } * ``` */ callServerTool(params: CallToolRequest["params"], options?: RequestOptions): Promise; /** * Read a resource from the originating MCP server (proxied through the host). * * Apps can read resources to access files, data, or other content provided by * the MCP server. Resources are identified by URI (e.g., `file:///path/to/file` * or custom schemes like `videos://bunny-1mb`). The host proxies the request to * the actual MCP server and returns the resource content. * * @param params - Resource URI to read * @param options - Request options (timeout, etc.) * @returns Resource content with URI, name, description, mimeType, and contents array * * @throws {Error} If the resource does not exist on the server * @throws {Error} If the request times out or the connection is lost * @throws {Error} If the host rejects the request * * @example Read a video resource and play it * ```ts source="./app.examples.ts#App_readServerResource_playVideo" * try { * const result = await app.readServerResource({ * uri: "videos://bunny-1mb", * }); * const content = result.contents[0]; * if (content && "blob" in content) { * const binary = Uint8Array.from(atob(content.blob), (c) => * c.charCodeAt(0), * ); * const url = URL.createObjectURL( * new Blob([binary], { type: content.mimeType || "video/mp4" }), * ); * videoElement.src = url; * videoElement.play(); * } * } catch (error) { * console.error("Failed to read resource:", error); * } * ``` * * @see {@link listServerResources `listServerResources`} to discover available resources */ readServerResource(params: ReadResourceRequest["params"], options?: RequestOptions): Promise; /** * List available resources from the originating MCP server (proxied through the host). * * Apps can list resources to discover what content is available on the MCP server. * This enables dynamic resource discovery and building resource browsers or pickers. * The host proxies the request to the actual MCP server and returns the resource list. * * Results may be paginated using the `cursor` parameter for servers with many resources. * * @param params - Optional parameters (omit for all resources, or `{ cursor }` for pagination) * @param options - Request options (timeout, etc.) * @returns List of resources with their URIs, names, descriptions, mimeTypes, and optional pagination cursor * * @throws {Error} If the request times out or the connection is lost * @throws {Error} If the host rejects the request * * @example Discover available videos and build a picker UI * ```ts source="./app.examples.ts#App_listServerResources_buildPicker" * try { * const result = await app.listServerResources(); * const videoResources = result.resources.filter((r) => * r.mimeType?.startsWith("video/"), * ); * videoResources.forEach((resource) => { * const option = document.createElement("option"); * option.value = resource.uri; * option.textContent = resource.description || resource.name; * selectElement.appendChild(option); * }); * } catch (error) { * console.error("Failed to list resources:", error); * } * ``` * * @see {@link readServerResource `readServerResource`} to read a specific resource */ listServerResources(params?: ListResourcesRequest["params"], options?: RequestOptions): Promise; /** * Request an LLM completion from the host (standard MCP `sampling/createMessage`). * * Enables the app to use the host's model connection for completions. The host * has full discretion over which model to select and MAY modify or reject the * request (human-in-the-loop). Check {@link getHostCapabilities `getHostCapabilities`}`()?.sampling` * before calling — hosts without this capability will reject the request. * * This method reuses the stock MCP `CreateMessageRequest` shape. When `params.tools` * is provided, the result is parsed with the extended schema that permits * `stopReason: "toolUse"` and array content containing `tool_use` blocks. * * @param params - Standard MCP `CreateMessageRequest` params (messages, maxTokens, * systemPrompt, temperature, modelPreferences, tools, toolChoice, etc.) * @param options - Request options (timeout, abort signal) * @returns `CreateMessageResult` (single content block) or `CreateMessageResultWithTools` * (array content, may include `tool_use` blocks) depending on whether `tools` was set * * @throws {Error} If the host rejects the request or does not support sampling * @throws {Error} If the request times out or the connection is lost * * @example Simple completion * ```ts source="./app.examples.ts#App_createSamplingMessage_simple" * const result = await app.createSamplingMessage({ * messages: [ * { * role: "user", * content: { type: "text", text: "Summarize this in one line." }, * }, * ], * maxTokens: 100, * }); * console.log(result.content); * ``` * * @example Agentic loop with tools * ```ts source="./app.examples.ts#App_createSamplingMessage_withTools" * if (!app.getHostCapabilities()?.sampling?.tools) return; * * const result = await app.createSamplingMessage({ * messages, * maxTokens: 1024, * tools: [ * { * name: "get_weather", * description: "Get the current weather", * inputSchema: { * type: "object", * properties: { city: { type: "string" } }, * }, * }, * ], * }); * if (result.stopReason === "toolUse") { * // result.content may be an array containing tool_use blocks * } * ``` * * @see `CreateMessageRequest` from @modelcontextprotocol/sdk for the request type * @see `CreateMessageResult` / `CreateMessageResultWithTools` from @modelcontextprotocol/sdk for result types */ createSamplingMessage(params: CreateMessageRequest["params"] & { tools?: undefined; }, options?: RequestOptions): Promise; createSamplingMessage(params: CreateMessageRequest["params"], options?: RequestOptions): Promise; /** * Send a message to the host's chat interface. * * Enables the app to add messages to the conversation thread. Useful for * user-initiated messages or app-to-conversation communication. * * @param params - Message role and content * @param options - Request options (timeout, etc.) * @returns Result with optional `isError` flag indicating host rejection * * @throws {Error} If the request times out or the connection is lost * * @example Send a text message from user interaction * ```ts source="./app.examples.ts#App_sendMessage_textFromInteraction" * try { * const result = await app.sendMessage({ * role: "user", * content: [{ type: "text", text: "Show me details for item #42" }], * }); * if (result.isError) { * console.error("Host rejected the message"); * // Handle rejection appropriately for your app * } * } catch (error) { * console.error("Failed to send message:", error); * // Handle transport/protocol error * } * ``` * * @example Send follow-up message after offloading large data to model context * ```ts source="./app.examples.ts#App_sendMessage_withLargeContext" * const markdown = `--- * word-count: ${fullTranscript.split(/\s+/).length} * speaker-names: ${speakerNames.join(", ")} * --- * * ${fullTranscript}`; * * // Offload long transcript to model context * await app.updateModelContext({ content: [{ type: "text", text: markdown }] }); * * // Send brief trigger message * await app.sendMessage({ * role: "user", * content: [{ type: "text", text: "Summarize the key points" }], * }); * ``` * * @see {@link McpUiMessageRequest `McpUiMessageRequest`} for request structure */ sendMessage(params: McpUiMessageRequest["params"], options?: RequestOptions): Promise<{ [x: string]: unknown; isError?: boolean | undefined; }>; /** * Send log messages to the host for debugging and telemetry. * * Logs are not added to the conversation but may be recorded by the host * for debugging purposes. * * @param params - Log level and message * * @example Log app state for debugging * ```ts source="./app.examples.ts#App_sendLog_debugState" * app.sendLog({ * level: "info", * data: "Weather data refreshed", * logger: "WeatherApp", * }); * ``` * * @returns Promise that resolves when the log notification is sent */ sendLog(params: LoggingMessageNotification["params"]): Promise; /** * Update the host's model context with app state. * * Context updates are intended to be available to the model in future * turns, without triggering an immediate model response (unlike {@link sendMessage `sendMessage`}). * * The host will typically defer sending the context to the model until the * next user message — either from the actual user or via `sendMessage`. Only * the last update is sent; each call overwrites any previous context. * * @param params - Context content and/or structured content * @param options - Request options (timeout, etc.) * * @throws {Error} If the host rejects the context update (e.g., unsupported content type) * @throws {Error} If the request times out or the connection is lost * * @example Update model context with current app state * ```ts source="./app.examples.ts#App_updateModelContext_appState" * const markdown = `--- * item-count: ${itemList.length} * total-cost: ${totalCost} * currency: ${currency} * --- * * User is viewing their shopping cart with ${itemList.length} items selected: * * ${itemList.map((item) => `- ${item}`).join("\n")}`; * * await app.updateModelContext({ * content: [{ type: "text", text: markdown }], * }); * ``` * * @example Report runtime error to model * ```ts source="./app.examples.ts#App_updateModelContext_reportError" * try { * const _stream = await navigator.mediaDevices.getUserMedia({ audio: true }); * // ... use _stream for transcription * } catch (err) { * // Inform the model that the app is in a degraded state * await app.updateModelContext({ * content: [ * { * type: "text", * text: "Error: transcription unavailable", * }, * ], * }); * } * ``` * * @returns Promise that resolves when the context update is acknowledged */ updateModelContext(params: McpUiUpdateModelContextRequest["params"], options?: RequestOptions): Promise<{ _meta?: { [x: string]: unknown; progressToken?: string | number | undefined; "io.modelcontextprotocol/related-task"?: { taskId: string; } | undefined; } | undefined; }>; /** * Request the host to open an external URL in the default browser. * * The host may deny this request based on user preferences or security policy. * Apps should handle rejection gracefully by checking `result.isError`. * * @param params - URL to open * @param options - Request options (timeout, etc.) * @returns Result with `isError: true` if the host denied the request (e.g., blocked domain, user cancelled) * * @throws {Error} If the request times out or the connection is lost * * @example Open documentation link * ```ts source="./app.examples.ts#App_openLink_documentation" * const { isError } = await app.openLink({ url: "https://docs.example.com" }); * if (isError) { * // Host denied the request (e.g., blocked domain, user cancelled) * // Optionally show fallback: display URL for manual copy * console.warn("Link request denied"); * } * ``` * * @see {@link McpUiOpenLinkRequest `McpUiOpenLinkRequest`} for request structure * @see {@link McpUiOpenLinkResult `McpUiOpenLinkResult`} for result structure */ openLink(params: McpUiOpenLinkRequest["params"], options?: RequestOptions): Promise<{ [x: string]: unknown; isError?: boolean | undefined; }>; /** @deprecated Use {@link openLink `openLink`} instead */ sendOpenLink: App["openLink"]; /** * Request the host to download a file. * * Since MCP Apps run in sandboxed iframes where direct downloads are blocked, * this provides a host-mediated mechanism for file exports. The host will * typically show a confirmation dialog before initiating the download. * * Uses standard MCP resource types: `EmbeddedResource` for inline content * and `ResourceLink` for content the host can fetch directly. * * @param params - Resource contents to download * @param options - Request options (timeout, etc.) * @returns Result with `isError: true` if the host denied the request (e.g., user cancelled) * * @throws {Error} If the request times out or the connection is lost * * @example Download a JSON file (embedded text resource) * ```ts * const data = JSON.stringify({ items: selectedItems }, null, 2); * const { isError } = await app.downloadFile({ * contents: [{ * type: "resource", * resource: { * uri: "file:///export.json", * mimeType: "application/json", * text: data, * }, * }], * }); * if (isError) { * console.warn("Download denied or cancelled"); * } * ``` * * @example Download binary content (embedded blob resource) * ```ts * const { isError } = await app.downloadFile({ * contents: [{ * type: "resource", * resource: { * uri: "file:///image.png", * mimeType: "image/png", * blob: base64EncodedPng, * }, * }], * }); * ``` * * @example Download via resource link (host fetches) * ```ts * const { isError } = await app.downloadFile({ * contents: [{ * type: "resource_link", * uri: "https://api.example.com/reports/q4.pdf", * name: "Q4 Report", * mimeType: "application/pdf", * }], * }); * ``` * * @see {@link McpUiDownloadFileRequest `McpUiDownloadFileRequest`} for request structure * @see {@link McpUiDownloadFileResult `McpUiDownloadFileResult`} for result structure */ downloadFile(params: McpUiDownloadFileRequest["params"], options?: RequestOptions): Promise<{ [x: string]: unknown; isError?: boolean | undefined; }>; /** * Request the host to tear down this app. * * Apps call this method to request that the host tear them down. The host * decides whether to proceed - if approved, the host will send * `ui/resource-teardown` to allow the app to perform gracefull termination before being * unmounted. This piggybacks on the existing teardown mechanism, ensuring * the app only needs a single shutdown procedure (via {@link onteardown `onteardown`}) * regardless of whether the teardown was initiated by the app or the host. * * This is a fire-and-forget notification - no response is expected. * If the host approves, the app will receive a `ui/resource-teardown` * request via the {@link onteardown `onteardown`} handler to persist unsaved state. * * @param params - Empty params object (reserved for future use) * @returns Promise that resolves when the notification is sent * * @example App-initiated teardown after user action * ```typescript * // User clicks "Done" button in the app * async function handleDoneClick() { * // Request the host to tear down the app * await app.requestTeardown(); * // If host approves, onteardown handler will be called for termination * } * * // Set up teardown handler (called for both app-initiated and host-initiated teardown) * app.onteardown = async () => { * await saveState(); * closeConnections(); * return {}; * }; * ``` * * @see {@link McpUiRequestTeardownNotification `McpUiRequestTeardownNotification`} for notification structure * @see {@link onteardown `onteardown`} for the graceful termination handler */ requestTeardown(params?: McpUiRequestTeardownNotification["params"]): Promise; /** * Request a change to the display mode. * * Requests the host to change the UI container to the specified display mode * (e.g., "inline", "fullscreen", "pip"). The host will respond with the actual * display mode that was set, which may differ from the requested mode if * the requested mode is not available (check `availableDisplayModes` in host context). * * @param params - The display mode being requested * @param options - Request options (timeout, etc.) * @returns Result containing the actual display mode that was set * * @example Toggle display mode * ```ts source="./app.examples.ts#App_requestDisplayMode_toggle" * const container = document.getElementById("main")!; * const ctx = app.getHostContext(); * const newMode = ctx?.displayMode === "inline" ? "fullscreen" : "inline"; * if (ctx?.availableDisplayModes?.includes(newMode)) { * const result = await app.requestDisplayMode({ mode: newMode }); * container.classList.toggle("fullscreen", result.mode === "fullscreen"); * } * ``` * * @see {@link McpUiRequestDisplayModeRequest `McpUiRequestDisplayModeRequest`} for request structure * @see {@link McpUiHostContext `McpUiHostContext`} for checking availableDisplayModes */ requestDisplayMode(params: McpUiRequestDisplayModeRequest["params"], options?: RequestOptions): Promise<{ [x: string]: unknown; mode: "inline" | "fullscreen" | "pip"; }>; /** * Notify the host of UI size changes. * * Apps can manually report size changes to help the host adjust the container. * If `autoResize` is enabled (default), this is called automatically. * * @param params - New width and height in pixels * * @example Manually notify host of size change * ```ts source="./app.examples.ts#App_sendSizeChanged_manual" * app.sendSizeChanged({ * width: 400, * height: 600, * }); * ``` * * @returns Promise that resolves when the notification is sent * * @see {@link McpUiSizeChangedNotification `McpUiSizeChangedNotification`} for notification structure */ sendSizeChanged(params: McpUiSizeChangedNotification["params"]): Promise; /** * Set up automatic size change notifications using ResizeObserver. * * Observes both `document.documentElement` and `document.body` for size changes * and automatically sends `ui/notifications/size-changed` notifications to the host. * The notifications are debounced using requestAnimationFrame to avoid duplicates. * * Note: This method is automatically called by `connect()` if the `autoResize` * option is true (default). You typically don't need to call this manually unless * you disabled autoResize and want to enable it later. * * @returns Cleanup function to disconnect the observer * * @example Manual setup for custom scenarios * ```ts source="./app.examples.ts#App_setupAutoResize_manual" * const app = new App( * { name: "MyApp", version: "1.0.0" }, * {}, * { autoResize: false }, * ); * await app.connect(transport); * * // Later, enable auto-resize manually * const cleanup = app.setupSizeChangedNotifications(); * * // Clean up when done * cleanup(); * ``` */ setupSizeChangedNotifications(): () => void; /** * Establish connection with the host and perform initialization handshake. * * This method performs the following steps: * 1. Connects the transport layer * 2. Sends `ui/initialize` request with app info and capabilities * 3. Receives host capabilities and context in response * 4. Sends `ui/notifications/initialized` notification * 5. Sets up auto-resize using {@link setupSizeChangedNotifications `setupSizeChangedNotifications`} if enabled (default) * * If initialization fails, the connection is automatically closed and an error * is thrown. * * @param transport - Transport layer (typically {@link PostMessageTransport `PostMessageTransport`}) * @param options - Request options for the initialize request * * @throws {Error} If initialization fails or connection is lost * * @example Connect with PostMessageTransport * ```ts source="./app.examples.ts#App_connect_withPostMessageTransport" * const app = new App({ name: "MyApp", version: "1.0.0" }, {}); * * try { * await app.connect(new PostMessageTransport(window.parent, window.parent)); * console.log("Connected successfully!"); * } catch (error) { * console.error("Failed to connect:", error); * } * ``` * * @see {@link McpUiInitializeRequest `McpUiInitializeRequest`} for the initialization request structure * @see {@link McpUiInitializedNotification `McpUiInitializedNotification`} for the initialized notification * @see {@link PostMessageTransport `PostMessageTransport`} for the typical transport implementation */ connect(transport?: Transport, options?: RequestOptions): Promise; }