Improve JSDoc comments with cross-references and clarifications (#254)

Key improvements:
- Add `{@link}` cross-references throughout the codebase to make API
  documentation navigable and help AI models understand relationships
- Use `{@link module!Export}` syntax for cross-module references
- Add backticks for inline code formatting (`ResizeObserver`, `App`, etc)
- Fix `PostMessageTransport` examples to show required two-argument form
- Clarify `onteardown` callback return type requirement
- Document React hooks cleanup behavior and Strict Mode considerations
- Add tool visibility example for `registerAppTool`
- Add CSP example for `registerAppResource`
- Fix notification direction documentation in `spec.types.ts`

TypeDoc config migrated from `typedoc.json` to `typedoc.config.mjs` to:
- Support custom `@description` block tag
- Add `intentionallyNotExported` for internal types
- Include `src/server/index.ts` entry point

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jonathan Hefner 2026-01-13 18:41:17 -06:00 • committed by GitHub
commit d48e35d88a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 359 additions and 231 deletions

View file

@ -92,7 +92,7 @@ export { PostMessageTransport } from "./message-transport";
* *
* @param tool - A tool object with optional `_meta` property * @param tool - A tool object with optional `_meta` property
* @returns The UI resource URI if valid, undefined if not present * @returns The UI resource URI if valid, undefined if not present
* @throws Error if resourceUri is present but invalid (not starting with "ui://") * @throws Error if resourceUri is present but invalid (does not start with "ui://")
* *
* @example * @example
* ```typescript * ```typescript
@ -158,9 +158,12 @@ export function buildAllowAttribute(
} }
/** /**
* Options for configuring AppBridge behavior. * Options for configuring {@link AppBridge} behavior.
* *
* @see ProtocolOptions from @modelcontextprotocol/sdk for available options * @property hostContext - Optional initial host context to provide to the Guest UI
*
* @see `ProtocolOptions` from @modelcontextprotocol/sdk for available options
* @see {@link McpUiHostContext} for the hostContext structure
*/ */
export type HostOptions = ProtocolOptions & { export type HostOptions = ProtocolOptions & {
hostContext?: McpUiHostContext; hostContext?: McpUiHostContext;
@ -177,7 +180,7 @@ export const SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION];
/** /**
* Extra metadata passed to request handlers. * Extra metadata passed to request handlers.
* *
* This type represents the additional context provided by the Protocol class * This type represents the additional context provided by the `Protocol` class
* when handling requests, including abort signals and session information. * when handling requests, including abort signals and session information.
* It is extracted from the MCP SDK's request handler signature. * It is extracted from the MCP SDK's request handler signature.
* *
@ -188,12 +191,13 @@ type RequestHandlerExtra = Parameters<
>[1]; >[1];
/** /**
* Host-side bridge for communicating with a single Guest UI (App). * Host-side bridge for communicating with a single Guest UI ({@link app!App}).
* *
* AppBridge extends the MCP SDK's Protocol class and acts as a proxy between * `AppBridge` extends the MCP SDK's `Protocol` class and acts as a proxy between
* the host application and a Guest UI running in an iframe. It automatically * the host application and a Guest UI running in an iframe. When an MCP client
* forwards MCP server capabilities (tools, resources, prompts) to the Guest UI * is provided to the constructor, it automatically forwards MCP server capabilities
* and handles the initialization handshake. * (tools, resources, prompts) to the Guest UI. It also handles the initialization
* handshake.
* *
* ## Architecture * ## Architecture
* *
@ -205,11 +209,11 @@ type RequestHandlerExtra = Parameters<
* *
* ## Lifecycle * ## Lifecycle
* *
* 1. **Create**: Instantiate AppBridge with MCP client and capabilities * 1. **Create**: Instantiate `AppBridge` with MCP client and capabilities
* 2. **Connect**: Call `connect()` with transport to establish communication * 2. **Connect**: Call `connect()` with transport to establish communication
* 3. **Wait for init**: Guest UI sends initialize request, bridge responds * 3. **Wait for init**: Guest UI sends initialize request, bridge responds
* 4. **Send data**: Call `sendToolInput()`, `sendToolResult()`, etc. * 4. **Send data**: Call {@link sendToolInput}, {@link sendToolResult}, etc.
* 5. **Teardown**: Call `teardownResource()` before unmounting iframe * 5. **Teardown**: Call {@link teardownResource} before unmounting iframe
* *
* @example Basic usage * @example Basic usage
* ```typescript * ```typescript
@ -261,7 +265,7 @@ export class AppBridge extends Protocol<
* @param _client - MCP client connected to the server, or `null`. When provided, * @param _client - MCP client connected to the server, or `null`. When provided,
* {@link connect} will automatically set up forwarding of MCP requests/notifications * {@link connect} will automatically set up forwarding of MCP requests/notifications
* between the Guest UI and the server. When `null`, you must register handlers * between the Guest UI and the server. When `null`, you must register handlers
* manually using the `oncalltool`, `onlistresources`, etc. setters. * manually using the {@link oncalltool}, {@link onlistresources}, etc. setters.
* @param _hostInfo - Host application identification (name and version) * @param _hostInfo - Host application identification (name and version)
* @param _capabilities - Features and capabilities the host supports * @param _capabilities - Features and capabilities the host supports
* @param options - Configuration options (inherited from Protocol) * @param options - Configuration options (inherited from Protocol)
@ -363,7 +367,7 @@ export class AppBridge extends Protocol<
* Optional handler for ping requests from the Guest UI. * Optional handler for ping requests from the Guest UI.
* *
* The Guest UI can send standard MCP `ping` requests to verify the connection * The Guest UI can send standard MCP `ping` requests to verify the connection
* is alive. The AppBridge automatically responds with an empty object, but this * is alive. The {@link AppBridge} automatically responds with an empty object, but this
* handler allows the host to observe or log ping activity. * handler allows the host to observe or log ping activity.
* *
* Unlike the other handlers which use setters, this is a direct property * Unlike the other handlers which use setters, this is a direct property
@ -385,7 +389,7 @@ export class AppBridge extends Protocol<
* Register a handler for size change notifications from the Guest UI. * Register a handler for size change notifications from the Guest UI.
* *
* The Guest UI sends `ui/notifications/size-changed` when its rendered content * The Guest UI sends `ui/notifications/size-changed` when its rendered content
* size changes, typically via ResizeObserver. Set this callback to dynamically * size changes, typically via `ResizeObserver`. Set this callback to dynamically
* adjust the iframe container dimensions based on the Guest UI's content. * adjust the iframe container dimensions based on the Guest UI's content.
* *
* Note: This is for Guest UI → Host communication. To notify the Guest UI of * Note: This is for Guest UI → Host communication. To notify the Guest UI of
@ -404,7 +408,7 @@ export class AppBridge extends Protocol<
* ``` * ```
* *
* @see {@link McpUiSizeChangedNotification} for the notification type * @see {@link McpUiSizeChangedNotification} for the notification type
* @see {@link app.App.sendSizeChanged} for Host → Guest UI size notifications * @see {@link app!App.sendSizeChanged} - the Guest UI method that sends these notifications
*/ */
set onsizechange( set onsizechange(
callback: (params: McpUiSizeChangedNotification["params"]) => void, callback: (params: McpUiSizeChangedNotification["params"]) => void,
@ -490,10 +494,10 @@ export class AppBridge extends Protocol<
* leakage. * leakage.
* *
* @param callback - Handler that receives message params and returns a result * @param callback - Handler that receives message params and returns a result
* - params.role - Message role (currently only "user" is supported) * - `params.role` - Message role (currently only "user" is supported)
* - params.content - Message content blocks (text, image, etc.) * - `params.content` - Message content blocks (text, image, etc.)
* - extra - Request metadata (abort signal, session info) * - `extra` - Request metadata (abort signal, session info)
* - Returns: Promise<McpUiMessageResult> with optional isError flag * - Returns: `Promise<McpUiMessageResult>` with optional `isError` flag
* *
* @example * @example
* ```typescript * ```typescript
@ -539,9 +543,9 @@ export class AppBridge extends Protocol<
* - Reject the request entirely * - Reject the request entirely
* *
* @param callback - Handler that receives URL params and returns a result * @param callback - Handler that receives URL params and returns a result
* - params.url - URL to open in the host's browser * - `params.url` - URL to open in the host's browser
* - extra - Request metadata (abort signal, session info) * - `extra` - Request metadata (abort signal, session info)
* - Returns: Promise<McpUiOpenLinkResult> with optional isError flag * - Returns: `Promise<McpUiOpenLinkResult>` with optional `isError` flag
* *
* @example * @example
* ```typescript * ```typescript
@ -593,17 +597,22 @@ export class AppBridge extends Protocol<
* If the requested mode is not available, the handler should return the current * If the requested mode is not available, the handler should return the current
* display mode instead. * display mode instead.
* *
* By default, `AppBridge` returns the current `displayMode` from host context (or "inline").
* Setting this property replaces that default behavior.
*
* @param callback - Handler that receives the requested mode and returns the actual mode set * @param callback - Handler that receives the requested mode and returns the actual mode set
* - params.mode - The display mode being requested ("inline" | "fullscreen" | "pip") * - `params.mode` - The display mode being requested ("inline" | "fullscreen" | "pip")
* - extra - Request metadata (abort signal, session info) * - `extra` - Request metadata (abort signal, session info)
* - Returns: Promise<McpUiRequestDisplayModeResult> with the actual mode set * - Returns: `Promise<McpUiRequestDisplayModeResult>` with the actual mode set
* *
* @example * @example
* ```typescript * ```typescript
* let currentDisplayMode: McpUiDisplayMode = "inline";
*
* bridge.onrequestdisplaymode = async ({ mode }, extra) => { * bridge.onrequestdisplaymode = async ({ mode }, extra) => {
* const availableModes = hostContext.availableDisplayModes ?? ["inline"]; * const availableModes = hostContext.availableDisplayModes ?? ["inline"];
* if (availableModes.includes(mode)) { * if (availableModes.includes(mode)) {
* setDisplayMode(mode); * currentDisplayMode = mode;
* return { mode }; * return { mode };
* } * }
* // Return current mode if requested mode not available * // Return current mode if requested mode not available
@ -640,9 +649,9 @@ export class AppBridge extends Protocol<
* message type. * message type.
* *
* @param callback - Handler that receives logging params * @param callback - Handler that receives logging params
* - params.level - Log level: "debug" | "info" | "notice" | "warning" | "error" | "critical" | "alert" | "emergency" * - `params.level` - Log level: "debug" | "info" | "notice" | "warning" | "error" | "critical" | "alert" | "emergency"
* - params.logger - Optional logger name/identifier * - `params.logger` - Optional logger name/identifier
* - params.data - Log message and optional structured data * - `params.data` - Log message and optional structured data
* *
* @example * @example
* ```typescript * ```typescript
@ -716,9 +725,9 @@ export class AppBridge extends Protocol<
* by forwarding them to the MCP server. * by forwarding them to the MCP server.
* *
* @param callback - Handler that receives tool call params and returns a * @param callback - Handler that receives tool call params and returns a
* {@link CallToolResult} * `CallToolResult`
* @param callback.params - Tool call parameters (name and arguments) * - `params` - Tool call parameters (name and arguments)
* @param callback.extra - Request metadata (abort signal, session info) * - `extra` - Request metadata (abort signal, session info)
* *
* @example * @example
* ```typescript * ```typescript
@ -731,8 +740,8 @@ export class AppBridge extends Protocol<
* }; * };
* ``` * ```
* *
* @see {@link CallToolRequest} for the request type * @see `CallToolRequest` from @modelcontextprotocol/sdk for the request type
* @see {@link CallToolResult} for the result type * @see `CallToolResult` from @modelcontextprotocol/sdk for the result type
*/ */
set oncalltool( set oncalltool(
callback: ( callback: (
@ -762,7 +771,7 @@ export class AppBridge extends Protocol<
* }); * });
* ``` * ```
* *
* @see {@link ToolListChangedNotification} for the notification type * @see `ToolListChangedNotification` from @modelcontextprotocol/sdk for the notification type
*/ */
sendToolListChanged(params: ToolListChangedNotification["params"] = {}) { sendToolListChanged(params: ToolListChangedNotification["params"] = {}) {
return this.notification({ return this.notification({
@ -779,9 +788,9 @@ export class AppBridge extends Protocol<
* requests, typically by forwarding them to the MCP server. * requests, typically by forwarding them to the MCP server.
* *
* @param callback - Handler that receives list params and returns a * @param callback - Handler that receives list params and returns a
* {@link ListResourcesResult} * `ListResourcesResult`
* @param callback.params - Request params (may include cursor for pagination) * - `params` - Request params (may include cursor for pagination)
* @param callback.extra - Request metadata (abort signal, session info) * - `extra` - Request metadata (abort signal, session info)
* *
* @example * @example
* ```typescript * ```typescript
@ -794,8 +803,8 @@ export class AppBridge extends Protocol<
* }; * };
* ``` * ```
* *
* @see {@link ListResourcesRequest} for the request type * @see `ListResourcesRequest` from @modelcontextprotocol/sdk for the request type
* @see {@link ListResourcesResult} for the result type * @see `ListResourcesResult` from @modelcontextprotocol/sdk for the result type
*/ */
set onlistresources( set onlistresources(
callback: ( callback: (
@ -819,9 +828,9 @@ export class AppBridge extends Protocol<
* these requests, typically by forwarding them to the MCP server. * these requests, typically by forwarding them to the MCP server.
* *
* @param callback - Handler that receives list params and returns a * @param callback - Handler that receives list params and returns a
* {@link ListResourceTemplatesResult} * `ListResourceTemplatesResult`
* @param callback.params - Request params (may include cursor for pagination) * - `params` - Request params (may include cursor for pagination)
* @param callback.extra - Request metadata (abort signal, session info) * - `extra` - Request metadata (abort signal, session info)
* *
* @example * @example
* ```typescript * ```typescript
@ -834,8 +843,8 @@ export class AppBridge extends Protocol<
* }; * };
* ``` * ```
* *
* @see {@link ListResourceTemplatesRequest} for the request type * @see `ListResourceTemplatesRequest` from @modelcontextprotocol/sdk for the request type
* @see {@link ListResourceTemplatesResult} for the result type * @see `ListResourceTemplatesResult` from @modelcontextprotocol/sdk for the result type
*/ */
set onlistresourcetemplates( set onlistresourcetemplates(
callback: ( callback: (
@ -859,9 +868,9 @@ export class AppBridge extends Protocol<
* requests, typically by forwarding them to the MCP server. * requests, typically by forwarding them to the MCP server.
* *
* @param callback - Handler that receives read params and returns a * @param callback - Handler that receives read params and returns a
* {@link ReadResourceResult} * `ReadResourceResult`
* @param callback.params - Read parameters including the resource URI * - `params` - Read parameters including the resource URI
* @param callback.extra - Request metadata (abort signal, session info) * - `extra` - Request metadata (abort signal, session info)
* *
* @example * @example
* ```typescript * ```typescript
@ -874,8 +883,8 @@ export class AppBridge extends Protocol<
* }; * };
* ``` * ```
* *
* @see {@link ReadResourceRequest} for the request type * @see `ReadResourceRequest` from @modelcontextprotocol/sdk for the request type
* @see {@link ReadResourceResult} for the result type * @see `ReadResourceResult` from @modelcontextprotocol/sdk for the result type
*/ */
set onreadresource( set onreadresource(
callback: ( callback: (
@ -908,7 +917,7 @@ export class AppBridge extends Protocol<
* }); * });
* ``` * ```
* *
* @see {@link ResourceListChangedNotification} for the notification type * @see `ResourceListChangedNotification` from @modelcontextprotocol/sdk for the notification type
*/ */
sendResourceListChanged( sendResourceListChanged(
params: ResourceListChangedNotification["params"] = {}, params: ResourceListChangedNotification["params"] = {},
@ -927,9 +936,9 @@ export class AppBridge extends Protocol<
* requests, typically by forwarding them to the MCP server. * requests, typically by forwarding them to the MCP server.
* *
* @param callback - Handler that receives list params and returns a * @param callback - Handler that receives list params and returns a
* {@link ListPromptsResult} * `ListPromptsResult`
* @param callback.params - Request params (may include cursor for pagination) * - `params` - Request params (may include cursor for pagination)
* @param callback.extra - Request metadata (abort signal, session info) * - `extra` - Request metadata (abort signal, session info)
* *
* @example * @example
* ```typescript * ```typescript
@ -942,8 +951,8 @@ export class AppBridge extends Protocol<
* }; * };
* ``` * ```
* *
* @see {@link ListPromptsRequest} for the request type * @see `ListPromptsRequest` from @modelcontextprotocol/sdk for the request type
* @see {@link ListPromptsResult} for the result type * @see `ListPromptsResult` from @modelcontextprotocol/sdk for the result type
*/ */
set onlistprompts( set onlistprompts(
callback: ( callback: (
@ -973,7 +982,7 @@ export class AppBridge extends Protocol<
* }); * });
* ``` * ```
* *
* @see {@link PromptListChangedNotification} for the notification type * @see `PromptListChangedNotification` from @modelcontextprotocol/sdk for the notification type
*/ */
sendPromptListChanged(params: PromptListChangedNotification["params"] = {}) { sendPromptListChanged(params: PromptListChangedNotification["params"] = {}) {
return this.notification({ return this.notification({
@ -1062,9 +1071,10 @@ export class AppBridge extends Protocol<
/** /**
* Update the host context and notify the Guest UI of changes. * Update the host context and notify the Guest UI of changes.
* *
* Compares the new context with the current context and sends a * Compares fields present in the new context with the current context and sends a
* `ui/notifications/host-context-changed` notification containing only the * `ui/notifications/host-context-changed` notification containing only fields
* fields that have changed. If no fields have changed, no notification is sent. * that have been added or modified. If no fields have changed, no notification is sent.
* The new context fully replaces the internal state.
* *
* Common use cases include notifying the Guest UI when: * Common use cases include notifying the Guest UI when:
* - Theme changes (light/dark mode toggle) * - Theme changes (light/dark mode toggle)
@ -1111,8 +1121,13 @@ export class AppBridge extends Protocol<
} }
/** /**
* Send a host context change notification to the app. * Low-level method to notify the Guest UI of host context changes.
* Only sends the fields that have changed (partial update). *
* Most hosts should use {@link setHostContext} instead, which automatically
* detects changes and calls this method with only the modified fields.
* Use this directly only when you need fine-grained control over change detection.
*
* @param params - The context fields that have changed (partial update)
*/ */
sendHostContextChange( sendHostContextChange(
params: McpUiHostContextChangedNotification["params"], params: McpUiHostContextChangedNotification["params"],
@ -1225,7 +1240,7 @@ export class AppBridge extends Protocol<
* any other interruption. This allows the Guest UI to update its state and * any other interruption. This allows the Guest UI to update its state and
* display appropriate feedback to the user. * display appropriate feedback to the user.
* *
* @param params - Optional cancellation details: * @param params - Cancellation details object
* - `reason`: Human-readable explanation for why the tool was cancelled * - `reason`: Human-readable explanation for why the tool was cancelled
* *
* @example User-initiated cancellation * @example User-initiated cancellation
@ -1330,13 +1345,13 @@ export class AppBridge extends Protocol<
* - Prompts (prompts/list, notifications/prompts/list_changed) * - Prompts (prompts/list, notifications/prompts/list_changed)
* *
* If no client was passed to the constructor, no automatic forwarding is set up * If no client was passed to the constructor, no automatic forwarding is set up
* and you must register handlers manually using the `oncalltool`, `onlistresources`, * and you must register handlers manually using the {@link oncalltool}, {@link onlistresources},
* etc. setters. * etc. setters.
* *
* After calling connect, wait for the `oninitialized` callback before sending * After calling connect, wait for the {@link oninitialized} callback before sending
* tool input and other data to the Guest UI. * tool input and other data to the Guest UI.
* *
* @param transport - Transport layer (typically PostMessageTransport) * @param transport - Transport layer (typically {@link PostMessageTransport})
* @returns Promise resolving when connection is established * @returns Promise resolving when connection is established
* *
* @throws {Error} If a client was passed but server capabilities are not available. * @throws {Error} If a client was passed but server capabilities are not available.

View file

@ -64,7 +64,7 @@ export {
* *
* MCP servers include this key in tool call result metadata to indicate which * MCP servers include this key in tool call result metadata to indicate which
* UI resource should be displayed for the tool. When hosts receive a tool result * UI resource should be displayed for the tool. When hosts receive a tool result
* containing this metadata, they resolve and render the corresponding App. * containing this metadata, they resolve and render the corresponding {@link App}.
* *
* **Note**: This constant is provided for reference. MCP servers set this metadata * **Note**: This constant is provided for reference. MCP servers set this metadata
* in their tool handlers; App developers typically don't need to use it directly. * in their tool handlers; App developers typically don't need to use it directly.
@ -93,21 +93,25 @@ export const RESOURCE_URI_META_KEY = "ui/resourceUri";
/** /**
* MIME type for MCP UI resources. * MIME type for MCP UI resources.
*
* Identifies HTML content as an MCP App UI resource.
*
* Used by {@link server-helpers!registerAppResource} as the default MIME type for app resources.
*/ */
export const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app"; export const RESOURCE_MIME_TYPE = "text/html;profile=mcp-app";
/** /**
* Options for configuring App behavior. * Options for configuring {@link App} behavior.
* *
* Extends ProtocolOptions from the MCP SDK with App-specific configuration. * Extends `ProtocolOptions` from the MCP SDK with `App`-specific configuration.
* *
* @see ProtocolOptions from @modelcontextprotocol/sdk for inherited options * @see `ProtocolOptions` from @modelcontextprotocol/sdk for inherited options
*/ */
type AppOptions = ProtocolOptions & { type AppOptions = ProtocolOptions & {
/** /**
* Automatically report size changes to the host using ResizeObserver. * Automatically report size changes to the host using `ResizeObserver`.
* *
* When enabled, the App monitors `document.body` and `document.documentElement` * When enabled, the {@link App} monitors `document.body` and `document.documentElement`
* for size changes and automatically sends `ui/notifications/size-changed` * for size changes and automatically sends `ui/notifications/size-changed`
* notifications to the host. * notifications to the host.
* *
@ -123,8 +127,8 @@ type RequestHandlerExtra = Parameters<
/** /**
* Main class for MCP Apps to communicate with their host. * Main class for MCP Apps to communicate with their host.
* *
* The App class provides a framework-agnostic way to build interactive MCP Apps * 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 * that run inside host applications. It extends the MCP SDK's `Protocol` class and
* handles the connection lifecycle, initialization handshake, and bidirectional * handles the connection lifecycle, initialization handshake, and bidirectional
* communication with the host. * communication with the host.
* *
@ -143,19 +147,20 @@ type RequestHandlerExtra = Parameters<
* *
* ## Inherited Methods * ## Inherited Methods
* *
* As a subclass of Protocol, App inherits key methods for handling communication: * As a subclass of `Protocol`, `App` inherits key methods for handling communication:
* - `setRequestHandler()` - Register handlers for requests from host * - `setRequestHandler()` - Register handlers for requests from host
* - `setNotificationHandler()` - Register handlers for notifications from host * - `setNotificationHandler()` - Register handlers for notifications from host
* *
* @see Protocol from @modelcontextprotocol/sdk for all inherited methods * @see `Protocol` from @modelcontextprotocol/sdk for all inherited methods
* *
* ## Notification Setters * ## Notification Setters
* *
* For common notifications, the App class provides convenient setter properties * For common notifications, the `App` class provides convenient setter properties
* that simplify handler registration: * that simplify handler registration:
* - `ontoolinput` - Complete tool arguments from host * - `ontoolinput` - Complete tool arguments from host
* - `ontoolinputpartial` - Streaming partial tool arguments * - `ontoolinputpartial` - Streaming partial tool arguments
* - `ontoolresult` - Tool execution results * - `ontoolresult` - Tool execution results
* - `ontoolcancelled` - Tool execution was cancelled by user or host
* - `onhostcontextchanged` - Host context changes (theme, locale, etc.) * - `onhostcontextchanged` - Host context changes (theme, locale, etc.)
* *
* These setters are convenience wrappers around `setNotificationHandler()`. * These setters are convenience wrappers around `setNotificationHandler()`.
@ -187,7 +192,7 @@ type RequestHandlerExtra = Parameters<
* } * }
* ); * );
* *
* await app.connect(new PostMessageTransport(window.parent)); * await app.connect(new PostMessageTransport(window.parent, window.parent));
* ``` * ```
* *
* @example Sending a message to the host's chat * @example Sending a message to the host's chat
@ -208,7 +213,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* *
* @param _appInfo - App identification (name and version) * @param _appInfo - App identification (name and version)
* @param _capabilities - Features and capabilities this app provides * @param _capabilities - Features and capabilities this app provides
* @param options - Configuration options including autoResize behavior * @param options - Configuration options including `autoResize` behavior
* *
* @example * @example
* ```typescript * ```typescript
@ -339,7 +344,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* *
* Register handlers before calling {@link connect} to avoid missing notifications. * Register handlers before calling {@link connect} to avoid missing notifications.
* *
* @param callback - Function called with the tool input params * @param callback - Function called with the tool input params ({@link McpUiToolInputNotification.params})
* *
* @example Using the setter (simpler) * @example Using the setter (simpler)
* ```typescript * ```typescript
@ -384,7 +389,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* *
* Register handlers before calling {@link connect} to avoid missing notifications. * Register handlers before calling {@link connect} to avoid missing notifications.
* *
* @param callback - Function called with each partial tool input update * @param callback - Function called with each partial tool input update ({@link McpUiToolInputPartialNotification.params})
* *
* @example Progressive rendering of tool arguments * @example Progressive rendering of tool arguments
* ```typescript * ```typescript
@ -418,7 +423,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* *
* Register handlers before calling {@link connect} to avoid missing notifications. * Register handlers before calling {@link connect} to avoid missing notifications.
* *
* @param callback - Function called with the tool result * @param callback - Function called with the tool result ({@link McpUiToolResultNotification.params})
* *
* @example Display tool execution results * @example Display tool execution results
* ```typescript * ```typescript
@ -457,7 +462,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* *
* Register handlers before calling {@link connect} to avoid missing notifications. * Register handlers before calling {@link connect} to avoid missing notifications.
* *
* @param callback - Function called when tool execution is cancelled * @param callback - Function called when tool execution is cancelled. Receives optional cancellation reason — see {@link McpUiToolCancelledNotification.params}.
* *
* @example Handle tool cancellation * @example Handle tool cancellation
* ```typescript * ```typescript
@ -490,6 +495,10 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* This setter is a convenience wrapper around `setNotificationHandler()` that * This setter is a convenience wrapper around `setNotificationHandler()` that
* automatically handles the notification schema and extracts the params for you. * automatically handles the notification schema and extracts the params for you.
* *
* Notification params are automatically merged into the internal host context
* before the callback is invoked. This means {@link getHostContext} will
* return the updated values even before your callback runs.
*
* Register handlers before calling {@link connect} to avoid missing notifications. * Register handlers before calling {@link connect} to avoid missing notifications.
* *
* @param callback - Function called with the updated host context * @param callback - Function called with the updated host context
@ -538,7 +547,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* Register handlers before calling {@link connect} to avoid missing requests. * Register handlers before calling {@link connect} to avoid missing requests.
* *
* @param callback - Function called when teardown is requested. * @param callback - Function called when teardown is requested.
* Can return void or a Promise that resolves when cleanup is complete. * Must return `McpUiResourceTeardownResult` (can be an empty object `{}`) or a Promise resolving to it.
* *
* @example Perform cleanup before teardown * @example Perform cleanup before teardown
* ```typescript * ```typescript
@ -546,6 +555,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* await saveState(); * await saveState();
* closeConnections(); * closeConnections();
* console.log("App ready for teardown"); * console.log("App ready for teardown");
* return {};
* }; * };
* ``` * ```
* *
@ -620,9 +630,9 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* *
* Register handlers before calling {@link connect} to avoid missing requests. * Register handlers before calling {@link connect} to avoid missing requests.
* *
* @param callback - Async function that returns the list of available tools. * @param callback - Async function that returns tool names as strings (simplified
* The callback will only be invoked if the app declared tool capabilities * from full `ListToolsResult` with `Tool` objects). Registration is always
* in the constructor. * allowed; capability validation occurs when handlers are invoked.
* *
* @example Return available tools * @example Return available tools
* ```typescript * ```typescript
@ -1050,7 +1060,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* If initialization fails, the connection is automatically closed and an error * If initialization fails, the connection is automatically closed and an error
* is thrown. * is thrown.
* *
* @param transport - Transport layer (typically PostMessageTransport) * @param transport - Transport layer (typically {@link PostMessageTransport})
* @param options - Request options for the initialize request * @param options - Request options for the initialize request
* *
* @throws {Error} If initialization fails or connection is lost * @throws {Error} If initialization fails or connection is lost
@ -1063,7 +1073,7 @@ export class App extends Protocol<AppRequest, AppNotification, AppResult> {
* ); * );
* *
* try { * try {
* await app.connect(new PostMessageTransport(window.parent)); * await app.connect(new PostMessageTransport(window.parent, window.parent));
* console.log("Connected successfully!"); * console.log("Connected successfully!");
* } catch (error) { * } catch (error) {
* console.error("Failed to connect:", error); * console.error("Failed to connect:", error);

View file

@ -839,7 +839,6 @@
"type": "object", "type": "object",
"properties": { "properties": {
"fonts": { "fonts": {
"description": "CSS for font loading (@font-face rules or",
"type": "string" "type": "string"
} }
}, },
@ -1593,7 +1592,6 @@
"type": "object", "type": "object",
"properties": { "properties": {
"fonts": { "fonts": {
"description": "CSS for font loading (@font-face rules or",
"type": "string" "type": "string"
} }
}, },
@ -1767,7 +1765,6 @@
"type": "object", "type": "object",
"properties": { "properties": {
"fonts": { "fonts": {
"description": "CSS for font loading (@font-face rules or",
"type": "string" "type": "string"
} }
}, },
@ -2186,7 +2183,6 @@
"type": "object", "type": "object",
"properties": { "properties": {
"fonts": { "fonts": {
"description": "CSS for font loading (@font-face rules or",
"type": "string" "type": "string"
} }
}, },
@ -3133,7 +3129,6 @@
"type": "object", "type": "object",
"properties": { "properties": {
"fonts": { "fonts": {
"description": "CSS for font loading (@font-face rules or",
"type": "string" "type": "string"
} }
}, },

View file

@ -135,7 +135,7 @@ export const McpUiStylesSchema = z
/** /**
* @description Request to open an external URL in the host's default browser. * @description Request to open an external URL in the host's default browser.
* @see {@link app.App.sendOpenLink} for the method that sends this request * @see {@link app!App.openLink} for the method that sends this request
*/ */
export const McpUiOpenLinkRequestSchema = z.object({ export const McpUiOpenLinkRequestSchema = z.object({
method: z.literal("ui/open-link"), method: z.literal("ui/open-link"),
@ -246,8 +246,8 @@ export const McpUiResourcePermissionsSchema = z.object({
}); });
/** /**
* @description Notification of UI size changes (bidirectional: Guest <-> Host). * @description Notification of UI size changes (Guest UI -> Host).
* @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI * @see {@link app!App.sendSizeChanged} for the method to send this from Guest UI
*/ */
export const McpUiSizeChangedNotificationSchema = z.object({ export const McpUiSizeChangedNotificationSchema = z.object({
method: z.literal("ui/notifications/size-changed"), method: z.literal("ui/notifications/size-changed"),
@ -319,11 +319,8 @@ export const McpUiToolCancelledNotificationSchema = z.object({
* @description CSS blocks that can be injected by apps. * @description CSS blocks that can be injected by apps.
*/ */
export const McpUiHostCssSchema = z.object({ export const McpUiHostCssSchema = z.object({
/** @description CSS for font loading (@font-face rules or @import statements). Apps must apply using applyHostFonts(). */ /** @description CSS for font loading (`@font-face` rules or `@import` statements). Apps must apply using {@link applyHostFonts}. */
fonts: z fonts: z.string().optional(),
.string()
.optional()
.describe("CSS for font loading (@font-face rules or"),
}); });
/** /**
@ -342,7 +339,7 @@ export const McpUiHostStylesSchema = z.object({
/** /**
* @description Request for graceful shutdown of the Guest UI (Host -> Guest UI). * @description Request for graceful shutdown of the Guest UI (Host -> Guest UI).
* @see {@link app-bridge.AppBridge.teardownResource} for the host method that sends this * @see {@link app-bridge!AppBridge.teardownResource} for the host method that sends this
*/ */
export const McpUiResourceTeardownRequestSchema = z.object({ export const McpUiResourceTeardownRequestSchema = z.object({
method: z.literal("ui/resource-teardown"), method: z.literal("ui/resource-teardown"),
@ -453,7 +450,7 @@ export const McpUiHostCapabilitiesSchema = z.object({
}); });
/** /**
* @description Capabilities provided by the Guest UI (App). * @description Capabilities provided by the Guest UI ({@link app!App}).
* @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities * @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities
*/ */
export const McpUiAppCapabilitiesSchema = z.object({ export const McpUiAppCapabilitiesSchema = z.object({
@ -477,7 +474,7 @@ export const McpUiAppCapabilitiesSchema = z.object({
/** /**
* @description Notification that Guest UI has completed initialization (Guest UI -> Host). * @description Notification that Guest UI has completed initialization (Guest UI -> Host).
* @see {@link app.App.connect} for the method that sends this notification * @see {@link app!App.connect} for the method that sends this notification
*/ */
export const McpUiInitializedNotificationSchema = z.object({ export const McpUiInitializedNotificationSchema = z.object({
method: z.literal("ui/notifications/initialized"), method: z.literal("ui/notifications/initialized"),
@ -514,7 +511,7 @@ export const McpUiResourceMetaSchema = z.object({
* @description Request to change the display mode of the UI. * @description Request to change the display mode of the UI.
* The host will respond with the actual display mode that was set, * The host will respond with the actual display mode that was set,
* which may differ from the requested mode if not supported. * which may differ from the requested mode if not supported.
* @see {@link app.App.requestDisplayMode} for the method that sends this request * @see {@link app!App.requestDisplayMode} for the method that sends this request
*/ */
export const McpUiRequestDisplayModeRequestSchema = z.object({ export const McpUiRequestDisplayModeRequestSchema = z.object({
method: z.literal("ui/request-display-mode"), method: z.literal("ui/request-display-mode"),
@ -570,7 +567,7 @@ export const McpUiToolMetaSchema = z.object({
/** /**
* @description Request to send a message to the host's chat interface. * @description Request to send a message to the host's chat interface.
* @see {@link app.App.sendMessage} for the method that sends this request * @see {@link app!App.sendMessage} for the method that sends this request
*/ */
export const McpUiMessageRequestSchema = z.object({ export const McpUiMessageRequestSchema = z.object({
method: z.literal("ui/message"), method: z.literal("ui/message"),
@ -788,7 +785,7 @@ export const McpUiUpdateModelContextRequestSchema = z.object({
/** /**
* @description Initialization request sent from Guest UI to Host. * @description Initialization request sent from Guest UI to Host.
* @see {@link app.App.connect} for the method that sends this request * @see {@link app!App.connect} for the method that sends this request
*/ */
export const McpUiInitializeRequestSchema = z.object({ export const McpUiInitializeRequestSchema = z.object({
method: z.literal("ui/initialize"), method: z.literal("ui/initialize"),

View file

@ -9,39 +9,38 @@ import {
} from "@modelcontextprotocol/sdk/shared/transport.js"; } from "@modelcontextprotocol/sdk/shared/transport.js";
/** /**
* JSON-RPC transport using window.postMessage for iframe↔parent communication. * JSON-RPC transport using `window.postMessage` for iframe↔parent communication.
* *
* This transport enables bidirectional communication between MCP Apps running in * This transport enables bidirectional communication between MCP Apps running in
* iframes and their host applications using the browser's postMessage API. It * iframes and their host applications using the browser's `postMessage` API. It
* implements the MCP SDK's Transport interface. * implements the MCP SDK's `Transport` interface.
* *
* ## Security * ## Security
* *
* The `eventSource` parameter provides origin validation by filtering messages * The `eventSource` parameter is required and validates the message source window
* from specific sources. Guest UIs typically don't need to specify this (they only * by checking `event.source`. For guest UIs, pass `window.parent`.
* communicate with their parent), but hosts should validate the iframe source for * For hosts, pass `iframe.contentWindow` to validate the iframe source.
* security.
* *
* ## Usage * ## Usage
* *
* **Guest UI (default)**: * **Guest UI**:
* ```typescript * ```typescript
* const transport = new PostMessageTransport(window.parent); * const transport = new PostMessageTransport(window.parent, window.parent);
* await app.connect(transport); * await app.connect(transport);
* ``` * ```
* *
* **Host (with source validation)**: * **Host**:
* ```typescript * ```typescript
* const iframe = document.getElementById('app-iframe') as HTMLIFrameElement; * const iframe = document.getElementById('app-iframe') as HTMLIFrameElement;
* const transport = new PostMessageTransport( * const transport = new PostMessageTransport(
* iframe.contentWindow!, * iframe.contentWindow!,
* iframe.contentWindow // Validate messages from this iframe only * iframe.contentWindow!
* ); * );
* await bridge.connect(transport); * await bridge.connect(transport);
* ``` * ```
* *
* @see {@link app.App.connect} for Guest UI usage * @see {@link app!App.connect} for Guest UI usage
* @see {@link app-bridge.AppBridge.connect} for Host usage * @see {@link app-bridge!AppBridge.connect} for Host usage
*/ */
export class PostMessageTransport implements Transport { export class PostMessageTransport implements Transport {
private messageListener: ( private messageListener: (
@ -52,22 +51,21 @@ export class PostMessageTransport implements Transport {
/** /**
* Create a new PostMessageTransport. * Create a new PostMessageTransport.
* *
* @param eventTarget - Target window to send messages to (default: window.parent) * @param eventTarget - Target window to send messages to (default: `window.parent`)
* @param eventSource - Optional source validation. If specified, only messages from * @param eventSource - Source window for message validation. For guests, pass
* this source will be accepted. Guest UIs typically don't need this (they only * `window.parent`. For hosts, pass `iframe.contentWindow`.
* receive from parent), but hosts should validate the iframe source.
* *
* @example Guest UI connecting to parent * @example Guest UI connecting to parent
* ```typescript * ```typescript
* const transport = new PostMessageTransport(window.parent); * const transport = new PostMessageTransport(window.parent, window.parent);
* ``` * ```
* *
* @example Host connecting to iframe with validation * @example Host connecting to iframe
* ```typescript * ```typescript
* const iframe = document.getElementById('app') as HTMLIFrameElement; * const iframe = document.getElementById('app') as HTMLIFrameElement;
* const transport = new PostMessageTransport( * const transport = new PostMessageTransport(
* iframe.contentWindow!, * iframe.contentWindow!,
* iframe.contentWindow // Only accept messages from this iframe * iframe.contentWindow!
* ); * );
* ``` * ```
*/ */
@ -108,7 +106,7 @@ export class PostMessageTransport implements Transport {
/** /**
* Send a JSON-RPC message to the target window. * Send a JSON-RPC message to the target window.
* *
* Messages are sent using postMessage with "*" origin, meaning they are visible * Messages are sent using `postMessage` with `"*"` origin, meaning they are visible
* to all frames. The receiver should validate the message source for security. * to all frames. The receiver should validate the message source for security.
* *
* @param message - JSON-RPC message to send * @param message - JSON-RPC message to send
@ -161,7 +159,7 @@ export class PostMessageTransport implements Transport {
* Optional session identifier for this transport connection. * Optional session identifier for this transport connection.
* *
* Set by the MCP SDK to track the connection session. Not required for * Set by the MCP SDK to track the connection session. Not required for
* PostMessageTransport functionality. * `PostMessageTransport` functionality.
*/ */
sessionId?: string; sessionId?: string;

View file

@ -5,27 +5,29 @@ import { App, McpUiAppCapabilities, PostMessageTransport } from "../app";
export * from "../app"; export * from "../app";
/** /**
* Options for configuring the useApp hook. * Options for configuring the {@link useApp} hook.
* *
* Note: This interface does NOT expose App options like `autoResize`. * Note: This interface does NOT expose {@link App} options like `autoResize`.
* The hook creates the App with default options (autoResize: true). If you need * The hook creates the `App` with default options (`autoResize: true`). If you
* custom App options, create the App manually instead of using this hook. * need custom `App` options, create the `App` manually instead of using this hook.
* *
* @see {@link useApp} for the hook that uses these options * @see {@link useApp} for the hook that uses these options
* @see {@link useAutoResize} for manual auto-resize control with custom App options * @see {@link useAutoResize} for manual auto-resize control with custom `App` options
*/ */
export interface UseAppOptions { export interface UseAppOptions {
/** App identification (name and version) */ /** App identification (name and version) */
appInfo: Implementation; appInfo: Implementation;
/** Features and capabilities this app provides */ /**
* Declares what features this app supports.
*/
capabilities: McpUiAppCapabilities; capabilities: McpUiAppCapabilities;
/** /**
* Called after App is created but before connection. * Called after {@link App} is created but before connection.
* *
* Use this to register request/notification handlers that need to be in place * Use this to register request/notification handlers that need to be in place
* before the initialization handshake completes. * before the initialization handshake completes.
* *
* @param app - The newly created App instance * @param app - The newly created `App` instance
* *
* @example Register a notification handler * @example Register a notification handler
* ```typescript * ```typescript
@ -45,10 +47,10 @@ export interface UseAppOptions {
} }
/** /**
* State returned by the useApp hook. * State returned by the {@link useApp} hook.
*/ */
export interface AppState { export interface AppState {
/** The connected App instance, null during initialization */ /** The connected {@link App} instance, null during initialization */
app: App | null; app: App | null;
/** Whether initialization completed successfully */ /** Whether initialization completed successfully */
isConnected: boolean; isConnected: boolean;
@ -59,16 +61,19 @@ export interface AppState {
/** /**
* React hook to create and connect an MCP App. * React hook to create and connect an MCP App.
* *
* This hook manages the complete lifecycle of an {@link App}: creation, connection, * This hook manages {@link App} creation and connection. It automatically
* and cleanup. It automatically creates a {@link PostMessageTransport} to window.parent * creates a {@link PostMessageTransport} to window.parent and handles
* and handles initialization. * initialization.
*
* This hook is part of the optional React integration. The core SDK (`App`,
* `PostMessageTransport`) is framework-agnostic and can be used with any UI
* framework or vanilla JavaScript.
* *
* **Important**: The hook intentionally does NOT re-run when options change * **Important**: The hook intentionally does NOT re-run when options change
* to avoid reconnection loops. Options are only used during the initial mount. * to avoid reconnection loops. Options are only used during the initial mount.
* * Furthermore, the `App` instance is NOT closed on unmount. This avoids cleanup
* **Note**: This is part of the optional React integration. The core SDK * issues during React Strict Mode's double-mount cycle. If you need to
* (App, PostMessageTransport) is framework-agnostic and can be * explicitly close the `App`, call {@link App.close} manually.
* used with any UI framework or vanilla JavaScript.
* *
* @param options - Configuration for the app * @param options - Configuration for the app
* @returns Current connection state and app instance. If connection fails during * @returns Current connection state and app instance. If connection fails during

View file

@ -4,15 +4,17 @@ import { App } from "../app";
/** /**
* React hook that automatically reports UI size changes to the host. * React hook that automatically reports UI size changes to the host.
* *
* Uses ResizeObserver to watch `document.body` and `document.documentElement` for * Uses `ResizeObserver` to watch `document.body` and `document.documentElement` for
* size changes and sends `ui/notifications/size-changed` notifications. * size changes and sends `ui/notifications/size-changed` notifications.
* *
* The hook automatically cleans up the `ResizeObserver` when the component unmounts.
*
* **Note**: This hook is rarely needed since the {@link useApp} hook automatically enables * **Note**: This hook is rarely needed since the {@link useApp} hook automatically enables
* auto-resize by default. This hook is provided for advanced cases where you * auto-resize by default. This hook is provided for advanced cases where you
* create the {@link App} manually with `autoResize: false` and want to add auto-resize * create the {@link App} manually with `autoResize: false` and want to add auto-resize
* behavior later. * behavior later.
* *
* @param app - The connected App instance, or null during initialization * @param app - The connected {@link App} instance, or null during initialization
* @param elementRef - Currently unused. The hook always observes `document.body` * @param elementRef - Currently unused. The hook always observes `document.body`
* and `document.documentElement` regardless of this value. Passing a ref will * and `document.documentElement` regardless of this value. Passing a ref will
* cause unnecessary effect re-runs; omit this parameter. * cause unnecessary effect re-runs; omit this parameter.
@ -31,7 +33,7 @@ import { App } from "../app";
* { autoResize: false } // Disable default auto-resize * { autoResize: false } // Disable default auto-resize
* ); * );
* *
* const transport = new PostMessageTransport(window.parent); * const transport = new PostMessageTransport(window.parent, window.parent);
* myApp.connect(transport) * myApp.connect(transport)
* .then(() => setApp(myApp)) * .then(() => setApp(myApp))
* .catch((err) => setError(err)); * .catch((err) => setError(err));

View file

@ -5,11 +5,13 @@ import { McpUiTheme } from "../types";
/** /**
* React hook that provides the current document theme reactively. * React hook that provides the current document theme reactively.
* *
* Uses a MutationObserver to watch for changes to the `data-theme` attribute * Uses a `MutationObserver` to watch for changes to the `data-theme` attribute
* or `class` on `document.documentElement`. When the theme changes (e.g., from * or `class` on `document.documentElement`. When the theme changes (e.g., from
* host context updates), the hook automatically re-renders your component with * host context updates), the hook automatically re-renders your component with
* the new theme value. * the new theme value.
* *
* The `MutationObserver` is automatically disconnected when the component unmounts.
*
* @returns The current theme ("light" or "dark") * @returns The current theme ("light" or "dark")
* *
* @example Conditionally render based on theme * @example Conditionally render based on theme

View file

@ -21,14 +21,13 @@ import { McpUiHostContext } from "../types";
* this hook ensures they work correctly by setting the `color-scheme` property * this hook ensures they work correctly by setting the `color-scheme` property
* based on the host's theme preference. * based on the host's theme preference.
* *
* @param app - The connected App instance, or null during initialization * @param app - The connected {@link App} instance, or null during initialization
* @param initialContext - Initial host context from the connection (optional). * @param initialContext - Initial host context from the connection (optional).
* If provided, styles and theme will be applied immediately on mount. * If provided, styles and theme will be applied immediately on mount.
* *
* @example Basic usage with useApp * @example
* ```tsx * ```tsx
* import { useApp } from '@modelcontextprotocol/ext-apps/react'; * import { useApp, useHostStyleVariables } from '@modelcontextprotocol/ext-apps/react';
* import { useHostStyleVariables } from '@modelcontextprotocol/ext-apps/react';
* *
* function MyApp() { * function MyApp() {
* const { app, isConnected } = useApp({ * const { app, isConnected } = useApp({
@ -36,8 +35,8 @@ import { McpUiHostContext } from "../types";
* capabilities: {}, * capabilities: {},
* }); * });
* *
* // Automatically apply host style variables and theme * // Apply host styles - pass initial context to apply styles from connect() immediately
* useHostStyleVariables(app); * useHostStyleVariables(app, app?.getHostContext());
* *
* return ( * return (
* <div style={{ background: 'var(--color-background-primary)' }}> * <div style={{ background: 'var(--color-background-primary)' }}>
@ -47,15 +46,6 @@ import { McpUiHostContext } from "../types";
* } * }
* ``` * ```
* *
* @example With initial context
* ```tsx
* const [hostContext, setHostContext] = useState<McpUiHostContext | null>(null);
*
* // ... get initial context from app.connect() result
*
* useHostStyleVariables(app, hostContext);
* ```
*
* @see {@link applyHostStyleVariables} for the underlying styles function * @see {@link applyHostStyleVariables} for the underlying styles function
* @see {@link applyDocumentTheme} for the underlying theme function * @see {@link applyDocumentTheme} for the underlying theme function
* @see {@link useHostFonts} for applying host fonts * @see {@link useHostFonts} for applying host fonts
@ -112,7 +102,7 @@ export function useHostStyleVariables(
* The hook also applies fonts from the initial host context when * The hook also applies fonts from the initial host context when
* the app first connects. * the app first connects.
* *
* @param app - The connected App instance, or null during initialization * @param app - The connected {@link App} instance, or null during initialization
* @param initialContext - Initial host context from the connection (optional). * @param initialContext - Initial host context from the connection (optional).
* If provided, fonts will be applied immediately on mount. * If provided, fonts will be applied immediately on mount.
* *
@ -182,13 +172,24 @@ export function useHostFonts(
} }
/** /**
* React hook that applies host styles, fonts, and theme. * Applies all host styling (CSS variables, theme, and fonts) to match the host application.
* *
* This is a convenience hook that combines {@link useHostStyleVariables} and * This is a convenience hook that combines {@link useHostStyleVariables} and
* {@link useHostFonts}. Use the individual hooks if you need more control. * {@link useHostFonts}. Use the individual hooks if you need more control.
* *
* @param app - The connected App instance, or null during initialization * @param app - The connected {@link App} instance, or null during initialization
* @param initialContext - Initial host context from the connection (optional). * @param initialContext - Initial host context from the connection (optional).
* Pass `app?.getHostContext()` to apply styles immediately on mount.
*
* @example
* ```tsx
* function MyApp() {
* const { app } = useApp({ appInfo, capabilities: {} });
* useHostStyles(app, app?.getHostContext());
*
* return <div style={{ background: 'var(--color-background-primary)' }}>...</div>;
* }
* ```
* *
* @see {@link useHostStyleVariables} for style variables and theme only * @see {@link useHostStyleVariables} for style variables and theme only
* @see {@link useHostFonts} for fonts only * @see {@link useHostFonts} for fonts only

View file

@ -1,7 +1,25 @@
/** /**
* Server Helpers for MCP Apps. * Utilities for MCP servers to register tools and resources that display interactive UIs.
*
* Use these helpers instead of the base SDK's `registerTool` and `registerResource` when
* your tool should render an {@link app!App} in the client. They handle UI metadata normalization
* and provide sensible defaults for the MCP Apps MIME type ({@link RESOURCE_MIME_TYPE}).
* *
* @module server-helpers * @module server-helpers
*
* @example
* ```typescript
* import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-apps/server';
*
* // Register a tool that displays a widget
* registerAppTool(server, "weather", {
* description: "Get weather forecast",
* _meta: { ui: { resourceUri: "ui://weather/widget.html" } },
* }, handler);
*
* // Register the HTML resource the tool references
* registerAppResource(server, "Weather Widget", "ui://weather/widget.html", {}, readCallback);
* ```
*/ */
import { import {
@ -29,7 +47,8 @@ export { RESOURCE_URI_META_KEY, RESOURCE_MIME_TYPE };
export type { ResourceMetadata, ToolCallback, ReadResourceCallback }; export type { ResourceMetadata, ToolCallback, ReadResourceCallback };
/** /**
* Tool configuration (same as McpServer.registerTool). * Base tool configuration matching the standard MCP server tool options.
* Extended by {@link McpUiAppToolConfig} to add UI metadata requirements.
*/ */
export interface ToolConfig { export interface ToolConfig {
title?: string; title?: string;
@ -41,7 +60,14 @@ export interface ToolConfig {
} }
/** /**
* MCP App Tool configuration for `registerAppTool`. * Configuration for tools that render an interactive UI.
*
* Extends {@link ToolConfig} with a required `_meta` field that specifies UI metadata.
* The UI resource can be specified in two ways:
* - `_meta.ui.resourceUri` (preferred)
* - `_meta["ui/resourceUri"]` (deprecated, for backward compatibility)
*
* @see {@link registerAppTool} for the recommended way to register app tools
*/ */
export interface McpUiAppToolConfig extends ToolConfig { export interface McpUiAppToolConfig extends ToolConfig {
_meta: { _meta: {
@ -65,11 +91,24 @@ export interface McpUiAppToolConfig extends ToolConfig {
} }
/** /**
* MCP App Resource configuration for `registerAppResource`. * MCP App Resource configuration for {@link registerAppResource}.
*
* Extends the base MCP SDK `ResourceMetadata` with optional UI metadata
* for configuring security policies and rendering preferences.
*
* @see {@link registerAppResource} for usage
*/ */
export interface McpUiAppResourceConfig extends ResourceMetadata { export interface McpUiAppResourceConfig extends ResourceMetadata {
/**
* Optional UI metadata for the resource.
* Used to configure security policies (CSP) and rendering preferences.
*/
_meta?: { _meta?: {
/**
* UI-specific metadata including CSP configuration and rendering preferences.
*/
ui?: McpUiResourceMeta; ui?: McpUiResourceMeta;
// Allow additional metadata properties for extensibility.
[key: string]: unknown; [key: string]: unknown;
}; };
} }
@ -77,14 +116,16 @@ export interface McpUiAppResourceConfig extends ResourceMetadata {
/** /**
* Register an app tool with the MCP server. * Register an app tool with the MCP server.
* *
* This is a convenience wrapper around `server.registerTool` that will allow more backwards-compatibility. * This is a convenience wrapper around `server.registerTool` that normalizes
* UI metadata: if `_meta.ui.resourceUri` is set, the legacy `_meta["ui/resourceUri"]`
* key is also populated (and vice versa) for compatibility with older hosts.
* *
* @param server - The MCP server instance * @param server - The MCP server instance
* @param name - Tool name/identifier * @param name - Tool name/identifier
* @param config - Tool configuration with required `ui` field * @param config - Tool configuration with `_meta` field containing UI metadata
* @param handler - Tool handler function * @param cb - Tool handler function
* *
* @example * @example Basic usage
* ```typescript * ```typescript
* import { registerAppTool } from '@modelcontextprotocol/ext-apps/server'; * import { registerAppTool } from '@modelcontextprotocol/ext-apps/server';
* import { z } from 'zod'; * import { z } from 'zod';
@ -94,13 +135,50 @@ export interface McpUiAppResourceConfig extends ResourceMetadata {
* description: "Get current weather for a location", * description: "Get current weather for a location",
* inputSchema: { location: z.string() }, * inputSchema: { location: z.string() },
* _meta: { * _meta: {
* [RESOURCE_URI_META_KEY]: "ui://weather/widget.html", * ui: { resourceUri: "ui://weather/widget.html" },
* }, * },
* }, async (args) => { * }, async (args) => {
* const weather = await fetchWeather(args.location); * const weather = await fetchWeather(args.location);
* return { content: [{ type: "text", text: JSON.stringify(weather) }] }; * return { content: [{ type: "text", text: JSON.stringify(weather) }] };
* }); * });
* ``` * ```
*
* @example Tool visibility - create app-only tools for UI actions
* ```typescript
* import { registerAppTool } from '@modelcontextprotocol/ext-apps/server';
* import { z } from 'zod';
*
* // Main tool - visible to both model and app (default)
* registerAppTool(server, "show-cart", {
* description: "Display the user's shopping cart",
* _meta: {
* ui: {
* resourceUri: "ui://shop/cart.html",
* visibility: ["model", "app"],
* },
* },
* }, async () => {
* const cart = await getCart();
* return { content: [{ type: "text", text: JSON.stringify(cart) }] };
* });
*
* // App-only tool - hidden from the model, only callable by the UI
* registerAppTool(server, "update-quantity", {
* description: "Update item quantity in cart",
* inputSchema: { itemId: z.string(), quantity: z.number() },
* _meta: {
* ui: {
* resourceUri: "ui://shop/cart.html",
* visibility: ["app"],
* },
* },
* }, async ({ itemId, quantity }) => {
* const cart = await updateCartItem(itemId, quantity);
* return { content: [{ type: "text", text: JSON.stringify(cart) }] };
* });
* ```
*
* @see {@link registerAppResource} to register the HTML resource referenced by the tool
*/ */
export function registerAppTool< export function registerAppTool<
OutputArgs extends ZodRawShapeCompat | AnySchema, OutputArgs extends ZodRawShapeCompat | AnySchema,
@ -137,22 +215,21 @@ export function registerAppTool<
* Register an app resource with the MCP server. * Register an app resource with the MCP server.
* *
* This is a convenience wrapper around `server.registerResource` that: * This is a convenience wrapper around `server.registerResource` that:
* - Defaults the MIME type to "text/html;profile=mcp-app" * - Defaults the MIME type to {@link RESOURCE_MIME_TYPE} (`"text/html;profile=mcp-app"`)
* - Provides a cleaner API matching the SDK's callback signature * - Provides a cleaner API matching the SDK's callback signature
* *
* @param server - The MCP server instance * @param server - The MCP server instance
* @param name - Human-readable resource name * @param name - Human-readable resource name
* @param uri - Resource URI (should match the `ui` field in tool config) * @param uri - Resource URI (should match the `_meta.ui` field in tool config)
* @param config - Resource configuration * @param config - Resource configuration
* @param readCallback - Callback that returns the resource contents * @param readCallback - Callback that returns the resource contents
* *
* @example * @example Basic usage
* ```typescript * ```typescript
* import { registerAppResource } from '@modelcontextprotocol/ext-apps/server'; * import { registerAppResource } from '@modelcontextprotocol/ext-apps/server';
* *
* registerAppResource(server, "Weather Widget", "ui://weather/widget.html", { * registerAppResource(server, "Weather Widget", "ui://weather/widget.html", {
* description: "Interactive weather display", * description: "Interactive weather display",
* mimeType: RESOURCE_MIME_TYPE,
* }, async () => ({ * }, async () => ({
* contents: [{ * contents: [{
* uri: "ui://weather/widget.html", * uri: "ui://weather/widget.html",
@ -161,6 +238,23 @@ export function registerAppTool<
* }], * }],
* })); * }));
* ``` * ```
*
* @example With CSP configuration for external domains
* ```typescript
* registerAppResource(server, "Music Player", "ui://music/player.html", {
* description: "Audio player with external soundfonts",
* _meta: {
* ui: {
* csp: {
* connectDomains: ["https://api.example.com"], // For fetch/WebSocket
* resourceDomains: ["https://cdn.example.com"], // For scripts/styles/images
* },
* },
* },
* }, readCallback);
* ```
*
* @see {@link registerAppTool} to register tools that reference this resource
*/ */
export function registerAppResource( export function registerAppResource(
server: Pick<McpServer, "registerResource">, server: Pick<McpServer, "registerResource">,

View file

@ -2,7 +2,7 @@
* MCP Apps Protocol Types (spec.types.ts) * MCP Apps Protocol Types (spec.types.ts)
* *
* This file contains pure TypeScript interface definitions for the MCP Apps protocol. * This file contains pure TypeScript interface definitions for the MCP Apps protocol.
* These types are the source of truth and are used to generate Zod schemas via ts-to-zod. * These types are the source of truth and are used to generate Zod schemas via `ts-to-zod`.
* *
* - Use `@description` JSDoc tags to generate `.describe()` calls on schemas * - Use `@description` JSDoc tags to generate `.describe()` calls on schemas
* - Run `npm run generate:schemas` to regenerate schemas from these types * - Run `npm run generate:schemas` to regenerate schemas from these types
@ -144,7 +144,7 @@ export type McpUiStyles = Record<McpUiStyleVariableKey, string | undefined>;
/** /**
* @description Request to open an external URL in the host's default browser. * @description Request to open an external URL in the host's default browser.
* @see {@link app.App.sendOpenLink} for the method that sends this request * @see {@link app!App.openLink} for the method that sends this request
*/ */
export interface McpUiOpenLinkRequest { export interface McpUiOpenLinkRequest {
method: "ui/open-link"; method: "ui/open-link";
@ -163,14 +163,14 @@ export interface McpUiOpenLinkResult {
isError?: boolean; isError?: boolean;
/** /**
* Index signature required for MCP SDK `Protocol` class compatibility. * Index signature required for MCP SDK `Protocol` class compatibility.
* Note: The schema intentionally omits this to enforce strict validation. * Note: The generated schema uses passthrough() to allow additional properties.
*/ */
[key: string]: unknown; [key: string]: unknown;
} }
/** /**
* @description Request to send a message to the host's chat interface. * @description Request to send a message to the host's chat interface.
* @see {@link app.App.sendMessage} for the method that sends this request * @see {@link app!App.sendMessage} for the method that sends this request
*/ */
export interface McpUiMessageRequest { export interface McpUiMessageRequest {
method: "ui/message"; method: "ui/message";
@ -191,7 +191,7 @@ export interface McpUiMessageResult {
isError?: boolean; isError?: boolean;
/** /**
* Index signature required for MCP SDK `Protocol` class compatibility. * Index signature required for MCP SDK `Protocol` class compatibility.
* Note: The schema intentionally omits this to enforce strict validation. * Note: The generated schema uses passthrough() to allow additional properties.
*/ */
[key: string]: unknown; [key: string]: unknown;
} }
@ -226,8 +226,8 @@ export interface McpUiSandboxResourceReadyNotification {
} }
/** /**
* @description Notification of UI size changes (bidirectional: Guest <-> Host). * @description Notification of UI size changes (Guest UI -> Host).
* @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI * @see {@link app!App.sendSizeChanged} for the method to send this from Guest UI
*/ */
export interface McpUiSizeChangedNotification { export interface McpUiSizeChangedNotification {
method: "ui/notifications/size-changed"; method: "ui/notifications/size-changed";
@ -287,7 +287,7 @@ export interface McpUiToolCancelledNotification {
* @description CSS blocks that can be injected by apps. * @description CSS blocks that can be injected by apps.
*/ */
export interface McpUiHostCss { export interface McpUiHostCss {
/** @description CSS for font loading (@font-face rules or @import statements). Apps must apply using applyHostFonts(). */ /** @description CSS for font loading (`@font-face` rules or `@import` statements). Apps must apply using {@link applyHostFonts}. */
fonts?: string; fonts?: string;
} }
@ -408,7 +408,7 @@ export interface McpUiUpdateModelContextRequest {
/** /**
* @description Request for graceful shutdown of the Guest UI (Host -> Guest UI). * @description Request for graceful shutdown of the Guest UI (Host -> Guest UI).
* @see {@link app-bridge.AppBridge.teardownResource} for the host method that sends this * @see {@link app-bridge!AppBridge.teardownResource} for the host method that sends this
*/ */
export interface McpUiResourceTeardownRequest { export interface McpUiResourceTeardownRequest {
method: "ui/resource-teardown"; method: "ui/resource-teardown";
@ -476,7 +476,7 @@ export interface McpUiHostCapabilities {
} }
/** /**
* @description Capabilities provided by the Guest UI (App). * @description Capabilities provided by the Guest UI ({@link app!App}).
* @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities * @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities
*/ */
export interface McpUiAppCapabilities { export interface McpUiAppCapabilities {
@ -491,7 +491,7 @@ export interface McpUiAppCapabilities {
/** /**
* @description Initialization request sent from Guest UI to Host. * @description Initialization request sent from Guest UI to Host.
* @see {@link app.App.connect} for the method that sends this request * @see {@link app!App.connect} for the method that sends this request
*/ */
export interface McpUiInitializeRequest { export interface McpUiInitializeRequest {
method: "ui/initialize"; method: "ui/initialize";
@ -520,14 +520,14 @@ export interface McpUiInitializeResult {
hostContext: McpUiHostContext; hostContext: McpUiHostContext;
/** /**
* Index signature required for MCP SDK `Protocol` class compatibility. * Index signature required for MCP SDK `Protocol` class compatibility.
* Note: The schema intentionally omits this to enforce strict validation. * Note: The generated schema uses passthrough() to allow additional properties.
*/ */
[key: string]: unknown; [key: string]: unknown;
} }
/** /**
* @description Notification that Guest UI has completed initialization (Guest UI -> Host). * @description Notification that Guest UI has completed initialization (Guest UI -> Host).
* @see {@link app.App.connect} for the method that sends this notification * @see {@link app!App.connect} for the method that sends this notification
*/ */
export interface McpUiInitializedNotification { export interface McpUiInitializedNotification {
method: "ui/notifications/initialized"; method: "ui/notifications/initialized";
@ -582,7 +582,7 @@ export interface McpUiResourceMeta {
* @description Request to change the display mode of the UI. * @description Request to change the display mode of the UI.
* The host will respond with the actual display mode that was set, * The host will respond with the actual display mode that was set,
* which may differ from the requested mode if not supported. * which may differ from the requested mode if not supported.
* @see {@link app.App.requestDisplayMode} for the method that sends this request * @see {@link app!App.requestDisplayMode} for the method that sends this request
*/ */
export interface McpUiRequestDisplayModeRequest { export interface McpUiRequestDisplayModeRequest {
method: "ui/request-display-mode"; method: "ui/request-display-mode";
@ -601,7 +601,7 @@ export interface McpUiRequestDisplayModeResult {
mode: McpUiDisplayMode; mode: McpUiDisplayMode;
/** /**
* Index signature required for MCP SDK `Protocol` class compatibility. * Index signature required for MCP SDK `Protocol` class compatibility.
* Note: The schema intentionally omits this to enforce strict validation. * Note: The generated schema uses passthrough() to allow additional properties.
*/ */
[key: string]: unknown; [key: string]: unknown;
} }

View file

@ -76,12 +76,12 @@ export function applyDocumentTheme(theme: McpUiTheme): void {
/** /**
* Apply host style variables as CSS custom properties on an element. * Apply host style variables as CSS custom properties on an element.
* *
* This function takes the `variables` object from `McpUiHostContext.styles` and sets * This function takes the `variables` object from {@link McpUiHostContext.styles} and sets
* each CSS variable on the specified root element (defaults to `document.documentElement`). * each CSS variable on the specified root element (defaults to `document.documentElement`).
* This allows apps to use the host's theming values via CSS variables like * This allows apps to use the host's theming values via CSS variables like
* `var(--color-background-primary)`. * `var(--color-background-primary)`.
* *
* @param styles - The styles object from `McpUiHostContext.styles.variables` * @param styles - The style variables object from `McpUiHostContext.styles.variables`
* @param root - The element to apply styles to (defaults to `document.documentElement`) * @param root - The element to apply styles to (defaults to `document.documentElement`)
* *
* @example Apply style variables from host context * @example Apply style variables from host context
@ -123,10 +123,10 @@ export function applyHostStyleVariables(
* self-hosted fonts, `@import` statements for Google Fonts or other font services, * self-hosted fonts, `@import` statements for Google Fonts or other font services,
* or a combination of both. * or a combination of both.
* *
* The styles are only injected once. Subsequent calls will not create duplicate * The styles are only injected once. Subsequent calls are no-ops and will not
* style tags. * create duplicate style tags.
* *
* @param fontCss - CSS string containing @font-face rules and/or @import statements * @param fontCss - CSS string containing `@font-face` rules and/or `@import` statements
* *
* @example Apply fonts from host context * @example Apply fonts from host context
* ```typescript * ```typescript

View file

@ -1,12 +1,12 @@
/** /**
* MCP Apps Protocol Types and Schemas * MCP Apps Protocol Types and Schemas
* *
* This file re-exports types from spec.types.ts and schemas from generated/schema.ts. * This file re-exports types from `spec.types.ts` and schemas from `generated/schema.ts`.
* Compile-time verification is handled by generated/schema.test.ts. * Compile-time verification is handled by `generated/schema.test.ts`.
* *
* @see spec.types.ts for the source of truth TypeScript interfaces * @see `spec.types.ts` for the source of truth TypeScript interfaces
* @see generated/schema.ts for auto-generated Zod schemas * @see `generated/schema.ts` for auto-generated Zod schemas
* @see generated/schema.test.ts for compile-time verification * @see `generated/schema.test.ts` for compile-time verification
*/ */
// Re-export all types from spec.types.ts // Re-export all types from spec.types.ts
@ -151,7 +151,8 @@ import {
* *
* Includes: * Includes:
* - MCP UI requests (initialize, open-link, message, resource-teardown, request-display-mode) * - MCP UI requests (initialize, open-link, message, resource-teardown, request-display-mode)
* - MCP server requests forwarded from the app (tools/call, resources/*, prompts/list) * - MCP server requests forwarded from the app (tools/call, tools/list, resources/list,
* resources/templates/list, resources/read, prompts/list)
* - Protocol requests (ping) * - Protocol requests (ping)
*/ */
export type AppRequest = export type AppRequest =

30
typedoc.config.mjs Normal file
View file

@ -0,0 +1,30 @@
import { OptionDefaults } from "typedoc";
/** @type {Partial<import('typedoc').TypeDocOptions>} */
const config = {
blockTags: [...OptionDefaults.blockTags, "@description"],
intentionallyNotExported: ["AppOptions"],
projectDocuments: ["docs/quickstart.md"],
entryPoints: [
"src/server/index.ts",
"src/app.ts",
"src/react/index.tsx",
"src/app-bridge.ts",
"src/message-transport.ts",
"src/types.ts",
],
out: "docs/api",
gitRevision: "main",
excludePrivate: true,
excludeInternal: false,
categorizeByGroup: true,
navigationLinks: {
GitHub: "https://github.com/modelcontextprotocol/ext-apps",
Specification:
"https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx",
},
readme: "README.md",
includeVersion: true,
};
export default config;

View file

@ -1,22 +0,0 @@
{
"$schema": "https://typedoc.org/schema.json",
"projectDocuments": ["docs/quickstart.md"],
"entryPoints": [
"src/app.ts",
"src/app-bridge.ts",
"src/types.ts",
"src/message-transport.ts",
"src/react/index.tsx"
],
"out": "docs/api",
"gitRevision": "main",
"excludePrivate": true,
"excludeInternal": false,
"categorizeByGroup": true,
"navigationLinks": {
"GitHub": "https://github.com/modelcontextprotocol/ext-apps",
"Specification": "https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx"
},
"readme": "README.md",
"includeVersion": true
}