* feat: add ts-to-zod schema generation from spec.types.ts Add automated Zod schema generation using ts-to-zod: - New npm script `generate:schemas` to regenerate schemas from spec.types.ts - Post-processing script for Zod v4 compatibility and MCP SDK type imports - src/spec.types.ts: Pure TypeScript interface definitions (source of truth) - src/schemas.generated.ts: Auto-generated Zod schemas - src/schemas.ts: Re-exports with PascalCase naming for backwards compatibility The generated schemas provide a simpler alternative to the hand-written schemas in types.ts, useful for lighter validation or reference implementations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: types.ts now re-exports from spec.types.ts and schemas.generated.ts - types.ts imports and re-exports types from spec.types.ts (source of truth) - types.ts imports and re-exports schemas from schemas.generated.ts - Added compile-time VerifySchemaMatches checks to flag mismatches between interfaces and generated schemas - Removed redundant schemas.ts (types.ts now handles all re-exports) - Applied prettier formatting to schemas.generated.ts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: use ts-to-zod as library with integration tests Replace CLI-based schema generation with library API: - scripts/generate-schemas.ts: New script using ts-to-zod library API - Detailed documentation of why each post-processing step is needed - Generates integration tests via getIntegrationTestFile() - Better error reporting and control - src/schemas.generated.test.ts: Auto-generated integration tests - Compile-time verification that schemas match TypeScript types - Uses expectType<> pattern for bidirectional type checking - Removed scripts/postprocess-schemas.ts (merged into generate-schemas.ts) - Fixed McpUiResourceTeardownResult to include index signature for MCP SDK Protocol compatibility (detected by the new integration tests) Post-processing rationale (documented in generate-schemas.ts): 1. zod → zod/v4: Explicit v4 subpath for version clarity 2. z.any() → MCP SDK schemas: External types need real validation 3. z.record().and() → z.looseObject(): Index signatures need Zod v4 idiom 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: regenerate schemas during build + CI check - build script now runs generate:schemas before bun build - CI workflow verifies generated schemas are up-to-date (fails if spec.types.ts changed but schemas weren't regenerated) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: generate PascalCase schemas, move verification to tests - Add getSchemaName option to generate PascalCase schema names directly (McpUiOpenLinkRequestSchema instead of mcpUiOpenLinkRequestSchema) - Remove redundant compile-time verification from types.ts (already handled by generated test file's bidirectional expectType checks) - Simplify types.ts from 235 to 57 lines (just re-exports) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: add missing csp field, simplify schema generation - Add missing csp field to McpUiSandboxResourceReadyNotification (regression from merge) - Simplify generate-schemas.ts - remove complex .describe() conversion - Document that ts-to-zod supports @description JSDoc tags for .describe() - Improve z.looseObject() replacement with brace-counting for nested objects 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: add @description JSDoc tags for .describe() on schemas Added @description tags to all interfaces and fields in spec.types.ts. ts-to-zod now generates .describe() calls on all schema fields, making descriptions available at runtime for introspection and JSON Schema generation. Example: /** @description URL to open in the host's browser */ url: string; Generates: url: z.string().describe("URL to open in the host's browser") 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: generate JSON Schema from Zod schemas Added JSON Schema generation to the schema generation pipeline: - Uses Zod v4's built-in toJSONSchema() to convert schemas - Generates src/schema.json with all message types in $defs - Includes descriptions from @description JSDoc tags - Added export "./schema.json" to package.json - Updated CI to verify schema.json is up-to-date Use cases: - Language-agnostic validation (Python, Go, Rust) - Documentation generation (Redoc, Swagger UI) - Code generation (quicktype) - IDE autocomplete for JSON/YAML 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: rename schema.json to schema.generated.json Renamed to match other generated files naming convention. Export path unchanged: ./schema.json -> ./dist/src/schema.generated.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: rename schemas.generated.* to schema.generated.* (singular) Consistent singular naming for all generated files: - schema.generated.ts - schema.generated.test.ts - schema.generated.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: rename schemas.generated.* to schema.generated.* (singular) Consistent singular naming for all generated files: - schema.generated.ts - schema.generated.test.ts - schema.generated.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: move generated files to src/generated/ with simpler names Moved: - src/schema.generated.ts → src/generated/schema.ts - src/schema.generated.test.ts → src/generated/schema.test.ts - src/schema.generated.json → src/generated/schema.json Benefits: - Cleaner organization (generated files isolated) - Simpler names without .generated suffix - Easier to gitignore if desired later 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: add missing type exports for backwards compatibility Added missing exports that existed in main: - McpUiTheme, McpUiThemeSchema - McpUiDisplayMode, McpUiDisplayModeSchema - McpUiResourceCsp, McpUiResourceCspSchema - McpUiResourceMeta, McpUiResourceMetaSchema Also fixed theme/displayMode to match original values: - theme: 'light' | 'dark' (removed 'system') - displayMode: 'inline' | 'fullscreen' | 'pip' (removed 'carousel') Verified: all 47 exports from main are preserved with compatible types. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: stage generated files after prettier in pre-commit hook The pre-commit hook runs build (which generates schemas) then prettier (which formats them). The formatted generated files weren't being staged, causing CI to fail with 'Generated schemas are out of date'. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * update generated files * fix: run prettier after regenerating schemas in CI verification CI was comparing unformatted generated output against formatted committed files, causing false 'out of date' failures. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
358 lines
12 KiB
TypeScript
358 lines
12 KiB
TypeScript
/**
|
|
* MCP Apps Protocol Types (spec.types.ts)
|
|
*
|
|
* 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.
|
|
*
|
|
* - Use `@description` JSDoc tags to generate `.describe()` calls on schemas
|
|
* - Run `npm run generate:schemas` to regenerate schemas from these types
|
|
*
|
|
* @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx
|
|
*/
|
|
|
|
import type {
|
|
CallToolResult,
|
|
ContentBlock,
|
|
Implementation,
|
|
RequestId,
|
|
Tool,
|
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
|
|
/**
|
|
* 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";
|
|
|
|
/**
|
|
* @description Color theme preference for the host environment.
|
|
*/
|
|
export type McpUiTheme = "light" | "dark";
|
|
|
|
/**
|
|
* @description Display mode for UI presentation.
|
|
*/
|
|
export type McpUiDisplayMode = "inline" | "fullscreen" | "pip";
|
|
|
|
/**
|
|
* @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
|
|
*/
|
|
export interface McpUiOpenLinkRequest {
|
|
method: "ui/open-link";
|
|
params: {
|
|
/** @description URL to open in the host's browser */
|
|
url: string;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @description Result from opening a URL.
|
|
* @see {@link McpUiOpenLinkRequest}
|
|
*/
|
|
export interface McpUiOpenLinkResult {
|
|
/** @description True if the host failed to open the URL (e.g., due to security policy). */
|
|
isError?: boolean;
|
|
/**
|
|
* Index signature required for MCP SDK `Protocol` class compatibility.
|
|
* Note: The schema intentionally omits this to enforce strict validation.
|
|
*/
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
/**
|
|
* @description Request to send a message to the host's chat interface.
|
|
* @see {@link app.App.sendMessage} for the method that sends this request
|
|
*/
|
|
export interface McpUiMessageRequest {
|
|
method: "ui/message";
|
|
params: {
|
|
/** @description Message role, currently only "user" is supported. */
|
|
role: "user";
|
|
/** @description Message content blocks (text, image, etc.). */
|
|
content: ContentBlock[];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @description Result from sending a message.
|
|
* @see {@link McpUiMessageRequest}
|
|
*/
|
|
export interface McpUiMessageResult {
|
|
/** @description True if the host rejected or failed to deliver the message. */
|
|
isError?: boolean;
|
|
/**
|
|
* Index signature required for MCP SDK `Protocol` class compatibility.
|
|
* Note: The schema intentionally omits this to enforce strict validation.
|
|
*/
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
/**
|
|
* @description Notification that the sandbox proxy iframe is ready to receive content.
|
|
* @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: {};
|
|
}
|
|
|
|
/**
|
|
* @description Notification containing HTML resource for the sandbox proxy to load.
|
|
* @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: {
|
|
/** @description HTML content to load into the inner iframe. */
|
|
html: string;
|
|
/** @description Optional override for the inner iframe's sandbox attribute. */
|
|
sandbox?: string;
|
|
/** @description CSP configuration from resource metadata. */
|
|
csp?: {
|
|
/** @description Origins for network requests (fetch/XHR/WebSocket). */
|
|
connectDomains?: string[];
|
|
/** @description Origins for static resources (scripts, images, styles, fonts). */
|
|
resourceDomains?: string[];
|
|
};
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @description Notification of UI size changes (bidirectional: Guest <-> Host).
|
|
* @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI
|
|
*/
|
|
export interface McpUiSizeChangedNotification {
|
|
method: "ui/notifications/size-changed";
|
|
params: {
|
|
/** @description New width in pixels. */
|
|
width?: number;
|
|
/** @description New height in pixels. */
|
|
height?: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @description Notification containing complete tool arguments (Host -> Guest UI).
|
|
*/
|
|
export interface McpUiToolInputNotification {
|
|
method: "ui/notifications/tool-input";
|
|
params: {
|
|
/** @description Complete tool call arguments as key-value pairs. */
|
|
arguments?: Record<string, unknown>;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @description Notification containing partial/streaming tool arguments (Host -> Guest UI).
|
|
*/
|
|
export interface McpUiToolInputPartialNotification {
|
|
method: "ui/notifications/tool-input-partial";
|
|
params: {
|
|
/** @description Partial tool call arguments (incomplete, may change). */
|
|
arguments?: Record<string, unknown>;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @description Notification containing tool execution result (Host -> Guest UI).
|
|
*/
|
|
export interface McpUiToolResultNotification {
|
|
method: "ui/notifications/tool-result";
|
|
/** @description Standard MCP tool execution result. */
|
|
params: CallToolResult;
|
|
}
|
|
|
|
/**
|
|
* @description Rich context about the host environment provided to Guest UIs.
|
|
*/
|
|
export interface McpUiHostContext {
|
|
/** @description Metadata of the tool call that instantiated this App. */
|
|
toolInfo?: {
|
|
/** @description JSON-RPC id of the tools/call request. */
|
|
id: RequestId;
|
|
/** @description Tool definition including name, inputSchema, etc. */
|
|
tool: Tool;
|
|
};
|
|
/** @description Current color theme preference. */
|
|
theme?: McpUiTheme;
|
|
/** @description How the UI is currently displayed. */
|
|
displayMode?: McpUiDisplayMode;
|
|
/** @description Display modes the host supports. */
|
|
availableDisplayModes?: string[];
|
|
/** @description Current and maximum dimensions available to the UI. */
|
|
viewport?: {
|
|
/** @description Current viewport width in pixels. */
|
|
width: number;
|
|
/** @description Current viewport height in pixels. */
|
|
height: number;
|
|
/** @description Maximum available height in pixels (if constrained). */
|
|
maxHeight?: number;
|
|
/** @description Maximum available width in pixels (if constrained). */
|
|
maxWidth?: number;
|
|
};
|
|
/** @description User's language and region preference in BCP 47 format. */
|
|
locale?: string;
|
|
/** @description User's timezone in IANA format. */
|
|
timeZone?: string;
|
|
/** @description Host application identifier. */
|
|
userAgent?: string;
|
|
/** @description Platform type for responsive design decisions. */
|
|
platform?: "web" | "desktop" | "mobile";
|
|
/** @description Device input capabilities. */
|
|
deviceCapabilities?: {
|
|
/** @description Whether the device supports touch input. */
|
|
touch?: boolean;
|
|
/** @description Whether the device supports hover interactions. */
|
|
hover?: boolean;
|
|
};
|
|
/** @description Mobile safe area boundaries in pixels. */
|
|
safeAreaInsets?: {
|
|
/** @description Top safe area inset in pixels. */
|
|
top: number;
|
|
/** @description Right safe area inset in pixels. */
|
|
right: number;
|
|
/** @description Bottom safe area inset in pixels. */
|
|
bottom: number;
|
|
/** @description Left safe area inset in pixels. */
|
|
left: number;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @description Notification that host context has changed (Host -> Guest UI).
|
|
* @see {@link McpUiHostContext} for the full context structure
|
|
*/
|
|
export interface McpUiHostContextChangedNotification {
|
|
method: "ui/notifications/host-context-changed";
|
|
/** @description Partial context update containing only changed fields. */
|
|
params: McpUiHostContext;
|
|
}
|
|
|
|
/**
|
|
* @description Request for graceful shutdown of the Guest UI (Host -> Guest UI).
|
|
* @see {@link app-bridge.AppBridge.sendResourceTeardown} for the host method that sends this
|
|
*/
|
|
export interface McpUiResourceTeardownRequest {
|
|
method: "ui/resource-teardown";
|
|
params: {};
|
|
}
|
|
|
|
/**
|
|
* @description Result from graceful shutdown request.
|
|
* @see {@link McpUiResourceTeardownRequest}
|
|
*/
|
|
export interface McpUiResourceTeardownResult {
|
|
/**
|
|
* Index signature required for MCP SDK `Protocol` class compatibility.
|
|
*/
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
/**
|
|
* @description Capabilities supported by the host application.
|
|
* @see {@link McpUiInitializeResult} for the initialization result that includes these capabilities
|
|
*/
|
|
export interface McpUiHostCapabilities {
|
|
/** @description Experimental features (structure TBD). */
|
|
experimental?: {};
|
|
/** @description Host supports opening external URLs. */
|
|
openLinks?: {};
|
|
/** @description Host can proxy tool calls to the MCP server. */
|
|
serverTools?: {
|
|
/** @description Host supports tools/list_changed notifications. */
|
|
listChanged?: boolean;
|
|
};
|
|
/** @description Host can proxy resource reads to the MCP server. */
|
|
serverResources?: {
|
|
/** @description Host supports resources/list_changed notifications. */
|
|
listChanged?: boolean;
|
|
};
|
|
/** @description Host accepts log messages. */
|
|
logging?: {};
|
|
}
|
|
|
|
/**
|
|
* @description Capabilities provided by the Guest UI (App).
|
|
* @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities
|
|
*/
|
|
export interface McpUiAppCapabilities {
|
|
/** @description Experimental features (structure TBD). */
|
|
experimental?: {};
|
|
/** @description App exposes MCP-style tools that the host can call. */
|
|
tools?: {
|
|
/** @description App supports tools/list_changed notifications. */
|
|
listChanged?: boolean;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @description Initialization request sent from Guest UI to Host.
|
|
* @see {@link app.App.connect} for the method that sends this request
|
|
*/
|
|
export interface McpUiInitializeRequest {
|
|
method: "ui/initialize";
|
|
params: {
|
|
/** @description App identification (name and version). */
|
|
appInfo: Implementation;
|
|
/** @description Features and capabilities this app provides. */
|
|
appCapabilities: McpUiAppCapabilities;
|
|
/** @description Protocol version this app supports. */
|
|
protocolVersion: string;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @description Initialization result returned from Host to Guest UI.
|
|
* @see {@link McpUiInitializeRequest}
|
|
*/
|
|
export interface McpUiInitializeResult {
|
|
/** @description Negotiated protocol version string (e.g., "2025-11-21"). */
|
|
protocolVersion: string;
|
|
/** @description Host application identification and version. */
|
|
hostInfo: Implementation;
|
|
/** @description Features and capabilities provided by the host. */
|
|
hostCapabilities: McpUiHostCapabilities;
|
|
/** @description 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;
|
|
}
|
|
|
|
/**
|
|
* @description Notification that Guest UI has completed initialization (Guest UI -> Host).
|
|
* @see {@link app.App.connect} for the method that sends this notification
|
|
*/
|
|
export interface McpUiInitializedNotification {
|
|
method: "ui/notifications/initialized";
|
|
params?: {};
|
|
}
|
|
|
|
/**
|
|
* @description Content Security Policy configuration for UI resources.
|
|
*/
|
|
export interface McpUiResourceCsp {
|
|
/** @description Origins for network requests (fetch/XHR/WebSocket). */
|
|
connectDomains?: string[];
|
|
/** @description Origins for static resources (scripts, images, styles, fonts). */
|
|
resourceDomains?: string[];
|
|
}
|
|
|
|
/**
|
|
* @description UI Resource metadata for security and rendering configuration.
|
|
*/
|
|
export interface McpUiResourceMeta {
|
|
/** @description Content Security Policy configuration. */
|
|
csp?: McpUiResourceCsp;
|
|
/** @description Dedicated origin for widget sandbox. */
|
|
domain?: string;
|
|
/** @description Visual boundary preference - true if UI prefers a visible border. */
|
|
prefersBorder?: boolean;
|
|
}
|