Safe area insets apply on web as well, not just mobile devices. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
860 lines
26 KiB
TypeScript
860 lines
26 KiB
TypeScript
import {
|
|
CallToolResult,
|
|
CallToolResultSchema,
|
|
ContentBlock,
|
|
ContentBlockSchema,
|
|
EmptyResultSchema,
|
|
Implementation,
|
|
ImplementationSchema,
|
|
RequestId,
|
|
RequestIdSchema,
|
|
RequestSchema,
|
|
Tool,
|
|
ToolSchema,
|
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
import { z } from "zod/v4";
|
|
|
|
/**
|
|
* Type-level assertion that validates a Zod schema produces the expected interface.
|
|
*
|
|
* This helper is used for request and notification schemas that cannot use
|
|
* `z.ZodType<Interface>` type annotations. Adding `: z.ZodType<Interface>` to
|
|
* schemas widens the type from the specific `ZodObject` to the generic `ZodType`,
|
|
* which breaks MCP SDK's `setRequestHandler()` and `setNotificationHandler()`
|
|
* methods that require the specific `ZodObject` type.
|
|
*
|
|
* By using this type-level assertion instead, we get compile-time validation that
|
|
* the schema matches the interface without affecting the runtime schema type.
|
|
*
|
|
* @internal
|
|
*/
|
|
type VerifySchemaMatches<TSchema extends z.ZodTypeAny, TInterface> =
|
|
z.infer<TSchema> extends TInterface
|
|
? TInterface extends z.infer<TSchema>
|
|
? true
|
|
: never
|
|
: never;
|
|
|
|
/**
|
|
* Current protocol version supported by this SDK.
|
|
*
|
|
* The SDK automatically handles version negotiation during initialization.
|
|
* Apps and hosts don't need to manage protocol versions manually.
|
|
*/
|
|
export const LATEST_PROTOCOL_VERSION = "2025-11-21";
|
|
|
|
/**
|
|
* Request to open an external URL in the host's default browser.
|
|
*
|
|
* Sent from the Guest UI to the Host when requesting to open an external link.
|
|
* The host may deny the request based on user preferences or security policy.
|
|
*
|
|
* @see {@link app.App.sendOpenLink} for the method that sends this request
|
|
*/
|
|
export interface McpUiOpenLinkRequest {
|
|
method: "ui/open-link";
|
|
params: {
|
|
/** URL to open in the host's browser */
|
|
url: string;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiOpenLinkRequest}.
|
|
* @internal
|
|
*/
|
|
export const McpUiOpenLinkRequestSchema = RequestSchema.extend({
|
|
method: z.literal("ui/open-link"),
|
|
params: z.object({
|
|
url: z.string().url(),
|
|
}),
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifyOpenLinkRequest = VerifySchemaMatches<
|
|
typeof McpUiOpenLinkRequestSchema,
|
|
McpUiOpenLinkRequest
|
|
>;
|
|
|
|
/**
|
|
* Result from a {@link McpUiOpenLinkRequest}.
|
|
*
|
|
* The host returns this result after attempting to open the requested URL.
|
|
*
|
|
* @see {@link McpUiOpenLinkRequest}
|
|
*/
|
|
export interface McpUiOpenLinkResult {
|
|
/**
|
|
* True if the host failed to open the URL (e.g., due to security policy,
|
|
* user cancellation, or system error). False or undefined indicates success.
|
|
*/
|
|
isError?: boolean;
|
|
/**
|
|
* Index signature required for MCP SDK `Protocol` class compatibility.
|
|
* Note: The schema intentionally omits this to enforce strict validation.
|
|
*/
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiOpenLinkResult}.
|
|
* @internal
|
|
*/
|
|
export const McpUiOpenLinkResultSchema: z.ZodType<McpUiOpenLinkResult> =
|
|
z.object({
|
|
isError: z.boolean().optional(),
|
|
});
|
|
|
|
/**
|
|
* Request to send a message to the host's chat interface.
|
|
*
|
|
* Sent from the Guest UI to the Host when the app wants to add a message to the
|
|
* conversation thread. This enables interactive apps to communicate with the user
|
|
* through the host's chat interface.
|
|
*
|
|
* @see {@link app.App.sendMessage} for the method that sends this request
|
|
*/
|
|
export interface McpUiMessageRequest {
|
|
method: "ui/message";
|
|
params: {
|
|
/** Message role, currently only "user" is supported */
|
|
role: "user";
|
|
/** Message content blocks (text, image, etc.) */
|
|
content: ContentBlock[];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiMessageRequest}.
|
|
* @internal
|
|
*/
|
|
export const McpUiMessageRequestSchema = RequestSchema.extend({
|
|
method: z.literal("ui/message"),
|
|
params: z.object({
|
|
role: z.literal("user"),
|
|
content: z.array(ContentBlockSchema),
|
|
}),
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifyMessageRequest = VerifySchemaMatches<
|
|
typeof McpUiMessageRequestSchema,
|
|
McpUiMessageRequest
|
|
>;
|
|
|
|
/**
|
|
* Result from a {@link McpUiMessageRequest}.
|
|
*
|
|
* Note: The host does not return message content or follow-up results to prevent
|
|
* leaking information from the conversation. Only error status is provided.
|
|
*
|
|
* @see {@link McpUiMessageRequest}
|
|
*/
|
|
export interface McpUiMessageResult {
|
|
/**
|
|
* True if the host rejected or failed to deliver the message (e.g., due to
|
|
* rate limiting, content policy, or system error). False or undefined
|
|
* indicates the message was accepted.
|
|
*/
|
|
isError?: boolean;
|
|
/**
|
|
* Index signature required for MCP SDK `Protocol` class compatibility.
|
|
* Note: The schema intentionally omits this to enforce strict validation.
|
|
*/
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiMessageResult}.
|
|
* @internal
|
|
*/
|
|
export const McpUiMessageResultSchema: z.ZodType<McpUiMessageResult> = z.object(
|
|
{
|
|
isError: z.boolean().optional(),
|
|
},
|
|
);
|
|
|
|
// McpUiIframeReadyNotification removed - replaced by standard MCP initialization
|
|
// The SDK's oninitialized callback now handles the ready signal
|
|
|
|
/**
|
|
* Notification that the sandbox proxy iframe is ready to receive content.
|
|
*
|
|
* This is an internal message used by web-based hosts implementing the
|
|
* double-iframe sandbox architecture. The sandbox proxy sends this to the host
|
|
* after it loads and is ready to receive HTML content via
|
|
* {@link McpUiSandboxResourceReadyNotification}.
|
|
*
|
|
* @internal
|
|
* @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy
|
|
*/
|
|
export interface McpUiSandboxProxyReadyNotification {
|
|
method: "ui/notifications/sandbox-proxy-ready";
|
|
params: {};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiSandboxProxyReadyNotification}.
|
|
* @internal
|
|
*/
|
|
export const McpUiSandboxProxyReadyNotificationSchema = z.object({
|
|
method: z.literal("ui/notifications/sandbox-proxy-ready"),
|
|
params: z.object({}),
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifySandboxProxyReadyNotification = VerifySchemaMatches<
|
|
typeof McpUiSandboxProxyReadyNotificationSchema,
|
|
McpUiSandboxProxyReadyNotification
|
|
>;
|
|
|
|
/**
|
|
* Notification containing HTML resource for the sandbox proxy to load.
|
|
*
|
|
* This is an internal message used by web-based hosts implementing the
|
|
* double-iframe sandbox architecture. After the sandbox proxy signals readiness,
|
|
* the host sends this notification with the HTML content and optional sandbox
|
|
* attributes to load into the inner iframe.
|
|
*
|
|
* @internal
|
|
* @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy
|
|
*/
|
|
export interface McpUiSandboxResourceReadyNotification {
|
|
method: "ui/notifications/sandbox-resource-ready";
|
|
params: {
|
|
/** HTML content to load into the inner iframe */
|
|
html: string;
|
|
/** Optional override for the inner iframe's sandbox attribute */
|
|
sandbox?: string;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiSandboxResourceReadyNotification}.
|
|
* @internal
|
|
*/
|
|
export const McpUiSandboxResourceReadyNotificationSchema = z.object({
|
|
method: z.literal("ui/notifications/sandbox-resource-ready"),
|
|
params: z.object({
|
|
html: z.string(),
|
|
sandbox: z.string().optional(),
|
|
}),
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifySandboxResourceReadyNotification = VerifySchemaMatches<
|
|
typeof McpUiSandboxResourceReadyNotificationSchema,
|
|
McpUiSandboxResourceReadyNotification
|
|
>;
|
|
|
|
/**
|
|
* Notification of UI size changes (bidirectional: Guest ↔ Host).
|
|
*
|
|
* **Guest UI → Host**: Sent by the Guest UI when its rendered content size changes,
|
|
* typically using ResizeObserver. This helps the host adjust the iframe container.
|
|
* If {@link app.App} is configured with `autoResize: true` (default), this is sent
|
|
* automatically.
|
|
*
|
|
* **Host → Guest UI**: Sent by the Host when the viewport size changes (e.g.,
|
|
* window resize, orientation change). This allows the Guest UI to adjust its layout.
|
|
*
|
|
* @see {@link app.App.sendSizeChange} for the method to send this from Guest UI
|
|
* @see {@link app.App.setupSizeChangeNotifications} for automatic size reporting
|
|
*/
|
|
export interface McpUiSizeChangeNotification {
|
|
method: "ui/notifications/size-change";
|
|
params: {
|
|
/** New width in pixels */
|
|
width?: number;
|
|
/** New height in pixels */
|
|
height?: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiSizeChangeNotification}.
|
|
* @internal
|
|
*/
|
|
export const McpUiSizeChangeNotificationSchema = z.object({
|
|
method: z.literal("ui/notifications/size-change"),
|
|
params: z.object({
|
|
width: z.number().optional(),
|
|
height: z.number().optional(),
|
|
}),
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifySizeChangeNotification = VerifySchemaMatches<
|
|
typeof McpUiSizeChangeNotificationSchema,
|
|
McpUiSizeChangeNotification
|
|
>;
|
|
|
|
/**
|
|
* Notification containing complete tool arguments (Host → Guest UI).
|
|
*
|
|
* The host MUST send this notification after the Guest UI's initialize request
|
|
* completes, when complete tool arguments become available. This notification is
|
|
* sent exactly once and is required before {@link McpUiToolResultNotification}.
|
|
*
|
|
* The arguments object contains the complete tool call parameters that triggered
|
|
* this App instance.
|
|
*/
|
|
export interface McpUiToolInputNotification {
|
|
method: "ui/notifications/tool-input";
|
|
params: {
|
|
/** Complete tool call arguments as key-value pairs */
|
|
arguments?: Record<string, unknown>;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiToolInputNotification}.
|
|
* @internal
|
|
*/
|
|
export const McpUiToolInputNotificationSchema = z.object({
|
|
method: z.literal("ui/notifications/tool-input"),
|
|
params: z.object({
|
|
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
}),
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifyToolInputNotification = VerifySchemaMatches<
|
|
typeof McpUiToolInputNotificationSchema,
|
|
McpUiToolInputNotification
|
|
>;
|
|
|
|
/**
|
|
* Notification containing partial/streaming tool arguments (Host → Guest UI).
|
|
*
|
|
* The host MAY send this notification zero or more times while the agent is
|
|
* streaming tool arguments, before {@link McpUiToolInputNotification} is sent
|
|
* with complete arguments.
|
|
*
|
|
* The arguments object represents best-effort recovery of incomplete JSON, with
|
|
* unclosed structures automatically closed to produce valid JSON. Guest UIs may
|
|
* ignore these notifications or use them to render progressive loading states.
|
|
*
|
|
* Guest UIs MUST NOT rely on partial arguments for critical operations and SHOULD
|
|
* gracefully handle missing or changing fields between notifications.
|
|
*/
|
|
export interface McpUiToolInputPartialNotification {
|
|
method: "ui/notifications/tool-input-partial";
|
|
params: {
|
|
/** Partial tool call arguments (incomplete, may change) */
|
|
arguments?: Record<string, unknown>;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiToolInputPartialNotification}.
|
|
* @internal
|
|
*/
|
|
export const McpUiToolInputPartialNotificationSchema = z.object({
|
|
method: z.literal("ui/notifications/tool-input-partial"),
|
|
params: z.object({
|
|
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
}),
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifyToolInputPartialNotification = VerifySchemaMatches<
|
|
typeof McpUiToolInputPartialNotificationSchema,
|
|
McpUiToolInputPartialNotification
|
|
>;
|
|
|
|
/**
|
|
* Notification containing tool execution result (Host → Guest UI).
|
|
*
|
|
* The host MUST send this notification when tool execution completes successfully,
|
|
* provided the UI is still displayed. If the UI was closed before execution
|
|
* completes, the host MAY skip this notification. This notification is sent after
|
|
* {@link McpUiToolInputNotification}.
|
|
*
|
|
* The result follows the standard MCP CallToolResult format, containing content
|
|
* for the model and optionally structuredContent optimized for UI rendering.
|
|
*/
|
|
export interface McpUiToolResultNotification {
|
|
method: "ui/notifications/tool-result";
|
|
/** Standard MCP tool execution result */
|
|
params: CallToolResult;
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiToolResultNotification}.
|
|
* @internal
|
|
*/
|
|
export const McpUiToolResultNotificationSchema = z.object({
|
|
method: z.literal("ui/notifications/tool-result"),
|
|
params: CallToolResultSchema,
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifyToolResultNotification = VerifySchemaMatches<
|
|
typeof McpUiToolResultNotificationSchema,
|
|
McpUiToolResultNotification
|
|
>;
|
|
|
|
/**
|
|
* Rich context about the host environment provided to Guest UIs.
|
|
*
|
|
* Hosts provide this context in the {@link McpUiInitializeResult} response and send
|
|
* updates via {@link McpUiHostContextChangedNotification} when values change.
|
|
* All fields are optional and Guest UIs should handle missing fields gracefully.
|
|
*
|
|
* @example
|
|
* ```typescript
|
|
* // Received during initialization
|
|
* const result = await app.connect(transport);
|
|
* const context = result.hostContext;
|
|
*
|
|
* if (context.theme === "dark") {
|
|
* document.body.classList.add("dark-mode");
|
|
* }
|
|
* ```
|
|
*/
|
|
export interface McpUiHostContext {
|
|
/** Metadata of the tool call that instantiated this App */
|
|
toolInfo?: {
|
|
/** JSON-RPC id of the tools/call request */
|
|
id: RequestId;
|
|
/** Tool definition including name, inputSchema, etc. */
|
|
tool: Tool;
|
|
};
|
|
/**
|
|
* Current color theme preference.
|
|
* @example "dark"
|
|
*/
|
|
theme?: "light" | "dark" | "system";
|
|
/**
|
|
* How the UI is currently displayed.
|
|
* @example "inline"
|
|
*/
|
|
displayMode?: "inline" | "fullscreen" | "pip";
|
|
/**
|
|
* Display modes the host supports.
|
|
* Apps can use this to offer mode-switching UI if applicable.
|
|
*/
|
|
availableDisplayModes?: string[];
|
|
/** Current and maximum dimensions available to the UI */
|
|
viewport?: {
|
|
/** Current viewport width in pixels */
|
|
width: number;
|
|
/** Current viewport height in pixels */
|
|
height: number;
|
|
/** Maximum available height in pixels (if constrained) */
|
|
maxHeight?: number;
|
|
/** Maximum available width in pixels (if constrained) */
|
|
maxWidth?: number;
|
|
};
|
|
/**
|
|
* User's language and region preference in BCP 47 format.
|
|
* @example "en-US", "fr-CA", "ja-JP"
|
|
*/
|
|
locale?: string;
|
|
/**
|
|
* User's timezone in IANA format.
|
|
* @example "America/New_York", "Europe/London", "Asia/Tokyo"
|
|
*/
|
|
timeZone?: string;
|
|
/**
|
|
* Host application identifier.
|
|
* @example "claude-desktop/1.0.0"
|
|
*/
|
|
userAgent?: string;
|
|
/**
|
|
* Platform type for responsive design decisions.
|
|
* @example "desktop"
|
|
*/
|
|
platform?: "web" | "desktop" | "mobile";
|
|
/** Device input capabilities */
|
|
deviceCapabilities?: {
|
|
/** Whether the device supports touch input */
|
|
touch?: boolean;
|
|
/** Whether the device supports hover interactions */
|
|
hover?: boolean;
|
|
};
|
|
/**
|
|
* Safe area boundaries in pixels.
|
|
* Used to avoid notches, rounded corners, and system UI.
|
|
*/
|
|
safeAreaInsets?: {
|
|
/** Top safe area inset in pixels */
|
|
top: number;
|
|
/** Right safe area inset in pixels */
|
|
right: number;
|
|
/** Bottom safe area inset in pixels */
|
|
bottom: number;
|
|
/** Left safe area inset in pixels */
|
|
left: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiHostContext}.
|
|
* @internal
|
|
*/
|
|
export const McpUiHostContextSchema: z.ZodType<McpUiHostContext> = z.object({
|
|
toolInfo: z
|
|
.object({
|
|
id: RequestIdSchema,
|
|
tool: ToolSchema,
|
|
})
|
|
.optional(),
|
|
theme: z.enum(["light", "dark"]).optional(),
|
|
displayMode: z.enum(["inline", "fullscreen", "pip"]).optional(),
|
|
availableDisplayModes: z.array(z.string()).optional(),
|
|
viewport: z
|
|
.object({
|
|
width: z.number(),
|
|
height: z.number(),
|
|
maxHeight: z.number().optional(),
|
|
maxWidth: z.number().optional(),
|
|
})
|
|
.optional(),
|
|
locale: z.string().optional(),
|
|
timeZone: z.string().optional(),
|
|
userAgent: z.string().optional(),
|
|
platform: z.enum(["web", "desktop", "mobile"]).optional(),
|
|
deviceCapabilities: z
|
|
.object({
|
|
touch: z.boolean().optional(),
|
|
hover: z.boolean().optional(),
|
|
})
|
|
.optional(),
|
|
safeAreaInsets: z
|
|
.object({
|
|
top: z.number(),
|
|
right: z.number(),
|
|
bottom: z.number(),
|
|
left: z.number(),
|
|
})
|
|
.optional(),
|
|
});
|
|
|
|
/**
|
|
* Notification that host context has changed (Host → Guest UI).
|
|
*
|
|
* The host MAY send this notification when any context field changes, such as:
|
|
* - Theme toggled (light/dark)
|
|
* - Display mode changed (inline/fullscreen)
|
|
* - Device orientation changed
|
|
* - Window/panel resized
|
|
*
|
|
* This notification contains partial updates. Guest UIs SHOULD merge received
|
|
* fields with their current context state rather than replacing it entirely.
|
|
*
|
|
* @see {@link McpUiHostContext} for the full context structure
|
|
*/
|
|
export interface McpUiHostContextChangedNotification {
|
|
method: "ui/notifications/host-context-changed";
|
|
/** Partial context update containing only changed fields */
|
|
params: McpUiHostContext;
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiHostContextChangedNotification}.
|
|
* @internal
|
|
*/
|
|
export const McpUiHostContextChangedNotificationSchema = z.object({
|
|
method: z.literal("ui/notifications/host-context-changed"),
|
|
params: McpUiHostContextSchema,
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifyHostContextChangedNotification = VerifySchemaMatches<
|
|
typeof McpUiHostContextChangedNotificationSchema,
|
|
McpUiHostContextChangedNotification
|
|
>;
|
|
|
|
/**
|
|
* Request for graceful shutdown of the Guest UI (Host → Guest UI).
|
|
*
|
|
* The host MUST send this request before tearing down the UI resource, for any
|
|
* reason including user action, resource reallocation, or app closure. This gives
|
|
* the Guest UI an opportunity to save state, cancel pending operations, or show
|
|
* confirmation dialogs.
|
|
*
|
|
* The host SHOULD wait for the response before unmounting the iframe to prevent
|
|
* data loss.
|
|
*
|
|
* @see {@link app-bridge.AppBridge.sendResourceTeardown} for the host method that sends this
|
|
*/
|
|
export interface McpUiResourceTeardownRequest {
|
|
method: "ui/resource-teardown";
|
|
params: {};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiResourceTeardownRequest}.
|
|
* @internal
|
|
*/
|
|
export const McpUiResourceTeardownRequestSchema = RequestSchema.extend({
|
|
method: z.literal("ui/resource-teardown"),
|
|
params: z.object({}),
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifyResourceTeardownRequest = VerifySchemaMatches<
|
|
typeof McpUiResourceTeardownRequestSchema,
|
|
McpUiResourceTeardownRequest
|
|
>;
|
|
|
|
/**
|
|
* Result from graceful shutdown request.
|
|
*
|
|
* Empty result indicates the Guest UI has completed cleanup and is ready to be
|
|
* torn down.
|
|
*
|
|
* @see {@link McpUiResourceTeardownRequest}
|
|
*/
|
|
export interface McpUiResourceTeardownResult {}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiResourceTeardownResult}.
|
|
* @internal
|
|
*/
|
|
export const McpUiResourceTeardownResultSchema: z.ZodType<McpUiResourceTeardownResult> =
|
|
EmptyResultSchema;
|
|
|
|
/**
|
|
* Capabilities supported by the host application.
|
|
*
|
|
* Hosts declare these capabilities during the initialization handshake. Guest UIs
|
|
* can check capabilities before attempting to use specific features.
|
|
*
|
|
* @example Check if host supports opening links
|
|
* ```typescript
|
|
* const result = await app.connect(transport);
|
|
* if (result.hostCapabilities.openLinks) {
|
|
* await app.sendOpenLink({ url: "https://example.com" });
|
|
* }
|
|
* ```
|
|
*
|
|
* @see {@link McpUiInitializeResult} for the initialization result that includes these capabilities
|
|
*/
|
|
export interface McpUiHostCapabilities {
|
|
/** Experimental features (structure TBD) */
|
|
experimental?: {};
|
|
/** Host supports opening external URLs via {@link app.App.sendOpenLink} */
|
|
openLinks?: {};
|
|
/** Host can proxy tool calls to the MCP server */
|
|
serverTools?: {
|
|
/** Host supports tools/list_changed notifications */
|
|
listChanged?: boolean;
|
|
};
|
|
/** Host can proxy resource reads to the MCP server */
|
|
serverResources?: {
|
|
/** Host supports resources/list_changed notifications */
|
|
listChanged?: boolean;
|
|
};
|
|
/** Host accepts log messages via {@link app.App.sendLog} */
|
|
logging?: {};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiHostCapabilities}.
|
|
* @internal
|
|
*/
|
|
export const McpUiHostCapabilitiesSchema: z.ZodType<McpUiHostCapabilities> =
|
|
z.object({
|
|
experimental: z.object({}).optional(),
|
|
openLinks: z.object({}).optional(),
|
|
serverTools: z
|
|
.object({
|
|
listChanged: z.boolean().optional(),
|
|
})
|
|
.optional(),
|
|
serverResources: z
|
|
.object({
|
|
listChanged: z.boolean().optional(),
|
|
})
|
|
.optional(),
|
|
logging: z.object({}).optional(),
|
|
});
|
|
|
|
/**
|
|
* Capabilities provided by the Guest UI (App).
|
|
*
|
|
* Apps declare these capabilities during the initialization handshake to indicate
|
|
* what features they provide to the host.
|
|
*
|
|
* @example Declare tool capabilities
|
|
* ```typescript
|
|
* const app = new App(
|
|
* { name: "MyApp", version: "1.0.0" },
|
|
* { tools: { listChanged: true } }
|
|
* );
|
|
* ```
|
|
*
|
|
* @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities
|
|
*/
|
|
export interface McpUiAppCapabilities {
|
|
/** Experimental features (structure TBD) */
|
|
experimental?: {};
|
|
/**
|
|
* App exposes MCP-style tools that the host can call.
|
|
* These are app-specific tools, not proxied from the server.
|
|
*/
|
|
tools?: {
|
|
/** App supports tools/list_changed notifications */
|
|
listChanged?: boolean;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiAppCapabilities}.
|
|
* @internal
|
|
*/
|
|
export const McpUiAppCapabilitiesSchema: z.ZodType<McpUiAppCapabilities> =
|
|
z.object({
|
|
experimental: z.object({}).optional(),
|
|
tools: z
|
|
.object({
|
|
listChanged: z.boolean().optional(),
|
|
})
|
|
.optional(),
|
|
});
|
|
|
|
/**
|
|
* Initialization request sent from Guest UI to Host.
|
|
*
|
|
* This is the first message sent by the Guest UI after loading. The host responds
|
|
* with {@link McpUiInitializeResult} containing host capabilities and context.
|
|
* After receiving the response, the Guest UI MUST send
|
|
* {@link McpUiInitializedNotification}.
|
|
*
|
|
* This replaces the custom iframe-ready pattern used in pre-SEP MCP-UI.
|
|
*
|
|
* @see {@link app.App.connect} for the method that sends this request
|
|
*/
|
|
export interface McpUiInitializeRequest {
|
|
method: "ui/initialize";
|
|
params: {
|
|
/** App identification (name and version) */
|
|
appInfo: Implementation;
|
|
/** Features and capabilities this app provides */
|
|
appCapabilities: McpUiAppCapabilities;
|
|
/** Protocol version this app supports */
|
|
protocolVersion: string;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiInitializeRequest}.
|
|
* @internal
|
|
*/
|
|
export const McpUiInitializeRequestSchema = RequestSchema.extend({
|
|
method: z.literal("ui/initialize"),
|
|
params: z.object({
|
|
appInfo: ImplementationSchema,
|
|
appCapabilities: McpUiAppCapabilitiesSchema,
|
|
protocolVersion: z.string(),
|
|
}),
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifyInitializeRequest = VerifySchemaMatches<
|
|
typeof McpUiInitializeRequestSchema,
|
|
McpUiInitializeRequest
|
|
>;
|
|
|
|
/**
|
|
* Initialization result returned from Host to Guest UI.
|
|
*
|
|
* Contains the negotiated protocol version, host information, capabilities,
|
|
* and rich context about the host environment.
|
|
*
|
|
* @see {@link McpUiInitializeRequest}
|
|
*/
|
|
export interface McpUiInitializeResult {
|
|
/** Negotiated protocol version string (e.g., "2025-11-21") */
|
|
protocolVersion: string;
|
|
/** Host application identification and version */
|
|
hostInfo: Implementation;
|
|
/** Features and capabilities provided by the host */
|
|
hostCapabilities: McpUiHostCapabilities;
|
|
/** Rich context about the host environment */
|
|
hostContext: McpUiHostContext;
|
|
/**
|
|
* Index signature required for MCP SDK `Protocol` class compatibility.
|
|
* Note: The schema intentionally omits this to enforce strict validation.
|
|
*/
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiInitializeResult}.
|
|
* @internal
|
|
*/
|
|
export const McpUiInitializeResultSchema: z.ZodType<McpUiInitializeResult> =
|
|
z.object({
|
|
protocolVersion: z.string(),
|
|
hostInfo: ImplementationSchema,
|
|
hostCapabilities: McpUiHostCapabilitiesSchema,
|
|
hostContext: McpUiHostContextSchema,
|
|
});
|
|
|
|
/**
|
|
* Notification that Guest UI has completed initialization (Guest UI → Host).
|
|
*
|
|
* The Guest UI MUST send this notification after receiving
|
|
* {@link McpUiInitializeResult} and completing any setup. The host waits for this
|
|
* notification before sending tool input and other data to the Guest UI.
|
|
*
|
|
* @see {@link app.App.connect} for the method that sends this notification
|
|
*/
|
|
export interface McpUiInitializedNotification {
|
|
method: "ui/notifications/initialized";
|
|
params?: {};
|
|
}
|
|
|
|
/**
|
|
* Runtime validation schema for {@link McpUiInitializedNotification}.
|
|
* @internal
|
|
*/
|
|
export const McpUiInitializedNotificationSchema = z.object({
|
|
method: z.literal("ui/notifications/initialized"),
|
|
params: z.object({}).optional(),
|
|
});
|
|
|
|
/** @internal - Compile-time verification that schema matches interface */
|
|
type _VerifyInitializedNotification = VerifySchemaMatches<
|
|
typeof McpUiInitializedNotificationSchema,
|
|
McpUiInitializedNotification
|
|
>;
|
|
|
|
// =============================================================================
|
|
// UI Resource Metadata Types
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Content Security Policy configuration for UI resources.
|
|
*
|
|
* Servers declare which external origins their UI needs to access.
|
|
* Hosts use this to enforce appropriate CSP headers.
|
|
*/
|
|
export const McpUiResourceCspSchema = z.object({
|
|
/** Origins for network requests (fetch/XHR/WebSocket). Maps to CSP connect-src */
|
|
connectDomains: z.array(z.string()).optional(),
|
|
/** Origins for static resources (images, scripts, stylesheets, fonts). Maps to CSP img-src, script-src, style-src, font-src */
|
|
resourceDomains: z.array(z.string()).optional(),
|
|
});
|
|
export type McpUiResourceCsp = z.infer<typeof McpUiResourceCspSchema>;
|
|
|
|
/**
|
|
* UI Resource metadata for security and rendering configuration.
|
|
*
|
|
* Included in the `_meta.ui` field of UI resource content returned via `resources/read`.
|
|
*
|
|
* @see {@link McpUiResourceCspSchema} for CSP configuration
|
|
*/
|
|
export const McpUiResourceMetaSchema = z.object({
|
|
/** Content Security Policy configuration */
|
|
csp: McpUiResourceCspSchema.optional(),
|
|
/** Dedicated origin for widget sandbox */
|
|
domain: z.string().optional(),
|
|
/** Visual boundary preference - true if UI prefers a visible border */
|
|
prefersBorder: z.boolean().optional(),
|
|
});
|
|
export type McpUiResourceMeta = z.infer<typeof McpUiResourceMetaSchema>;
|