From 14a51c82bf2c0db4e0a2160c96b5c4afb434c31a Mon Sep 17 00:00:00 2001 From: martinalong Date: Wed, 10 Dec 2025 15:21:55 -0800 Subject: [PATCH 1/7] Add styles prop to host context --- src/spec.types.ts | 60 +++++++++++++++++++++++++++++++++++++++++++++++ src/types.ts | 2 ++ 2 files changed, 62 insertions(+) diff --git a/src/spec.types.ts b/src/spec.types.ts index 2596bff5..063aaebf 100644 --- a/src/spec.types.ts +++ b/src/spec.types.ts @@ -36,6 +36,64 @@ export type McpUiTheme = "light" | "dark"; */ export type McpUiDisplayMode = "inline" | "fullscreen" | "pip"; +/** + * @description CSS variable keys available to MCP apps for theming. + */ +export type McpUiStyleVariableKey = + // Background colors + | "--color-background-primary" + | "--color-background-secondary" + | "--color-background-tertiary" + | "--color-background-inverted" + // Text colors + | "--color-text-primary" + | "--color-text-secondary" + | "--color-text-tertiary" + | "--color-text-inverted" + // Icon colors + | "--color-icon-primary" + | "--color-icon-secondary" + | "--color-icon-tertiary" + | "--color-icon-inverted" + // Border colors + | "--color-border-primary" + | "--color-border-secondary" + // Accent colors + | "--color-accent-info" + | "--color-accent-danger" + | "--color-accent-success" + | "--color-accent-warning" + // Typography - Family + | "--font-family-sans" + // Typography - Size + | "--font-size-heading" + | "--font-size-body" + | "--font-size-caption" + // Typography - Weight + | "--font-weight-regular" + | "--font-weight-emphasized" + // Typography - Line height + | "--font-leading-regular" + | "--font-leading-tight" + // Typography - Composite styles + | "--font-style-heading" + | "--font-style-body" + | "--font-style-body-emphasized" + | "--font-style-caption" + | "--font-style-caption-emphasized" + // Border radius + | "--border-radius-small" + | "--border-radius-medium" + | "--border-radius-large" + | "--border-radius-full" + // Border width + | "--border-width-regular"; + +/** + * @description Style variables for theming MCP apps. + */ +export type McpUiStyles = Record; + /** * @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 @@ -180,6 +238,8 @@ export interface McpUiHostContext { }; /** @description Current color theme preference. */ theme?: McpUiTheme; + /** @description CSS variables for theming the app. */ + styles?: McpUiStyles; /** @description How the UI is currently displayed. */ displayMode?: McpUiDisplayMode; /** @description Display modes the host supports. */ diff --git a/src/types.ts b/src/types.ts index 92bb8cf8..d4bbbb62 100644 --- a/src/types.ts +++ b/src/types.ts @@ -14,6 +14,8 @@ export { LATEST_PROTOCOL_VERSION, type McpUiTheme, type McpUiDisplayMode, + type McpUiStyleVariableKey, + type McpUiStyles, type McpUiOpenLinkRequest, type McpUiOpenLinkResult, type McpUiMessageRequest, From 941412fcee14d2f8ac51a8fcd1e1d59a48056c69 Mon Sep 17 00:00:00 2001 From: martinalong Date: Wed, 10 Dec 2025 15:39:22 -0800 Subject: [PATCH 2/7] Add utility for using styles --- src/app.ts | 1 + src/react/index.tsx | 2 + src/react/useHostStyles.ts | 84 ++++++++++++++++++++++++++++++++++++++ src/styles.ts | 41 +++++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 src/react/useHostStyles.ts create mode 100644 src/styles.ts diff --git a/src/app.ts b/src/app.ts index 6813becb..9f199ca8 100644 --- a/src/app.ts +++ b/src/app.ts @@ -43,6 +43,7 @@ import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js"; export { PostMessageTransport } from "./message-transport"; export * from "./types"; +export { applyHostStyles } from "./styles"; /** * Metadata key for associating a resource URI with a tool call. diff --git a/src/react/index.tsx b/src/react/index.tsx index d5ce3760..82867df7 100644 --- a/src/react/index.tsx +++ b/src/react/index.tsx @@ -9,6 +9,7 @@ * ## Main Exports * * - {@link useApp} - React hook to create and connect an MCP App + * - {@link useHostStyles} - React hook to apply host styles as CSS variables * - {@link useAutoResize} - React hook for manual auto-resize control (rarely needed) * * @module @modelcontextprotocol/ext-apps/react @@ -32,3 +33,4 @@ */ export * from "./useApp"; export * from "./useAutoResize"; +export * from "./useHostStyles"; diff --git a/src/react/useHostStyles.ts b/src/react/useHostStyles.ts new file mode 100644 index 00000000..9fa7ad57 --- /dev/null +++ b/src/react/useHostStyles.ts @@ -0,0 +1,84 @@ +import { useEffect, useRef } from "react"; +import { App } from "../app"; +import { applyHostStyles } from "../styles"; +import { McpUiHostContext } from "../types"; + +/** + * React hook that applies host styles as CSS custom properties. + * + * This hook listens to host context changes and automatically applies the + * `styles` CSS variables to `document.documentElement`. This allows your + * app to use the host's theming values via CSS variables like + * `var(--color-background-primary)`. + * + * The hook also applies styles from the initial host context when the app + * first connects. + * + * @param app - The connected App instance, or null during initialization + * @param initialContext - Initial host context from the connection (optional). + * If provided, styles will be applied immediately on mount. + * + * @example Basic usage with useApp + * ```tsx + * import { useApp } from '@modelcontextprotocol/ext-apps/react'; + * import { useHostStyles } from '@modelcontextprotocol/ext-apps/react'; + * + * function MyApp() { + * const { app, isConnected } = useApp({ + * appInfo: { name: "MyApp", version: "1.0.0" }, + * capabilities: {}, + * }); + * + * // Automatically apply host styles as CSS variables + * useHostStyles(app); + * + * return ( + *
+ * Hello! + *
+ * ); + * } + * ``` + * + * @example With initial context + * ```tsx + * const [hostContext, setHostContext] = useState(null); + * + * // ... get initial context from app.connect() result + * + * useHostStyles(app, hostContext); + * ``` + * + * @see {@link applyHostStyles} for the underlying function + * @see {@link McpUiStyles} for available CSS variables + */ +export function useHostStyles( + app: App | null, + initialContext?: McpUiHostContext | null, +): void { + const initialStylesApplied = useRef(false); + + // Apply initial styles once on mount + useEffect(() => { + if (initialStylesApplied.current) { + return; + } + if (initialContext?.styles) { + applyHostStyles(initialContext.styles); + initialStylesApplied.current = true; + } + }, [initialContext]); + + // Listen for host context changes and apply updated styles + useEffect(() => { + if (!app) { + return; + } + + app.onhostcontextchanged = (params) => { + if (params.styles) { + applyHostStyles(params.styles); + } + }; + }, [app]); +} diff --git a/src/styles.ts b/src/styles.ts new file mode 100644 index 00000000..52ab6a13 --- /dev/null +++ b/src/styles.ts @@ -0,0 +1,41 @@ +import { McpUiStyles } from "./types"; + +/** + * Apply host styles as CSS custom properties on an element. + * + * This function takes the `styles` object from `McpUiHostContext` and sets + * 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 + * `var(--color-background-primary)`. + * + * @param styles - The styles object from `McpUiHostContext.styles` + * @param root - The element to apply styles to (defaults to `document.documentElement`) + * + * @example Apply styles from host context + * ```typescript + * import { applyHostStyles } from '@modelcontextprotocol/ext-apps'; + * + * app.onhostcontextchanged = (params) => { + * if (params.styles) { + * applyHostStyles(params.styles); + * } + * }; + * ``` + * + * @example Apply to a specific element + * ```typescript + * const container = document.getElementById('app-root'); + * applyHostStyles(hostContext.styles, container); + * ``` + * + * @see {@link McpUiStyles} for the available CSS variables + * @see {@link McpUiHostContext} for the full host context structure + */ +export function applyHostStyles( + styles: McpUiStyles, + root: HTMLElement = document.documentElement, +): void { + for (const [key, value] of Object.entries(styles)) { + root.style.setProperty(key, value); + } +} From 06cc7f183536ff7ef6bc796b711007da2aedf5af Mon Sep 17 00:00:00 2001 From: martinalong Date: Wed, 10 Dec 2025 15:44:48 -0800 Subject: [PATCH 3/7] Add utility to set + read theme --- src/app.ts | 6 ++- src/react/index.tsx | 2 + src/react/useDocumentTheme.ts | 69 ++++++++++++++++++++++++++++++++ src/styles.ts | 75 ++++++++++++++++++++++++++++++++++- 4 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 src/react/useDocumentTheme.ts diff --git a/src/app.ts b/src/app.ts index 9f199ca8..e38d1d99 100644 --- a/src/app.ts +++ b/src/app.ts @@ -43,7 +43,11 @@ import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js"; export { PostMessageTransport } from "./message-transport"; export * from "./types"; -export { applyHostStyles } from "./styles"; +export { + applyHostStyles, + getDocumentTheme, + applyDocumentTheme, +} from "./styles"; /** * Metadata key for associating a resource URI with a tool call. diff --git a/src/react/index.tsx b/src/react/index.tsx index 82867df7..09e3b872 100644 --- a/src/react/index.tsx +++ b/src/react/index.tsx @@ -10,6 +10,7 @@ * * - {@link useApp} - React hook to create and connect an MCP App * - {@link useHostStyles} - React hook to apply host styles as CSS variables + * - {@link useDocumentTheme} - React hook for reactive document theme * - {@link useAutoResize} - React hook for manual auto-resize control (rarely needed) * * @module @modelcontextprotocol/ext-apps/react @@ -33,4 +34,5 @@ */ export * from "./useApp"; export * from "./useAutoResize"; +export * from "./useDocumentTheme"; export * from "./useHostStyles"; diff --git a/src/react/useDocumentTheme.ts b/src/react/useDocumentTheme.ts new file mode 100644 index 00000000..2355c68f --- /dev/null +++ b/src/react/useDocumentTheme.ts @@ -0,0 +1,69 @@ +import { useEffect, useState } from "react"; +import { getDocumentTheme } from "../styles"; +import { McpUiTheme } from "../types"; + +/** + * React hook that provides the current document theme reactively. + * + * Uses a MutationObserver to watch for changes to the `data-theme` attribute + * or `class` on `document.documentElement`. When the theme changes (e.g., from + * host context updates), the hook automatically re-renders your component with + * the new theme value. + * + * @returns The current theme ("light" or "dark") + * + * @example Conditionally render based on theme + * ```tsx + * import { useDocumentTheme } from '@modelcontextprotocol/ext-apps/react'; + * + * function MyApp() { + * const theme = useDocumentTheme(); + * + * return ( + *
+ * {theme === 'dark' ? : } + *
+ * ); + * } + * ``` + * + * @example Use with theme-aware styling + * ```tsx + * function ThemedButton() { + * const theme = useDocumentTheme(); + * + * return ( + * + * ); + * } + * ``` + * + * @see {@link getDocumentTheme} for the underlying function + * @see {@link applyDocumentTheme} to set the theme + */ +export function useDocumentTheme(): McpUiTheme { + const [theme, setTheme] = useState(getDocumentTheme); + + useEffect(() => { + const observer = new MutationObserver(() => { + setTheme(getDocumentTheme()); + }); + + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ["data-theme", "class"], + characterData: false, + childList: false, + subtree: false, + }); + + return () => observer.disconnect(); + }, []); + + return theme; +} diff --git a/src/styles.ts b/src/styles.ts index 52ab6a13..45442483 100644 --- a/src/styles.ts +++ b/src/styles.ts @@ -1,4 +1,77 @@ -import { McpUiStyles } from "./types"; +import { McpUiStyles, McpUiTheme } from "./types"; + +/** + * Get the current document theme from the root HTML element. + * + * Reads the theme from the `data-theme` attribute on `document.documentElement`. + * Falls back to checking for a `dark` class for compatibility with Tailwind CSS + * dark mode conventions. + * + * @returns The current theme ("light" or "dark") + * + * @example Check current theme + * ```typescript + * import { getDocumentTheme } from '@modelcontextprotocol/ext-apps'; + * + * const theme = getDocumentTheme(); + * console.log(`Current theme: ${theme}`); + * ``` + * + * @see {@link applyDocumentTheme} to set the theme + * @see {@link McpUiTheme} for the theme type + */ +export function getDocumentTheme(): McpUiTheme { + const theme = document.documentElement.getAttribute("data-theme"); + + if (theme === "dark" || theme === "light") { + return theme; + } + + // Fallback: check for "dark" class (Tailwind CSS convention) + const darkMode = document.documentElement.classList.contains("dark"); + + return darkMode ? "dark" : "light"; +} + +/** + * Apply a theme to the document root element. + * + * Sets the `data-theme` attribute and CSS `color-scheme` property on + * `document.documentElement`. This enables CSS selectors like + * `[data-theme="dark"]` and ensures native elements (scrollbars, form controls) + * respect the theme. + * + * @param theme - The theme to apply ("light" or "dark") + * + * @example Apply theme from host context + * ```typescript + * import { applyDocumentTheme } from '@modelcontextprotocol/ext-apps'; + * + * app.onhostcontextchanged = (params) => { + * if (params.theme) { + * applyDocumentTheme(params.theme); + * } + * }; + * ``` + * + * @example Use with CSS selectors + * ```css + * [data-theme="dark"] { + * --bg-color: #1a1a1a; + * } + * [data-theme="light"] { + * --bg-color: #ffffff; + * } + * ``` + * + * @see {@link getDocumentTheme} to read the current theme + * @see {@link McpUiTheme} for the theme type + */ +export function applyDocumentTheme(theme: McpUiTheme): void { + const root = document.documentElement; + root.setAttribute("data-theme", theme); + root.style.colorScheme = theme; +} /** * Apply host styles as CSS custom properties on an element. From 8404563a45643a541b69c20b5cfdc2cc2c8b3ee6 Mon Sep 17 00:00:00 2001 From: martinalong Date: Wed, 10 Dec 2025 23:50:38 -0800 Subject: [PATCH 4/7] Regenerate schemas after npm install MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/generated/schema.json | 1137 +++++++++++++++++++++++++++++++--- src/generated/schema.test.ts | 306 +++------ src/generated/schema.ts | 486 ++++++--------- src/react/useHostStyles.ts | 44 +- 4 files changed, 1372 insertions(+), 601 deletions(-) diff --git a/src/generated/schema.json b/src/generated/schema.json index b51e23bc..32b4dbfe 100644 --- a/src/generated/schema.json +++ b/src/generated/schema.json @@ -150,7 +150,9 @@ } } }, - "required": ["src"], + "required": [ + "src" + ], "additionalProperties": false } }, @@ -178,7 +180,9 @@ } } }, - "required": ["type"], + "required": [ + "type" + ], "additionalProperties": {} }, "outputSchema": { @@ -202,7 +206,9 @@ } } }, - "required": ["type"], + "required": [ + "type" + ], "additionalProperties": {} }, "annotations": { @@ -231,7 +237,11 @@ "properties": { "taskSupport": { "type": "string", - "enum": ["required", "optional", "forbidden"] + "enum": [ + "required", + "optional", + "forbidden" + ] } }, "additionalProperties": false @@ -244,11 +254,17 @@ "additionalProperties": {} } }, - "required": ["name", "inputSchema"], + "required": [ + "name", + "inputSchema" + ], "additionalProperties": false } }, - "required": ["id", "tool"], + "required": [ + "id", + "tool" + ], "additionalProperties": false }, "theme": { @@ -264,6 +280,163 @@ } ] }, + "styles": { + "description": "CSS variables for theming the app.", + "type": "object", + "propertyNames": { + "description": "Style variables for theming MCP apps.", + "anyOf": [ + { + "type": "string", + "const": "--color-background-primary" + }, + { + "type": "string", + "const": "--color-background-secondary" + }, + { + "type": "string", + "const": "--color-background-tertiary" + }, + { + "type": "string", + "const": "--color-background-inverted" + }, + { + "type": "string", + "const": "--color-text-primary" + }, + { + "type": "string", + "const": "--color-text-secondary" + }, + { + "type": "string", + "const": "--color-text-tertiary" + }, + { + "type": "string", + "const": "--color-text-inverted" + }, + { + "type": "string", + "const": "--color-icon-primary" + }, + { + "type": "string", + "const": "--color-icon-secondary" + }, + { + "type": "string", + "const": "--color-icon-tertiary" + }, + { + "type": "string", + "const": "--color-icon-inverted" + }, + { + "type": "string", + "const": "--color-border-primary" + }, + { + "type": "string", + "const": "--color-border-secondary" + }, + { + "type": "string", + "const": "--color-accent-info" + }, + { + "type": "string", + "const": "--color-accent-danger" + }, + { + "type": "string", + "const": "--color-accent-success" + }, + { + "type": "string", + "const": "--color-accent-warning" + }, + { + "type": "string", + "const": "--font-family-sans" + }, + { + "type": "string", + "const": "--font-size-heading" + }, + { + "type": "string", + "const": "--font-size-body" + }, + { + "type": "string", + "const": "--font-size-caption" + }, + { + "type": "string", + "const": "--font-weight-regular" + }, + { + "type": "string", + "const": "--font-weight-emphasized" + }, + { + "type": "string", + "const": "--font-leading-regular" + }, + { + "type": "string", + "const": "--font-leading-tight" + }, + { + "type": "string", + "const": "--font-style-heading" + }, + { + "type": "string", + "const": "--font-style-body" + }, + { + "type": "string", + "const": "--font-style-body-emphasized" + }, + { + "type": "string", + "const": "--font-style-caption" + }, + { + "type": "string", + "const": "--font-style-caption-emphasized" + }, + { + "type": "string", + "const": "--border-radius-small" + }, + { + "type": "string", + "const": "--border-radius-medium" + }, + { + "type": "string", + "const": "--border-radius-large" + }, + { + "type": "string", + "const": "--border-radius-full" + }, + { + "type": "string", + "const": "--border-width-regular" + } + ] + }, + "additionalProperties": { + "description": "Style variables for theming MCP apps.", + "type": "string" + } + }, "displayMode": { "description": "How the UI is currently displayed.", "anyOf": [ @@ -309,7 +482,10 @@ "type": "number" } }, - "required": ["width", "height"], + "required": [ + "width", + "height" + ], "additionalProperties": false }, "locale": { @@ -377,14 +553,22 @@ "type": "number" } }, - "required": ["top", "right", "bottom", "left"], + "required": [ + "top", + "right", + "bottom", + "left" + ], "additionalProperties": false } }, "additionalProperties": false } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false }, "McpUiHostContext": { @@ -436,7 +620,9 @@ } } }, - "required": ["src"], + "required": [ + "src" + ], "additionalProperties": false } }, @@ -464,7 +650,9 @@ } } }, - "required": ["type"], + "required": [ + "type" + ], "additionalProperties": {} }, "outputSchema": { @@ -488,7 +676,9 @@ } } }, - "required": ["type"], + "required": [ + "type" + ], "additionalProperties": {} }, "annotations": { @@ -517,7 +707,11 @@ "properties": { "taskSupport": { "type": "string", - "enum": ["required", "optional", "forbidden"] + "enum": [ + "required", + "optional", + "forbidden" + ] } }, "additionalProperties": false @@ -530,11 +724,17 @@ "additionalProperties": {} } }, - "required": ["name", "inputSchema"], + "required": [ + "name", + "inputSchema" + ], "additionalProperties": false } }, - "required": ["id", "tool"], + "required": [ + "id", + "tool" + ], "additionalProperties": false }, "theme": { @@ -550,6 +750,163 @@ } ] }, + "styles": { + "description": "CSS variables for theming the app.", + "type": "object", + "propertyNames": { + "description": "Style variables for theming MCP apps.", + "anyOf": [ + { + "type": "string", + "const": "--color-background-primary" + }, + { + "type": "string", + "const": "--color-background-secondary" + }, + { + "type": "string", + "const": "--color-background-tertiary" + }, + { + "type": "string", + "const": "--color-background-inverted" + }, + { + "type": "string", + "const": "--color-text-primary" + }, + { + "type": "string", + "const": "--color-text-secondary" + }, + { + "type": "string", + "const": "--color-text-tertiary" + }, + { + "type": "string", + "const": "--color-text-inverted" + }, + { + "type": "string", + "const": "--color-icon-primary" + }, + { + "type": "string", + "const": "--color-icon-secondary" + }, + { + "type": "string", + "const": "--color-icon-tertiary" + }, + { + "type": "string", + "const": "--color-icon-inverted" + }, + { + "type": "string", + "const": "--color-border-primary" + }, + { + "type": "string", + "const": "--color-border-secondary" + }, + { + "type": "string", + "const": "--color-accent-info" + }, + { + "type": "string", + "const": "--color-accent-danger" + }, + { + "type": "string", + "const": "--color-accent-success" + }, + { + "type": "string", + "const": "--color-accent-warning" + }, + { + "type": "string", + "const": "--font-family-sans" + }, + { + "type": "string", + "const": "--font-size-heading" + }, + { + "type": "string", + "const": "--font-size-body" + }, + { + "type": "string", + "const": "--font-size-caption" + }, + { + "type": "string", + "const": "--font-weight-regular" + }, + { + "type": "string", + "const": "--font-weight-emphasized" + }, + { + "type": "string", + "const": "--font-leading-regular" + }, + { + "type": "string", + "const": "--font-leading-tight" + }, + { + "type": "string", + "const": "--font-style-heading" + }, + { + "type": "string", + "const": "--font-style-body" + }, + { + "type": "string", + "const": "--font-style-body-emphasized" + }, + { + "type": "string", + "const": "--font-style-caption" + }, + { + "type": "string", + "const": "--font-style-caption-emphasized" + }, + { + "type": "string", + "const": "--border-radius-small" + }, + { + "type": "string", + "const": "--border-radius-medium" + }, + { + "type": "string", + "const": "--border-radius-large" + }, + { + "type": "string", + "const": "--border-radius-full" + }, + { + "type": "string", + "const": "--border-width-regular" + } + ] + }, + "additionalProperties": { + "description": "Style variables for theming MCP apps.", + "type": "string" + } + }, "displayMode": { "description": "How the UI is currently displayed.", "anyOf": [ @@ -595,7 +952,10 @@ "type": "number" } }, - "required": ["width", "height"], + "required": [ + "width", + "height" + ], "additionalProperties": false }, "locale": { @@ -663,7 +1023,12 @@ "type": "number" } }, - "required": ["top", "right", "bottom", "left"], + "required": [ + "top", + "right", + "bottom", + "left" + ], "additionalProperties": false } }, @@ -708,7 +1073,9 @@ } } }, - "required": ["src"], + "required": [ + "src" + ], "additionalProperties": false } }, @@ -719,7 +1086,10 @@ "type": "string" } }, - "required": ["name", "version"], + "required": [ + "name", + "version" + ], "additionalProperties": false }, "appCapabilities": { @@ -751,11 +1121,18 @@ "type": "string" } }, - "required": ["appInfo", "appCapabilities", "protocolVersion"], + "required": [ + "appInfo", + "appCapabilities", + "protocolVersion" + ], "additionalProperties": false } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false }, "McpUiInitializeResult": { @@ -794,7 +1171,9 @@ } } }, - "required": ["src"], + "required": [ + "src" + ], "additionalProperties": false } }, @@ -805,7 +1184,10 @@ "type": "string" } }, - "required": ["name", "version"], + "required": [ + "name", + "version" + ], "additionalProperties": false }, "hostCapabilities": { @@ -904,7 +1286,9 @@ } } }, - "required": ["src"], + "required": [ + "src" + ], "additionalProperties": false } }, @@ -932,7 +1316,9 @@ } } }, - "required": ["type"], + "required": [ + "type" + ], "additionalProperties": {} }, "outputSchema": { @@ -956,7 +1342,9 @@ } } }, - "required": ["type"], + "required": [ + "type" + ], "additionalProperties": {} }, "annotations": { @@ -985,7 +1373,11 @@ "properties": { "taskSupport": { "type": "string", - "enum": ["required", "optional", "forbidden"] + "enum": [ + "required", + "optional", + "forbidden" + ] } }, "additionalProperties": false @@ -998,11 +1390,17 @@ "additionalProperties": {} } }, - "required": ["name", "inputSchema"], + "required": [ + "name", + "inputSchema" + ], "additionalProperties": false } }, - "required": ["id", "tool"], + "required": [ + "id", + "tool" + ], "additionalProperties": false }, "theme": { @@ -1018,6 +1416,163 @@ } ] }, + "styles": { + "description": "CSS variables for theming the app.", + "type": "object", + "propertyNames": { + "description": "Style variables for theming MCP apps.", + "anyOf": [ + { + "type": "string", + "const": "--color-background-primary" + }, + { + "type": "string", + "const": "--color-background-secondary" + }, + { + "type": "string", + "const": "--color-background-tertiary" + }, + { + "type": "string", + "const": "--color-background-inverted" + }, + { + "type": "string", + "const": "--color-text-primary" + }, + { + "type": "string", + "const": "--color-text-secondary" + }, + { + "type": "string", + "const": "--color-text-tertiary" + }, + { + "type": "string", + "const": "--color-text-inverted" + }, + { + "type": "string", + "const": "--color-icon-primary" + }, + { + "type": "string", + "const": "--color-icon-secondary" + }, + { + "type": "string", + "const": "--color-icon-tertiary" + }, + { + "type": "string", + "const": "--color-icon-inverted" + }, + { + "type": "string", + "const": "--color-border-primary" + }, + { + "type": "string", + "const": "--color-border-secondary" + }, + { + "type": "string", + "const": "--color-accent-info" + }, + { + "type": "string", + "const": "--color-accent-danger" + }, + { + "type": "string", + "const": "--color-accent-success" + }, + { + "type": "string", + "const": "--color-accent-warning" + }, + { + "type": "string", + "const": "--font-family-sans" + }, + { + "type": "string", + "const": "--font-size-heading" + }, + { + "type": "string", + "const": "--font-size-body" + }, + { + "type": "string", + "const": "--font-size-caption" + }, + { + "type": "string", + "const": "--font-weight-regular" + }, + { + "type": "string", + "const": "--font-weight-emphasized" + }, + { + "type": "string", + "const": "--font-leading-regular" + }, + { + "type": "string", + "const": "--font-leading-tight" + }, + { + "type": "string", + "const": "--font-style-heading" + }, + { + "type": "string", + "const": "--font-style-body" + }, + { + "type": "string", + "const": "--font-style-body-emphasized" + }, + { + "type": "string", + "const": "--font-style-caption" + }, + { + "type": "string", + "const": "--font-style-caption-emphasized" + }, + { + "type": "string", + "const": "--border-radius-small" + }, + { + "type": "string", + "const": "--border-radius-medium" + }, + { + "type": "string", + "const": "--border-radius-large" + }, + { + "type": "string", + "const": "--border-radius-full" + }, + { + "type": "string", + "const": "--border-width-regular" + } + ] + }, + "additionalProperties": { + "description": "Style variables for theming MCP apps.", + "type": "string" + } + }, "displayMode": { "description": "How the UI is currently displayed.", "anyOf": [ @@ -1063,7 +1618,10 @@ "type": "number" } }, - "required": ["width", "height"], + "required": [ + "width", + "height" + ], "additionalProperties": false }, "locale": { @@ -1131,7 +1689,12 @@ "type": "number" } }, - "required": ["top", "right", "bottom", "left"], + "required": [ + "top", + "right", + "bottom", + "left" + ], "additionalProperties": false } }, @@ -1160,7 +1723,9 @@ "additionalProperties": false } }, - "required": ["method"], + "required": [ + "method" + ], "additionalProperties": false }, "McpUiMessageRequest": { @@ -1201,7 +1766,10 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "assistant"] + "enum": [ + "user", + "assistant" + ] } }, "priority": { @@ -1225,7 +1793,10 @@ "additionalProperties": {} } }, - "required": ["type", "text"], + "required": [ + "type", + "text" + ], "additionalProperties": false }, { @@ -1248,7 +1819,10 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "assistant"] + "enum": [ + "user", + "assistant" + ] } }, "priority": { @@ -1272,7 +1846,11 @@ "additionalProperties": {} } }, - "required": ["type", "data", "mimeType"], + "required": [ + "type", + "data", + "mimeType" + ], "additionalProperties": false }, { @@ -1295,7 +1873,10 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "assistant"] + "enum": [ + "user", + "assistant" + ] } }, "priority": { @@ -1319,7 +1900,11 @@ "additionalProperties": {} } }, - "required": ["type", "data", "mimeType"], + "required": [ + "type", + "data", + "mimeType" + ], "additionalProperties": false }, { @@ -1349,7 +1934,9 @@ } } }, - "required": ["src"], + "required": [ + "src" + ], "additionalProperties": false } }, @@ -1369,7 +1956,10 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "assistant"] + "enum": [ + "user", + "assistant" + ] } }, "priority": { @@ -1395,7 +1985,11 @@ "const": "resource_link" } }, - "required": ["name", "uri", "type"], + "required": [ + "name", + "uri", + "type" + ], "additionalProperties": false }, { @@ -1427,7 +2021,10 @@ "type": "string" } }, - "required": ["uri", "text"], + "required": [ + "uri", + "text" + ], "additionalProperties": false }, { @@ -1450,7 +2047,10 @@ "type": "string" } }, - "required": ["uri", "blob"], + "required": [ + "uri", + "blob" + ], "additionalProperties": false } ] @@ -1462,7 +2062,10 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "assistant"] + "enum": [ + "user", + "assistant" + ] } }, "priority": { @@ -1486,18 +2089,27 @@ "additionalProperties": {} } }, - "required": ["type", "resource"], + "required": [ + "type", + "resource" + ], "additionalProperties": false } ] } } }, - "required": ["role", "content"], + "required": [ + "role", + "content" + ], "additionalProperties": false } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false }, "McpUiMessageResult": { @@ -1527,11 +2139,16 @@ "type": "string" } }, - "required": ["url"], + "required": [ + "url" + ], "additionalProperties": false } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false }, "McpUiOpenLinkResult": { @@ -1616,7 +2233,10 @@ "additionalProperties": false } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false }, "McpUiResourceTeardownResult": { @@ -1641,7 +2261,10 @@ "additionalProperties": false } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false }, "McpUiSandboxResourceReadyNotification": { @@ -1685,11 +2308,16 @@ "additionalProperties": false } }, - "required": ["html"], + "required": [ + "html" + ], "additionalProperties": false } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false }, "McpUiSizeChangedNotification": { @@ -1715,9 +2343,320 @@ "additionalProperties": false } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false }, + "McpUiStyleVariableKey": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "CSS variable keys available to MCP apps for theming.", + "anyOf": [ + { + "type": "string", + "const": "--color-background-primary" + }, + { + "type": "string", + "const": "--color-background-secondary" + }, + { + "type": "string", + "const": "--color-background-tertiary" + }, + { + "type": "string", + "const": "--color-background-inverted" + }, + { + "type": "string", + "const": "--color-text-primary" + }, + { + "type": "string", + "const": "--color-text-secondary" + }, + { + "type": "string", + "const": "--color-text-tertiary" + }, + { + "type": "string", + "const": "--color-text-inverted" + }, + { + "type": "string", + "const": "--color-icon-primary" + }, + { + "type": "string", + "const": "--color-icon-secondary" + }, + { + "type": "string", + "const": "--color-icon-tertiary" + }, + { + "type": "string", + "const": "--color-icon-inverted" + }, + { + "type": "string", + "const": "--color-border-primary" + }, + { + "type": "string", + "const": "--color-border-secondary" + }, + { + "type": "string", + "const": "--color-accent-info" + }, + { + "type": "string", + "const": "--color-accent-danger" + }, + { + "type": "string", + "const": "--color-accent-success" + }, + { + "type": "string", + "const": "--color-accent-warning" + }, + { + "type": "string", + "const": "--font-family-sans" + }, + { + "type": "string", + "const": "--font-size-heading" + }, + { + "type": "string", + "const": "--font-size-body" + }, + { + "type": "string", + "const": "--font-size-caption" + }, + { + "type": "string", + "const": "--font-weight-regular" + }, + { + "type": "string", + "const": "--font-weight-emphasized" + }, + { + "type": "string", + "const": "--font-leading-regular" + }, + { + "type": "string", + "const": "--font-leading-tight" + }, + { + "type": "string", + "const": "--font-style-heading" + }, + { + "type": "string", + "const": "--font-style-body" + }, + { + "type": "string", + "const": "--font-style-body-emphasized" + }, + { + "type": "string", + "const": "--font-style-caption" + }, + { + "type": "string", + "const": "--font-style-caption-emphasized" + }, + { + "type": "string", + "const": "--border-radius-small" + }, + { + "type": "string", + "const": "--border-radius-medium" + }, + { + "type": "string", + "const": "--border-radius-large" + }, + { + "type": "string", + "const": "--border-radius-full" + }, + { + "type": "string", + "const": "--border-width-regular" + } + ] + }, + "McpUiStyles": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Style variables for theming MCP apps.", + "type": "object", + "propertyNames": { + "description": "Style variables for theming MCP apps.", + "anyOf": [ + { + "type": "string", + "const": "--color-background-primary" + }, + { + "type": "string", + "const": "--color-background-secondary" + }, + { + "type": "string", + "const": "--color-background-tertiary" + }, + { + "type": "string", + "const": "--color-background-inverted" + }, + { + "type": "string", + "const": "--color-text-primary" + }, + { + "type": "string", + "const": "--color-text-secondary" + }, + { + "type": "string", + "const": "--color-text-tertiary" + }, + { + "type": "string", + "const": "--color-text-inverted" + }, + { + "type": "string", + "const": "--color-icon-primary" + }, + { + "type": "string", + "const": "--color-icon-secondary" + }, + { + "type": "string", + "const": "--color-icon-tertiary" + }, + { + "type": "string", + "const": "--color-icon-inverted" + }, + { + "type": "string", + "const": "--color-border-primary" + }, + { + "type": "string", + "const": "--color-border-secondary" + }, + { + "type": "string", + "const": "--color-accent-info" + }, + { + "type": "string", + "const": "--color-accent-danger" + }, + { + "type": "string", + "const": "--color-accent-success" + }, + { + "type": "string", + "const": "--color-accent-warning" + }, + { + "type": "string", + "const": "--font-family-sans" + }, + { + "type": "string", + "const": "--font-size-heading" + }, + { + "type": "string", + "const": "--font-size-body" + }, + { + "type": "string", + "const": "--font-size-caption" + }, + { + "type": "string", + "const": "--font-weight-regular" + }, + { + "type": "string", + "const": "--font-weight-emphasized" + }, + { + "type": "string", + "const": "--font-leading-regular" + }, + { + "type": "string", + "const": "--font-leading-tight" + }, + { + "type": "string", + "const": "--font-style-heading" + }, + { + "type": "string", + "const": "--font-style-body" + }, + { + "type": "string", + "const": "--font-style-body-emphasized" + }, + { + "type": "string", + "const": "--font-style-caption" + }, + { + "type": "string", + "const": "--font-style-caption-emphasized" + }, + { + "type": "string", + "const": "--border-radius-small" + }, + { + "type": "string", + "const": "--border-radius-medium" + }, + { + "type": "string", + "const": "--border-radius-large" + }, + { + "type": "string", + "const": "--border-radius-full" + }, + { + "type": "string", + "const": "--border-width-regular" + } + ] + }, + "additionalProperties": { + "description": "Style variables for theming MCP apps.", + "type": "string" + } + }, "McpUiTheme": { "$schema": "https://json-schema.org/draft/2020-12/schema", "description": "Color theme preference for the host environment.", @@ -1757,7 +2696,10 @@ "additionalProperties": false } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false }, "McpUiToolInputPartialNotification": { @@ -1785,7 +2727,10 @@ "additionalProperties": false } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false }, "McpUiToolResultNotification": { @@ -1810,7 +2755,9 @@ "type": "string" } }, - "required": ["taskId"], + "required": [ + "taskId" + ], "additionalProperties": {} } }, @@ -1838,7 +2785,10 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "assistant"] + "enum": [ + "user", + "assistant" + ] } }, "priority": { @@ -1862,7 +2812,10 @@ "additionalProperties": {} } }, - "required": ["type", "text"], + "required": [ + "type", + "text" + ], "additionalProperties": false }, { @@ -1885,7 +2838,10 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "assistant"] + "enum": [ + "user", + "assistant" + ] } }, "priority": { @@ -1909,7 +2865,11 @@ "additionalProperties": {} } }, - "required": ["type", "data", "mimeType"], + "required": [ + "type", + "data", + "mimeType" + ], "additionalProperties": false }, { @@ -1932,7 +2892,10 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "assistant"] + "enum": [ + "user", + "assistant" + ] } }, "priority": { @@ -1956,7 +2919,11 @@ "additionalProperties": {} } }, - "required": ["type", "data", "mimeType"], + "required": [ + "type", + "data", + "mimeType" + ], "additionalProperties": false }, { @@ -1986,7 +2953,9 @@ } } }, - "required": ["src"], + "required": [ + "src" + ], "additionalProperties": false } }, @@ -2006,7 +2975,10 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "assistant"] + "enum": [ + "user", + "assistant" + ] } }, "priority": { @@ -2032,7 +3004,11 @@ "const": "resource_link" } }, - "required": ["name", "uri", "type"], + "required": [ + "name", + "uri", + "type" + ], "additionalProperties": false }, { @@ -2064,7 +3040,10 @@ "type": "string" } }, - "required": ["uri", "text"], + "required": [ + "uri", + "text" + ], "additionalProperties": false }, { @@ -2087,7 +3066,10 @@ "type": "string" } }, - "required": ["uri", "blob"], + "required": [ + "uri", + "blob" + ], "additionalProperties": false } ] @@ -2099,7 +3081,10 @@ "type": "array", "items": { "type": "string", - "enum": ["user", "assistant"] + "enum": [ + "user", + "assistant" + ] } }, "priority": { @@ -2123,7 +3108,10 @@ "additionalProperties": {} } }, - "required": ["type", "resource"], + "required": [ + "type", + "resource" + ], "additionalProperties": false } ] @@ -2140,11 +3128,16 @@ "type": "boolean" } }, - "required": ["content"], + "required": [ + "content" + ], "additionalProperties": {} } }, - "required": ["method", "params"], + "required": [ + "method", + "params" + ], "additionalProperties": false } } diff --git a/src/generated/schema.test.ts b/src/generated/schema.test.ts index 5a2e3a60..17016a39 100644 --- a/src/generated/schema.test.ts +++ b/src/generated/schema.test.ts @@ -11,209 +11,103 @@ function expectType(_: T) { /* noop */ } -export type McpUiThemeSchemaInferredType = z.infer< - typeof generated.McpUiThemeSchema ->; - -export type McpUiDisplayModeSchemaInferredType = z.infer< - typeof generated.McpUiDisplayModeSchema ->; - -export type McpUiOpenLinkRequestSchemaInferredType = z.infer< - typeof generated.McpUiOpenLinkRequestSchema ->; - -export type McpUiOpenLinkResultSchemaInferredType = z.infer< - typeof generated.McpUiOpenLinkResultSchema ->; - -export type McpUiMessageResultSchemaInferredType = z.infer< - typeof generated.McpUiMessageResultSchema ->; - -export type McpUiSandboxProxyReadyNotificationSchemaInferredType = z.infer< - typeof generated.McpUiSandboxProxyReadyNotificationSchema ->; - -export type McpUiSandboxResourceReadyNotificationSchemaInferredType = z.infer< - typeof generated.McpUiSandboxResourceReadyNotificationSchema ->; - -export type McpUiSizeChangedNotificationSchemaInferredType = z.infer< - typeof generated.McpUiSizeChangedNotificationSchema ->; - -export type McpUiToolInputNotificationSchemaInferredType = z.infer< - typeof generated.McpUiToolInputNotificationSchema ->; - -export type McpUiToolInputPartialNotificationSchemaInferredType = z.infer< - typeof generated.McpUiToolInputPartialNotificationSchema ->; - -export type McpUiResourceTeardownRequestSchemaInferredType = z.infer< - typeof generated.McpUiResourceTeardownRequestSchema ->; - -export type McpUiResourceTeardownResultSchemaInferredType = z.infer< - typeof generated.McpUiResourceTeardownResultSchema ->; - -export type McpUiHostCapabilitiesSchemaInferredType = z.infer< - typeof generated.McpUiHostCapabilitiesSchema ->; - -export type McpUiAppCapabilitiesSchemaInferredType = z.infer< - typeof generated.McpUiAppCapabilitiesSchema ->; - -export type McpUiInitializedNotificationSchemaInferredType = z.infer< - typeof generated.McpUiInitializedNotificationSchema ->; - -export type McpUiResourceCspSchemaInferredType = z.infer< - typeof generated.McpUiResourceCspSchema ->; - -export type McpUiResourceMetaSchemaInferredType = z.infer< - typeof generated.McpUiResourceMetaSchema ->; - -export type McpUiMessageRequestSchemaInferredType = z.infer< - typeof generated.McpUiMessageRequestSchema ->; - -export type McpUiToolResultNotificationSchemaInferredType = z.infer< - typeof generated.McpUiToolResultNotificationSchema ->; - -export type McpUiHostContextSchemaInferredType = z.infer< - typeof generated.McpUiHostContextSchema ->; - -export type McpUiHostContextChangedNotificationSchemaInferredType = z.infer< - typeof generated.McpUiHostContextChangedNotificationSchema ->; - -export type McpUiInitializeRequestSchemaInferredType = z.infer< - typeof generated.McpUiInitializeRequestSchema ->; - -export type McpUiInitializeResultSchemaInferredType = z.infer< - typeof generated.McpUiInitializeResultSchema ->; - -expectType({} as McpUiThemeSchemaInferredType); -expectType({} as spec.McpUiTheme); -expectType({} as McpUiDisplayModeSchemaInferredType); -expectType({} as spec.McpUiDisplayMode); -expectType( - {} as McpUiOpenLinkRequestSchemaInferredType, -); -expectType( - {} as spec.McpUiOpenLinkRequest, -); -expectType( - {} as McpUiOpenLinkResultSchemaInferredType, -); -expectType( - {} as spec.McpUiOpenLinkResult, -); -expectType({} as McpUiMessageResultSchemaInferredType); -expectType({} as spec.McpUiMessageResult); -expectType( - {} as McpUiSandboxProxyReadyNotificationSchemaInferredType, -); -expectType( - {} as spec.McpUiSandboxProxyReadyNotification, -); -expectType( - {} as McpUiSandboxResourceReadyNotificationSchemaInferredType, -); -expectType( - {} as spec.McpUiSandboxResourceReadyNotification, -); -expectType( - {} as McpUiSizeChangedNotificationSchemaInferredType, -); -expectType( - {} as spec.McpUiSizeChangedNotification, -); -expectType( - {} as McpUiToolInputNotificationSchemaInferredType, -); -expectType( - {} as spec.McpUiToolInputNotification, -); -expectType( - {} as McpUiToolInputPartialNotificationSchemaInferredType, -); -expectType( - {} as spec.McpUiToolInputPartialNotification, -); -expectType( - {} as McpUiResourceTeardownRequestSchemaInferredType, -); -expectType( - {} as spec.McpUiResourceTeardownRequest, -); -expectType( - {} as McpUiResourceTeardownResultSchemaInferredType, -); -expectType( - {} as spec.McpUiResourceTeardownResult, -); -expectType( - {} as McpUiHostCapabilitiesSchemaInferredType, -); -expectType( - {} as spec.McpUiHostCapabilities, -); -expectType( - {} as McpUiAppCapabilitiesSchemaInferredType, -); -expectType( - {} as spec.McpUiAppCapabilities, -); -expectType( - {} as McpUiInitializedNotificationSchemaInferredType, -); -expectType( - {} as spec.McpUiInitializedNotification, -); -expectType({} as McpUiResourceCspSchemaInferredType); -expectType({} as spec.McpUiResourceCsp); -expectType({} as McpUiResourceMetaSchemaInferredType); -expectType({} as spec.McpUiResourceMeta); -expectType( - {} as McpUiMessageRequestSchemaInferredType, -); -expectType( - {} as spec.McpUiMessageRequest, -); -expectType( - {} as McpUiToolResultNotificationSchemaInferredType, -); -expectType( - {} as spec.McpUiToolResultNotification, -); -expectType({} as McpUiHostContextSchemaInferredType); -expectType({} as spec.McpUiHostContext); -expectType( - {} as McpUiHostContextChangedNotificationSchemaInferredType, -); -expectType( - {} as spec.McpUiHostContextChangedNotification, -); -expectType( - {} as McpUiInitializeRequestSchemaInferredType, -); -expectType( - {} as spec.McpUiInitializeRequest, -); -expectType( - {} as McpUiInitializeResultSchemaInferredType, -); -expectType( - {} as spec.McpUiInitializeResult, -); +export type McpUiThemeSchemaInferredType = z.infer; + +export type McpUiDisplayModeSchemaInferredType = z.infer; + +export type McpUiStyleVariableKeySchemaInferredType = z.infer; + +export type McpUiStylesSchemaInferredType = z.infer; + +export type McpUiOpenLinkRequestSchemaInferredType = z.infer; + +export type McpUiOpenLinkResultSchemaInferredType = z.infer; + +export type McpUiMessageResultSchemaInferredType = z.infer; + +export type McpUiSandboxProxyReadyNotificationSchemaInferredType = z.infer; + +export type McpUiSandboxResourceReadyNotificationSchemaInferredType = z.infer; + +export type McpUiSizeChangedNotificationSchemaInferredType = z.infer; + +export type McpUiToolInputNotificationSchemaInferredType = z.infer; + +export type McpUiToolInputPartialNotificationSchemaInferredType = z.infer; + +export type McpUiResourceTeardownRequestSchemaInferredType = z.infer; + +export type McpUiResourceTeardownResultSchemaInferredType = z.infer; + +export type McpUiHostCapabilitiesSchemaInferredType = z.infer; + +export type McpUiAppCapabilitiesSchemaInferredType = z.infer; + +export type McpUiInitializedNotificationSchemaInferredType = z.infer; + +export type McpUiResourceCspSchemaInferredType = z.infer; + +export type McpUiResourceMetaSchemaInferredType = z.infer; + +export type McpUiMessageRequestSchemaInferredType = z.infer; + +export type McpUiToolResultNotificationSchemaInferredType = z.infer; + +export type McpUiHostContextSchemaInferredType = z.infer; + +export type McpUiHostContextChangedNotificationSchemaInferredType = z.infer; + +export type McpUiInitializeRequestSchemaInferredType = z.infer; + +export type McpUiInitializeResultSchemaInferredType = z.infer; + +expectType({} as McpUiThemeSchemaInferredType) +expectType({} as spec.McpUiTheme) +expectType({} as McpUiDisplayModeSchemaInferredType) +expectType({} as spec.McpUiDisplayMode) +expectType({} as McpUiStyleVariableKeySchemaInferredType) +expectType({} as spec.McpUiStyleVariableKey) +expectType({} as McpUiStylesSchemaInferredType) +expectType({} as spec.McpUiStyles) +expectType({} as McpUiOpenLinkRequestSchemaInferredType) +expectType({} as spec.McpUiOpenLinkRequest) +expectType({} as McpUiOpenLinkResultSchemaInferredType) +expectType({} as spec.McpUiOpenLinkResult) +expectType({} as McpUiMessageResultSchemaInferredType) +expectType({} as spec.McpUiMessageResult) +expectType({} as McpUiSandboxProxyReadyNotificationSchemaInferredType) +expectType({} as spec.McpUiSandboxProxyReadyNotification) +expectType({} as McpUiSandboxResourceReadyNotificationSchemaInferredType) +expectType({} as spec.McpUiSandboxResourceReadyNotification) +expectType({} as McpUiSizeChangedNotificationSchemaInferredType) +expectType({} as spec.McpUiSizeChangedNotification) +expectType({} as McpUiToolInputNotificationSchemaInferredType) +expectType({} as spec.McpUiToolInputNotification) +expectType({} as McpUiToolInputPartialNotificationSchemaInferredType) +expectType({} as spec.McpUiToolInputPartialNotification) +expectType({} as McpUiResourceTeardownRequestSchemaInferredType) +expectType({} as spec.McpUiResourceTeardownRequest) +expectType({} as McpUiResourceTeardownResultSchemaInferredType) +expectType({} as spec.McpUiResourceTeardownResult) +expectType({} as McpUiHostCapabilitiesSchemaInferredType) +expectType({} as spec.McpUiHostCapabilities) +expectType({} as McpUiAppCapabilitiesSchemaInferredType) +expectType({} as spec.McpUiAppCapabilities) +expectType({} as McpUiInitializedNotificationSchemaInferredType) +expectType({} as spec.McpUiInitializedNotification) +expectType({} as McpUiResourceCspSchemaInferredType) +expectType({} as spec.McpUiResourceCsp) +expectType({} as McpUiResourceMetaSchemaInferredType) +expectType({} as spec.McpUiResourceMeta) +expectType({} as McpUiMessageRequestSchemaInferredType) +expectType({} as spec.McpUiMessageRequest) +expectType({} as McpUiToolResultNotificationSchemaInferredType) +expectType({} as spec.McpUiToolResultNotification) +expectType({} as McpUiHostContextSchemaInferredType) +expectType({} as spec.McpUiHostContext) +expectType({} as McpUiHostContextChangedNotificationSchemaInferredType) +expectType({} as spec.McpUiHostContextChangedNotification) +expectType({} as McpUiInitializeRequestSchemaInferredType) +expectType({} as spec.McpUiInitializeRequest) +expectType({} as McpUiInitializeResultSchemaInferredType) +expectType({} as spec.McpUiInitializeResult) diff --git a/src/generated/schema.ts b/src/generated/schema.ts index 1b181afa..5024d02c 100644 --- a/src/generated/schema.ts +++ b/src/generated/schema.ts @@ -13,27 +13,33 @@ import { /** * @description Color theme preference for the host environment. */ -export const McpUiThemeSchema = z - .union([z.literal("light"), z.literal("dark")]) - .describe("Color theme preference for the host environment."); +export const McpUiThemeSchema = z.union([z.literal("light"), z.literal("dark")]).describe("Color theme preference for the host environment."); /** * @description Display mode for UI presentation. */ -export const McpUiDisplayModeSchema = z - .union([z.literal("inline"), z.literal("fullscreen"), z.literal("pip")]) - .describe("Display mode for UI presentation."); +export const McpUiDisplayModeSchema = z.union([z.literal("inline"), z.literal("fullscreen"), z.literal("pip")]).describe("Display mode for UI presentation."); + +/** + * @description CSS variable keys available to MCP apps for theming. + */ +export const McpUiStyleVariableKeySchema = z.union([z.literal("--color-background-primary"), z.literal("--color-background-secondary"), z.literal("--color-background-tertiary"), z.literal("--color-background-inverted"), z.literal("--color-text-primary"), z.literal("--color-text-secondary"), z.literal("--color-text-tertiary"), z.literal("--color-text-inverted"), z.literal("--color-icon-primary"), z.literal("--color-icon-secondary"), z.literal("--color-icon-tertiary"), z.literal("--color-icon-inverted"), z.literal("--color-border-primary"), z.literal("--color-border-secondary"), z.literal("--color-accent-info"), z.literal("--color-accent-danger"), z.literal("--color-accent-success"), z.literal("--color-accent-warning"), z.literal("--font-family-sans"), z.literal("--font-size-heading"), z.literal("--font-size-body"), z.literal("--font-size-caption"), z.literal("--font-weight-regular"), z.literal("--font-weight-emphasized"), z.literal("--font-leading-regular"), z.literal("--font-leading-tight"), z.literal("--font-style-heading"), z.literal("--font-style-body"), z.literal("--font-style-body-emphasized"), z.literal("--font-style-caption"), z.literal("--font-style-caption-emphasized"), z.literal("--border-radius-small"), z.literal("--border-radius-medium"), z.literal("--border-radius-large"), z.literal("--border-radius-full"), z.literal("--border-width-regular")]).describe("CSS variable keys available to MCP apps for theming."); + +/** + * @description Style variables for theming MCP apps. + */ +export const McpUiStylesSchema = z.record(McpUiStyleVariableKeySchema.describe("Style variables for theming MCP apps."), z.string().describe("Style variables for theming MCP apps.")).describe("Style variables for theming MCP apps."); /** * @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 const McpUiOpenLinkRequestSchema = z.object({ - method: z.literal("ui/open-link"), - params: z.object({ - /** @description URL to open in the host's browser */ - url: z.string().describe("URL to open in the host's browser"), - }), + method: z.literal("ui/open-link"), + params: z.object({ + /** @description URL to open in the host's browser */ + url: z.string().describe("URL to open in the host's browser") + }) }); /** @@ -41,13 +47,8 @@ export const McpUiOpenLinkRequestSchema = z.object({ * @see {@link McpUiOpenLinkRequest} */ export const McpUiOpenLinkResultSchema = z.looseObject({ - /** @description True if the host failed to open the URL (e.g., due to security policy). */ - isError: z - .boolean() - .optional() - .describe( - "True if the host failed to open the URL (e.g., due to security policy).", - ), + /** @description True if the host failed to open the URL (e.g., due to security policy). */ + isError: z.boolean().optional().describe("True if the host failed to open the URL (e.g., due to security policy).") }); /** @@ -55,11 +56,8 @@ export const McpUiOpenLinkResultSchema = z.looseObject({ * @see {@link McpUiMessageRequest} */ export const McpUiMessageResultSchema = z.looseObject({ - /** @description True if the host rejected or failed to deliver the message. */ - isError: z - .boolean() - .optional() - .describe("True if the host rejected or failed to deliver the message."), + /** @description True if the host rejected or failed to deliver the message. */ + isError: z.boolean().optional().describe("True if the host rejected or failed to deliver the message.") }); /** @@ -68,8 +66,8 @@ export const McpUiMessageResultSchema = z.looseObject({ * @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy */ export const McpUiSandboxProxyReadyNotificationSchema = z.object({ - method: z.literal("ui/notifications/sandbox-proxy-ready"), - params: z.object({}), + method: z.literal("ui/notifications/sandbox-proxy-ready"), + params: z.object({}) }); /** @@ -78,34 +76,20 @@ export const McpUiSandboxProxyReadyNotificationSchema = z.object({ * @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy */ export const McpUiSandboxResourceReadyNotificationSchema = z.object({ - method: z.literal("ui/notifications/sandbox-resource-ready"), - params: z.object({ - /** @description HTML content to load into the inner iframe. */ - html: z.string().describe("HTML content to load into the inner iframe."), - /** @description Optional override for the inner iframe's sandbox attribute. */ - sandbox: z - .string() - .optional() - .describe("Optional override for the inner iframe's sandbox attribute."), - /** @description CSP configuration from resource metadata. */ - csp: z - .object({ - /** @description Origins for network requests (fetch/XHR/WebSocket). */ - connectDomains: z - .array(z.string()) - .optional() - .describe("Origins for network requests (fetch/XHR/WebSocket)."), - /** @description Origins for static resources (scripts, images, styles, fonts). */ - resourceDomains: z - .array(z.string()) - .optional() - .describe( - "Origins for static resources (scripts, images, styles, fonts).", - ), - }) - .optional() - .describe("CSP configuration from resource metadata."), - }), + method: z.literal("ui/notifications/sandbox-resource-ready"), + params: z.object({ + /** @description HTML content to load into the inner iframe. */ + html: z.string().describe("HTML content to load into the inner iframe."), + /** @description Optional override for the inner iframe's sandbox attribute. */ + sandbox: z.string().optional().describe("Optional override for the inner iframe's sandbox attribute."), + /** @description CSP configuration from resource metadata. */ + csp: z.object({ + /** @description Origins for network requests (fetch/XHR/WebSocket). */ + connectDomains: z.array(z.string()).optional().describe("Origins for network requests (fetch/XHR/WebSocket)."), + /** @description Origins for static resources (scripts, images, styles, fonts). */ + resourceDomains: z.array(z.string()).optional().describe("Origins for static resources (scripts, images, styles, fonts).") + }).optional().describe("CSP configuration from resource metadata.") + }) }); /** @@ -113,51 +97,35 @@ export const McpUiSandboxResourceReadyNotificationSchema = z.object({ * @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI */ export const McpUiSizeChangedNotificationSchema = z.object({ - method: z.literal("ui/notifications/size-changed"), - params: z.object({ - /** @description New width in pixels. */ - width: z.number().optional().describe("New width in pixels."), - /** @description New height in pixels. */ - height: z.number().optional().describe("New height in pixels."), - }), + method: z.literal("ui/notifications/size-changed"), + params: z.object({ + /** @description New width in pixels. */ + width: z.number().optional().describe("New width in pixels."), + /** @description New height in pixels. */ + height: z.number().optional().describe("New height in pixels.") + }) }); /** * @description Notification containing complete tool arguments (Host -> Guest UI). */ export const McpUiToolInputNotificationSchema = z.object({ - method: z.literal("ui/notifications/tool-input"), - params: z.object({ - /** @description Complete tool call arguments as key-value pairs. */ - arguments: z - .record( - z.string(), - z - .unknown() - .describe("Complete tool call arguments as key-value pairs."), - ) - .optional() - .describe("Complete tool call arguments as key-value pairs."), - }), + method: z.literal("ui/notifications/tool-input"), + params: z.object({ + /** @description Complete tool call arguments as key-value pairs. */ + arguments: z.record(z.string(), z.unknown().describe("Complete tool call arguments as key-value pairs.")).optional().describe("Complete tool call arguments as key-value pairs.") + }) }); /** * @description Notification containing partial/streaming tool arguments (Host -> Guest UI). */ export const McpUiToolInputPartialNotificationSchema = z.object({ - method: z.literal("ui/notifications/tool-input-partial"), - params: z.object({ - /** @description Partial tool call arguments (incomplete, may change). */ - arguments: z - .record( - z.string(), - z - .unknown() - .describe("Partial tool call arguments (incomplete, may change)."), - ) - .optional() - .describe("Partial tool call arguments (incomplete, may change)."), - }), + method: z.literal("ui/notifications/tool-input-partial"), + params: z.object({ + /** @description Partial tool call arguments (incomplete, may change). */ + arguments: z.record(z.string(), z.unknown().describe("Partial tool call arguments (incomplete, may change).")).optional().describe("Partial tool call arguments (incomplete, may change).") + }) }); /** @@ -165,58 +133,37 @@ export const McpUiToolInputPartialNotificationSchema = z.object({ * @see {@link app-bridge.AppBridge.sendResourceTeardown} for the host method that sends this */ export const McpUiResourceTeardownRequestSchema = z.object({ - method: z.literal("ui/resource-teardown"), - params: z.object({}), + method: z.literal("ui/resource-teardown"), + params: z.object({}) }); /** * @description Result from graceful shutdown request. * @see {@link McpUiResourceTeardownRequest} */ -export const McpUiResourceTeardownResultSchema = z.record( - z.string(), - z.unknown(), -); +export const McpUiResourceTeardownResultSchema = z.record(z.string(), z.unknown()); /** * @description Capabilities supported by the host application. * @see {@link McpUiInitializeResult} for the initialization result that includes these capabilities */ export const McpUiHostCapabilitiesSchema = z.object({ - /** @description Experimental features (structure TBD). */ - experimental: z - .object({}) - .optional() - .describe("Experimental features (structure TBD)."), - /** @description Host supports opening external URLs. */ - openLinks: z - .object({}) - .optional() - .describe("Host supports opening external URLs."), - /** @description Host can proxy tool calls to the MCP server. */ - serverTools: z - .object({ - /** @description Host supports tools/list_changed notifications. */ - listChanged: z - .boolean() - .optional() - .describe("Host supports tools/list_changed notifications."), - }) - .optional() - .describe("Host can proxy tool calls to the MCP server."), - /** @description Host can proxy resource reads to the MCP server. */ - serverResources: z - .object({ - /** @description Host supports resources/list_changed notifications. */ - listChanged: z - .boolean() - .optional() - .describe("Host supports resources/list_changed notifications."), - }) - .optional() - .describe("Host can proxy resource reads to the MCP server."), - /** @description Host accepts log messages. */ - logging: z.object({}).optional().describe("Host accepts log messages."), + /** @description Experimental features (structure TBD). */ + experimental: z.object({}).optional().describe("Experimental features (structure TBD)."), + /** @description Host supports opening external URLs. */ + openLinks: z.object({}).optional().describe("Host supports opening external URLs."), + /** @description Host can proxy tool calls to the MCP server. */ + serverTools: z.object({ + /** @description Host supports tools/list_changed notifications. */ + listChanged: z.boolean().optional().describe("Host supports tools/list_changed notifications.") + }).optional().describe("Host can proxy tool calls to the MCP server."), + /** @description Host can proxy resource reads to the MCP server. */ + serverResources: z.object({ + /** @description Host supports resources/list_changed notifications. */ + listChanged: z.boolean().optional().describe("Host supports resources/list_changed notifications.") + }).optional().describe("Host can proxy resource reads to the MCP server."), + /** @description Host accepts log messages. */ + logging: z.object({}).optional().describe("Host accepts log messages.") }); /** @@ -224,22 +171,13 @@ export const McpUiHostCapabilitiesSchema = z.object({ * @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities */ export const McpUiAppCapabilitiesSchema = z.object({ - /** @description Experimental features (structure TBD). */ - experimental: z - .object({}) - .optional() - .describe("Experimental features (structure TBD)."), - /** @description App exposes MCP-style tools that the host can call. */ - tools: z - .object({ - /** @description App supports tools/list_changed notifications. */ - listChanged: z - .boolean() - .optional() - .describe("App supports tools/list_changed notifications."), - }) - .optional() - .describe("App exposes MCP-style tools that the host can call."), + /** @description Experimental features (structure TBD). */ + experimental: z.object({}).optional().describe("Experimental features (structure TBD)."), + /** @description App exposes MCP-style tools that the host can call. */ + tools: z.object({ + /** @description App supports tools/list_changed notifications. */ + listChanged: z.boolean().optional().describe("App supports tools/list_changed notifications.") + }).optional().describe("App exposes MCP-style tools that the host can call.") }); /** @@ -247,168 +185,116 @@ export const McpUiAppCapabilitiesSchema = z.object({ * @see {@link app.App.connect} for the method that sends this notification */ export const McpUiInitializedNotificationSchema = z.object({ - method: z.literal("ui/notifications/initialized"), - params: z.object({}).optional(), + method: z.literal("ui/notifications/initialized"), + params: z.object({}).optional() }); /** * @description Content Security Policy configuration for UI resources. */ export const McpUiResourceCspSchema = z.object({ - /** @description Origins for network requests (fetch/XHR/WebSocket). */ - connectDomains: z - .array(z.string()) - .optional() - .describe("Origins for network requests (fetch/XHR/WebSocket)."), - /** @description Origins for static resources (scripts, images, styles, fonts). */ - resourceDomains: z - .array(z.string()) - .optional() - .describe("Origins for static resources (scripts, images, styles, fonts)."), + /** @description Origins for network requests (fetch/XHR/WebSocket). */ + connectDomains: z.array(z.string()).optional().describe("Origins for network requests (fetch/XHR/WebSocket)."), + /** @description Origins for static resources (scripts, images, styles, fonts). */ + resourceDomains: z.array(z.string()).optional().describe("Origins for static resources (scripts, images, styles, fonts).") }); /** * @description UI Resource metadata for security and rendering configuration. */ export const McpUiResourceMetaSchema = z.object({ - /** @description Content Security Policy configuration. */ - csp: McpUiResourceCspSchema.optional().describe( - "Content Security Policy configuration.", - ), - /** @description Dedicated origin for widget sandbox. */ - domain: z - .string() - .optional() - .describe("Dedicated origin for widget sandbox."), - /** @description Visual boundary preference - true if UI prefers a visible border. */ - prefersBorder: z - .boolean() - .optional() - .describe( - "Visual boundary preference - true if UI prefers a visible border.", - ), + /** @description Content Security Policy configuration. */ + csp: McpUiResourceCspSchema.optional().describe("Content Security Policy configuration."), + /** @description Dedicated origin for widget sandbox. */ + domain: z.string().optional().describe("Dedicated origin for widget sandbox."), + /** @description Visual boundary preference - true if UI prefers a visible border. */ + prefersBorder: z.boolean().optional().describe("Visual boundary preference - true if UI prefers a visible border.") }); + + + + + /** * @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 const McpUiMessageRequestSchema = z.object({ - method: z.literal("ui/message"), - params: z.object({ - /** @description Message role, currently only "user" is supported. */ - role: z - .literal("user") - .describe('Message role, currently only "user" is supported.'), - /** @description Message content blocks (text, image, etc.). */ - content: z - .array(ContentBlockSchema) - .describe("Message content blocks (text, image, etc.)."), - }), + method: z.literal("ui/message"), + params: z.object({ + /** @description Message role, currently only "user" is supported. */ + role: z.literal("user").describe("Message role, currently only \"user\" is supported."), + /** @description Message content blocks (text, image, etc.). */ + content: z.array(ContentBlockSchema).describe("Message content blocks (text, image, etc.).") + }) }); /** * @description Notification containing tool execution result (Host -> Guest UI). */ export const McpUiToolResultNotificationSchema = z.object({ - method: z.literal("ui/notifications/tool-result"), - /** @description Standard MCP tool execution result. */ - params: CallToolResultSchema.describe("Standard MCP tool execution result."), + method: z.literal("ui/notifications/tool-result"), + /** @description Standard MCP tool execution result. */ + params: CallToolResultSchema.describe("Standard MCP tool execution result.") }); /** * @description Rich context about the host environment provided to Guest UIs. */ export const McpUiHostContextSchema = z.object({ - /** @description Metadata of the tool call that instantiated this App. */ - toolInfo: z - .object({ - /** @description JSON-RPC id of the tools/call request. */ - id: RequestIdSchema.describe("JSON-RPC id of the tools/call request."), - /** @description Tool definition including name, inputSchema, etc. */ - tool: ToolSchema.describe( - "Tool definition including name, inputSchema, etc.", - ), - }) - .optional() - .describe("Metadata of the tool call that instantiated this App."), - /** @description Current color theme preference. */ - theme: McpUiThemeSchema.optional().describe( - "Current color theme preference.", - ), - /** @description How the UI is currently displayed. */ - displayMode: McpUiDisplayModeSchema.optional().describe( - "How the UI is currently displayed.", - ), - /** @description Display modes the host supports. */ - availableDisplayModes: z - .array(z.string()) - .optional() - .describe("Display modes the host supports."), - /** @description Current and maximum dimensions available to the UI. */ - viewport: z - .object({ - /** @description Current viewport width in pixels. */ - width: z.number().describe("Current viewport width in pixels."), - /** @description Current viewport height in pixels. */ - height: z.number().describe("Current viewport height in pixels."), - /** @description Maximum available height in pixels (if constrained). */ - maxHeight: z - .number() - .optional() - .describe("Maximum available height in pixels (if constrained)."), - /** @description Maximum available width in pixels (if constrained). */ - maxWidth: z - .number() - .optional() - .describe("Maximum available width in pixels (if constrained)."), - }) - .optional() - .describe("Current and maximum dimensions available to the UI."), - /** @description User's language and region preference in BCP 47 format. */ - locale: z - .string() - .optional() - .describe("User's language and region preference in BCP 47 format."), - /** @description User's timezone in IANA format. */ - timeZone: z.string().optional().describe("User's timezone in IANA format."), - /** @description Host application identifier. */ - userAgent: z.string().optional().describe("Host application identifier."), - /** @description Platform type for responsive design decisions. */ - platform: z - .union([z.literal("web"), z.literal("desktop"), z.literal("mobile")]) - .optional() - .describe("Platform type for responsive design decisions."), - /** @description Device input capabilities. */ - deviceCapabilities: z - .object({ - /** @description Whether the device supports touch input. */ - touch: z - .boolean() - .optional() - .describe("Whether the device supports touch input."), - /** @description Whether the device supports hover interactions. */ - hover: z - .boolean() - .optional() - .describe("Whether the device supports hover interactions."), - }) - .optional() - .describe("Device input capabilities."), - /** @description Mobile safe area boundaries in pixels. */ - safeAreaInsets: z - .object({ - /** @description Top safe area inset in pixels. */ - top: z.number().describe("Top safe area inset in pixels."), - /** @description Right safe area inset in pixels. */ - right: z.number().describe("Right safe area inset in pixels."), - /** @description Bottom safe area inset in pixels. */ - bottom: z.number().describe("Bottom safe area inset in pixels."), - /** @description Left safe area inset in pixels. */ - left: z.number().describe("Left safe area inset in pixels."), - }) - .optional() - .describe("Mobile safe area boundaries in pixels."), + /** @description Metadata of the tool call that instantiated this App. */ + toolInfo: z.object({ + /** @description JSON-RPC id of the tools/call request. */ + id: RequestIdSchema.describe("JSON-RPC id of the tools/call request."), + /** @description Tool definition including name, inputSchema, etc. */ + tool: ToolSchema.describe("Tool definition including name, inputSchema, etc.") + }).optional().describe("Metadata of the tool call that instantiated this App."), + /** @description Current color theme preference. */ + theme: McpUiThemeSchema.optional().describe("Current color theme preference."), + /** @description CSS variables for theming the app. */ + styles: McpUiStylesSchema.optional().describe("CSS variables for theming the app."), + /** @description How the UI is currently displayed. */ + displayMode: McpUiDisplayModeSchema.optional().describe("How the UI is currently displayed."), + /** @description Display modes the host supports. */ + availableDisplayModes: z.array(z.string()).optional().describe("Display modes the host supports."), + /** @description Current and maximum dimensions available to the UI. */ + viewport: z.object({ + /** @description Current viewport width in pixels. */ + width: z.number().describe("Current viewport width in pixels."), + /** @description Current viewport height in pixels. */ + height: z.number().describe("Current viewport height in pixels."), + /** @description Maximum available height in pixels (if constrained). */ + maxHeight: z.number().optional().describe("Maximum available height in pixels (if constrained)."), + /** @description Maximum available width in pixels (if constrained). */ + maxWidth: z.number().optional().describe("Maximum available width in pixels (if constrained).") + }).optional().describe("Current and maximum dimensions available to the UI."), + /** @description User's language and region preference in BCP 47 format. */ + locale: z.string().optional().describe("User's language and region preference in BCP 47 format."), + /** @description User's timezone in IANA format. */ + timeZone: z.string().optional().describe("User's timezone in IANA format."), + /** @description Host application identifier. */ + userAgent: z.string().optional().describe("Host application identifier."), + /** @description Platform type for responsive design decisions. */ + platform: z.union([z.literal("web"), z.literal("desktop"), z.literal("mobile")]).optional().describe("Platform type for responsive design decisions."), + /** @description Device input capabilities. */ + deviceCapabilities: z.object({ + /** @description Whether the device supports touch input. */ + touch: z.boolean().optional().describe("Whether the device supports touch input."), + /** @description Whether the device supports hover interactions. */ + hover: z.boolean().optional().describe("Whether the device supports hover interactions.") + }).optional().describe("Device input capabilities."), + /** @description Mobile safe area boundaries in pixels. */ + safeAreaInsets: z.object({ + /** @description Top safe area inset in pixels. */ + top: z.number().describe("Top safe area inset in pixels."), + /** @description Right safe area inset in pixels. */ + right: z.number().describe("Right safe area inset in pixels."), + /** @description Bottom safe area inset in pixels. */ + bottom: z.number().describe("Bottom safe area inset in pixels."), + /** @description Left safe area inset in pixels. */ + left: z.number().describe("Left safe area inset in pixels.") + }).optional().describe("Mobile safe area boundaries in pixels.") }); /** @@ -416,11 +302,9 @@ export const McpUiHostContextSchema = z.object({ * @see {@link McpUiHostContext} for the full context structure */ export const McpUiHostContextChangedNotificationSchema = z.object({ - method: z.literal("ui/notifications/host-context-changed"), - /** @description Partial context update containing only changed fields. */ - params: McpUiHostContextSchema.describe( - "Partial context update containing only changed fields.", - ), + method: z.literal("ui/notifications/host-context-changed"), + /** @description Partial context update containing only changed fields. */ + params: McpUiHostContextSchema.describe("Partial context update containing only changed fields.") }); /** @@ -428,19 +312,15 @@ export const McpUiHostContextChangedNotificationSchema = z.object({ * @see {@link app.App.connect} for the method that sends this request */ export const McpUiInitializeRequestSchema = z.object({ - method: z.literal("ui/initialize"), - params: z.object({ - /** @description App identification (name and version). */ - appInfo: ImplementationSchema.describe( - "App identification (name and version).", - ), - /** @description Features and capabilities this app provides. */ - appCapabilities: McpUiAppCapabilitiesSchema.describe( - "Features and capabilities this app provides.", - ), - /** @description Protocol version this app supports. */ - protocolVersion: z.string().describe("Protocol version this app supports."), - }), + method: z.literal("ui/initialize"), + params: z.object({ + /** @description App identification (name and version). */ + appInfo: ImplementationSchema.describe("App identification (name and version)."), + /** @description Features and capabilities this app provides. */ + appCapabilities: McpUiAppCapabilitiesSchema.describe("Features and capabilities this app provides."), + /** @description Protocol version this app supports. */ + protocolVersion: z.string().describe("Protocol version this app supports.") + }) }); /** @@ -448,20 +328,12 @@ export const McpUiInitializeRequestSchema = z.object({ * @see {@link McpUiInitializeRequest} */ export const McpUiInitializeResultSchema = z.looseObject({ - /** @description Negotiated protocol version string (e.g., "2025-11-21"). */ - protocolVersion: z - .string() - .describe('Negotiated protocol version string (e.g., "2025-11-21").'), - /** @description Host application identification and version. */ - hostInfo: ImplementationSchema.describe( - "Host application identification and version.", - ), - /** @description Features and capabilities provided by the host. */ - hostCapabilities: McpUiHostCapabilitiesSchema.describe( - "Features and capabilities provided by the host.", - ), - /** @description Rich context about the host environment. */ - hostContext: McpUiHostContextSchema.describe( - "Rich context about the host environment.", - ), + /** @description Negotiated protocol version string (e.g., "2025-11-21"). */ + protocolVersion: z.string().describe("Negotiated protocol version string (e.g., \"2025-11-21\")."), + /** @description Host application identification and version. */ + hostInfo: ImplementationSchema.describe("Host application identification and version."), + /** @description Features and capabilities provided by the host. */ + hostCapabilities: McpUiHostCapabilitiesSchema.describe("Features and capabilities provided by the host."), + /** @description Rich context about the host environment. */ + hostContext: McpUiHostContextSchema.describe("Rich context about the host environment.") }); diff --git a/src/react/useHostStyles.ts b/src/react/useHostStyles.ts index 9fa7ad57..0a2e32c2 100644 --- a/src/react/useHostStyles.ts +++ b/src/react/useHostStyles.ts @@ -1,22 +1,25 @@ import { useEffect, useRef } from "react"; import { App } from "../app"; -import { applyHostStyles } from "../styles"; +import { applyDocumentTheme, applyHostStyles } from "../styles"; import { McpUiHostContext } from "../types"; /** - * React hook that applies host styles as CSS custom properties. + * React hook that applies host styles and theme as CSS custom properties. * - * This hook listens to host context changes and automatically applies the - * `styles` CSS variables to `document.documentElement`. This allows your - * app to use the host's theming values via CSS variables like - * `var(--color-background-primary)`. + * This hook listens to host context changes and automatically applies: + * - `styles` CSS variables to `document.documentElement` (e.g., `--color-background-primary`) + * - `theme` via `color-scheme` CSS property, enabling `light-dark()` CSS function support * - * The hook also applies styles from the initial host context when the app - * first connects. + * The hook also applies styles and theme from the initial host context when + * the app first connects. + * + * **Note:** If the host provides style values using CSS `light-dark()` function, + * this hook ensures they work correctly by setting the `color-scheme` property + * based on the host's theme preference. * * @param app - The connected App instance, or null during initialization * @param initialContext - Initial host context from the connection (optional). - * If provided, styles will be applied immediately on mount. + * If provided, styles and theme will be applied immediately on mount. * * @example Basic usage with useApp * ```tsx @@ -29,7 +32,7 @@ import { McpUiHostContext } from "../types"; * capabilities: {}, * }); * - * // Automatically apply host styles as CSS variables + * // Automatically apply host styles and theme * useHostStyles(app); * * return ( @@ -49,33 +52,42 @@ import { McpUiHostContext } from "../types"; * useHostStyles(app, hostContext); * ``` * - * @see {@link applyHostStyles} for the underlying function + * @see {@link applyHostStyles} for the underlying styles function + * @see {@link applyDocumentTheme} for the underlying theme function * @see {@link McpUiStyles} for available CSS variables */ export function useHostStyles( app: App | null, initialContext?: McpUiHostContext | null, ): void { - const initialStylesApplied = useRef(false); + const initialApplied = useRef(false); - // Apply initial styles once on mount + // Apply initial styles and theme once on mount useEffect(() => { - if (initialStylesApplied.current) { + if (initialApplied.current) { return; } + if (initialContext?.theme) { + applyDocumentTheme(initialContext.theme); + } if (initialContext?.styles) { applyHostStyles(initialContext.styles); - initialStylesApplied.current = true; + } + if (initialContext?.theme || initialContext?.styles) { + initialApplied.current = true; } }, [initialContext]); - // Listen for host context changes and apply updated styles + // Listen for host context changes and apply updated styles/theme useEffect(() => { if (!app) { return; } app.onhostcontextchanged = (params) => { + if (params.theme) { + applyDocumentTheme(params.theme); + } if (params.styles) { applyHostStyles(params.styles); } From f8c0ffa32027cd455ec3a96707198dfeeb4f829d Mon Sep 17 00:00:00 2001 From: martinalong Date: Wed, 10 Dec 2025 23:55:06 -0800 Subject: [PATCH 5/7] Format generated schemas with prettier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/generated/schema.json | 358 +++++------------------ src/generated/schema.test.ts | 322 ++++++++++++++------- src/generated/schema.ts | 530 ++++++++++++++++++++++++----------- 3 files changed, 653 insertions(+), 557 deletions(-) diff --git a/src/generated/schema.json b/src/generated/schema.json index 32b4dbfe..d5589d35 100644 --- a/src/generated/schema.json +++ b/src/generated/schema.json @@ -150,9 +150,7 @@ } } }, - "required": [ - "src" - ], + "required": ["src"], "additionalProperties": false } }, @@ -180,9 +178,7 @@ } } }, - "required": [ - "type" - ], + "required": ["type"], "additionalProperties": {} }, "outputSchema": { @@ -206,9 +202,7 @@ } } }, - "required": [ - "type" - ], + "required": ["type"], "additionalProperties": {} }, "annotations": { @@ -237,11 +231,7 @@ "properties": { "taskSupport": { "type": "string", - "enum": [ - "required", - "optional", - "forbidden" - ] + "enum": ["required", "optional", "forbidden"] } }, "additionalProperties": false @@ -254,17 +244,11 @@ "additionalProperties": {} } }, - "required": [ - "name", - "inputSchema" - ], + "required": ["name", "inputSchema"], "additionalProperties": false } }, - "required": [ - "id", - "tool" - ], + "required": ["id", "tool"], "additionalProperties": false }, "theme": { @@ -482,10 +466,7 @@ "type": "number" } }, - "required": [ - "width", - "height" - ], + "required": ["width", "height"], "additionalProperties": false }, "locale": { @@ -553,22 +534,14 @@ "type": "number" } }, - "required": [ - "top", - "right", - "bottom", - "left" - ], + "required": ["top", "right", "bottom", "left"], "additionalProperties": false } }, "additionalProperties": false } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false }, "McpUiHostContext": { @@ -620,9 +593,7 @@ } } }, - "required": [ - "src" - ], + "required": ["src"], "additionalProperties": false } }, @@ -650,9 +621,7 @@ } } }, - "required": [ - "type" - ], + "required": ["type"], "additionalProperties": {} }, "outputSchema": { @@ -676,9 +645,7 @@ } } }, - "required": [ - "type" - ], + "required": ["type"], "additionalProperties": {} }, "annotations": { @@ -707,11 +674,7 @@ "properties": { "taskSupport": { "type": "string", - "enum": [ - "required", - "optional", - "forbidden" - ] + "enum": ["required", "optional", "forbidden"] } }, "additionalProperties": false @@ -724,17 +687,11 @@ "additionalProperties": {} } }, - "required": [ - "name", - "inputSchema" - ], + "required": ["name", "inputSchema"], "additionalProperties": false } }, - "required": [ - "id", - "tool" - ], + "required": ["id", "tool"], "additionalProperties": false }, "theme": { @@ -952,10 +909,7 @@ "type": "number" } }, - "required": [ - "width", - "height" - ], + "required": ["width", "height"], "additionalProperties": false }, "locale": { @@ -1023,12 +977,7 @@ "type": "number" } }, - "required": [ - "top", - "right", - "bottom", - "left" - ], + "required": ["top", "right", "bottom", "left"], "additionalProperties": false } }, @@ -1073,9 +1022,7 @@ } } }, - "required": [ - "src" - ], + "required": ["src"], "additionalProperties": false } }, @@ -1086,10 +1033,7 @@ "type": "string" } }, - "required": [ - "name", - "version" - ], + "required": ["name", "version"], "additionalProperties": false }, "appCapabilities": { @@ -1121,18 +1065,11 @@ "type": "string" } }, - "required": [ - "appInfo", - "appCapabilities", - "protocolVersion" - ], + "required": ["appInfo", "appCapabilities", "protocolVersion"], "additionalProperties": false } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false }, "McpUiInitializeResult": { @@ -1171,9 +1108,7 @@ } } }, - "required": [ - "src" - ], + "required": ["src"], "additionalProperties": false } }, @@ -1184,10 +1119,7 @@ "type": "string" } }, - "required": [ - "name", - "version" - ], + "required": ["name", "version"], "additionalProperties": false }, "hostCapabilities": { @@ -1286,9 +1218,7 @@ } } }, - "required": [ - "src" - ], + "required": ["src"], "additionalProperties": false } }, @@ -1316,9 +1246,7 @@ } } }, - "required": [ - "type" - ], + "required": ["type"], "additionalProperties": {} }, "outputSchema": { @@ -1342,9 +1270,7 @@ } } }, - "required": [ - "type" - ], + "required": ["type"], "additionalProperties": {} }, "annotations": { @@ -1373,11 +1299,7 @@ "properties": { "taskSupport": { "type": "string", - "enum": [ - "required", - "optional", - "forbidden" - ] + "enum": ["required", "optional", "forbidden"] } }, "additionalProperties": false @@ -1390,17 +1312,11 @@ "additionalProperties": {} } }, - "required": [ - "name", - "inputSchema" - ], + "required": ["name", "inputSchema"], "additionalProperties": false } }, - "required": [ - "id", - "tool" - ], + "required": ["id", "tool"], "additionalProperties": false }, "theme": { @@ -1618,10 +1534,7 @@ "type": "number" } }, - "required": [ - "width", - "height" - ], + "required": ["width", "height"], "additionalProperties": false }, "locale": { @@ -1689,12 +1602,7 @@ "type": "number" } }, - "required": [ - "top", - "right", - "bottom", - "left" - ], + "required": ["top", "right", "bottom", "left"], "additionalProperties": false } }, @@ -1723,9 +1631,7 @@ "additionalProperties": false } }, - "required": [ - "method" - ], + "required": ["method"], "additionalProperties": false }, "McpUiMessageRequest": { @@ -1766,10 +1672,7 @@ "type": "array", "items": { "type": "string", - "enum": [ - "user", - "assistant" - ] + "enum": ["user", "assistant"] } }, "priority": { @@ -1793,10 +1696,7 @@ "additionalProperties": {} } }, - "required": [ - "type", - "text" - ], + "required": ["type", "text"], "additionalProperties": false }, { @@ -1819,10 +1719,7 @@ "type": "array", "items": { "type": "string", - "enum": [ - "user", - "assistant" - ] + "enum": ["user", "assistant"] } }, "priority": { @@ -1846,11 +1743,7 @@ "additionalProperties": {} } }, - "required": [ - "type", - "data", - "mimeType" - ], + "required": ["type", "data", "mimeType"], "additionalProperties": false }, { @@ -1873,10 +1766,7 @@ "type": "array", "items": { "type": "string", - "enum": [ - "user", - "assistant" - ] + "enum": ["user", "assistant"] } }, "priority": { @@ -1900,11 +1790,7 @@ "additionalProperties": {} } }, - "required": [ - "type", - "data", - "mimeType" - ], + "required": ["type", "data", "mimeType"], "additionalProperties": false }, { @@ -1934,9 +1820,7 @@ } } }, - "required": [ - "src" - ], + "required": ["src"], "additionalProperties": false } }, @@ -1956,10 +1840,7 @@ "type": "array", "items": { "type": "string", - "enum": [ - "user", - "assistant" - ] + "enum": ["user", "assistant"] } }, "priority": { @@ -1985,11 +1866,7 @@ "const": "resource_link" } }, - "required": [ - "name", - "uri", - "type" - ], + "required": ["name", "uri", "type"], "additionalProperties": false }, { @@ -2021,10 +1898,7 @@ "type": "string" } }, - "required": [ - "uri", - "text" - ], + "required": ["uri", "text"], "additionalProperties": false }, { @@ -2047,10 +1921,7 @@ "type": "string" } }, - "required": [ - "uri", - "blob" - ], + "required": ["uri", "blob"], "additionalProperties": false } ] @@ -2062,10 +1933,7 @@ "type": "array", "items": { "type": "string", - "enum": [ - "user", - "assistant" - ] + "enum": ["user", "assistant"] } }, "priority": { @@ -2089,27 +1957,18 @@ "additionalProperties": {} } }, - "required": [ - "type", - "resource" - ], + "required": ["type", "resource"], "additionalProperties": false } ] } } }, - "required": [ - "role", - "content" - ], + "required": ["role", "content"], "additionalProperties": false } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false }, "McpUiMessageResult": { @@ -2139,16 +1998,11 @@ "type": "string" } }, - "required": [ - "url" - ], + "required": ["url"], "additionalProperties": false } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false }, "McpUiOpenLinkResult": { @@ -2233,10 +2087,7 @@ "additionalProperties": false } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false }, "McpUiResourceTeardownResult": { @@ -2261,10 +2112,7 @@ "additionalProperties": false } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false }, "McpUiSandboxResourceReadyNotification": { @@ -2308,16 +2156,11 @@ "additionalProperties": false } }, - "required": [ - "html" - ], + "required": ["html"], "additionalProperties": false } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false }, "McpUiSizeChangedNotification": { @@ -2343,10 +2186,7 @@ "additionalProperties": false } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false }, "McpUiStyleVariableKey": { @@ -2696,10 +2536,7 @@ "additionalProperties": false } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false }, "McpUiToolInputPartialNotification": { @@ -2727,10 +2564,7 @@ "additionalProperties": false } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false }, "McpUiToolResultNotification": { @@ -2755,9 +2589,7 @@ "type": "string" } }, - "required": [ - "taskId" - ], + "required": ["taskId"], "additionalProperties": {} } }, @@ -2785,10 +2617,7 @@ "type": "array", "items": { "type": "string", - "enum": [ - "user", - "assistant" - ] + "enum": ["user", "assistant"] } }, "priority": { @@ -2812,10 +2641,7 @@ "additionalProperties": {} } }, - "required": [ - "type", - "text" - ], + "required": ["type", "text"], "additionalProperties": false }, { @@ -2838,10 +2664,7 @@ "type": "array", "items": { "type": "string", - "enum": [ - "user", - "assistant" - ] + "enum": ["user", "assistant"] } }, "priority": { @@ -2865,11 +2688,7 @@ "additionalProperties": {} } }, - "required": [ - "type", - "data", - "mimeType" - ], + "required": ["type", "data", "mimeType"], "additionalProperties": false }, { @@ -2892,10 +2711,7 @@ "type": "array", "items": { "type": "string", - "enum": [ - "user", - "assistant" - ] + "enum": ["user", "assistant"] } }, "priority": { @@ -2919,11 +2735,7 @@ "additionalProperties": {} } }, - "required": [ - "type", - "data", - "mimeType" - ], + "required": ["type", "data", "mimeType"], "additionalProperties": false }, { @@ -2953,9 +2765,7 @@ } } }, - "required": [ - "src" - ], + "required": ["src"], "additionalProperties": false } }, @@ -2975,10 +2785,7 @@ "type": "array", "items": { "type": "string", - "enum": [ - "user", - "assistant" - ] + "enum": ["user", "assistant"] } }, "priority": { @@ -3004,11 +2811,7 @@ "const": "resource_link" } }, - "required": [ - "name", - "uri", - "type" - ], + "required": ["name", "uri", "type"], "additionalProperties": false }, { @@ -3040,10 +2843,7 @@ "type": "string" } }, - "required": [ - "uri", - "text" - ], + "required": ["uri", "text"], "additionalProperties": false }, { @@ -3066,10 +2866,7 @@ "type": "string" } }, - "required": [ - "uri", - "blob" - ], + "required": ["uri", "blob"], "additionalProperties": false } ] @@ -3081,10 +2878,7 @@ "type": "array", "items": { "type": "string", - "enum": [ - "user", - "assistant" - ] + "enum": ["user", "assistant"] } }, "priority": { @@ -3108,10 +2902,7 @@ "additionalProperties": {} } }, - "required": [ - "type", - "resource" - ], + "required": ["type", "resource"], "additionalProperties": false } ] @@ -3128,16 +2919,11 @@ "type": "boolean" } }, - "required": [ - "content" - ], + "required": ["content"], "additionalProperties": {} } }, - "required": [ - "method", - "params" - ], + "required": ["method", "params"], "additionalProperties": false } } diff --git a/src/generated/schema.test.ts b/src/generated/schema.test.ts index 17016a39..473440c9 100644 --- a/src/generated/schema.test.ts +++ b/src/generated/schema.test.ts @@ -11,103 +11,225 @@ function expectType(_: T) { /* noop */ } -export type McpUiThemeSchemaInferredType = z.infer; - -export type McpUiDisplayModeSchemaInferredType = z.infer; - -export type McpUiStyleVariableKeySchemaInferredType = z.infer; - -export type McpUiStylesSchemaInferredType = z.infer; - -export type McpUiOpenLinkRequestSchemaInferredType = z.infer; - -export type McpUiOpenLinkResultSchemaInferredType = z.infer; - -export type McpUiMessageResultSchemaInferredType = z.infer; - -export type McpUiSandboxProxyReadyNotificationSchemaInferredType = z.infer; - -export type McpUiSandboxResourceReadyNotificationSchemaInferredType = z.infer; - -export type McpUiSizeChangedNotificationSchemaInferredType = z.infer; - -export type McpUiToolInputNotificationSchemaInferredType = z.infer; - -export type McpUiToolInputPartialNotificationSchemaInferredType = z.infer; - -export type McpUiResourceTeardownRequestSchemaInferredType = z.infer; - -export type McpUiResourceTeardownResultSchemaInferredType = z.infer; - -export type McpUiHostCapabilitiesSchemaInferredType = z.infer; - -export type McpUiAppCapabilitiesSchemaInferredType = z.infer; - -export type McpUiInitializedNotificationSchemaInferredType = z.infer; - -export type McpUiResourceCspSchemaInferredType = z.infer; - -export type McpUiResourceMetaSchemaInferredType = z.infer; - -export type McpUiMessageRequestSchemaInferredType = z.infer; - -export type McpUiToolResultNotificationSchemaInferredType = z.infer; - -export type McpUiHostContextSchemaInferredType = z.infer; - -export type McpUiHostContextChangedNotificationSchemaInferredType = z.infer; - -export type McpUiInitializeRequestSchemaInferredType = z.infer; - -export type McpUiInitializeResultSchemaInferredType = z.infer; - -expectType({} as McpUiThemeSchemaInferredType) -expectType({} as spec.McpUiTheme) -expectType({} as McpUiDisplayModeSchemaInferredType) -expectType({} as spec.McpUiDisplayMode) -expectType({} as McpUiStyleVariableKeySchemaInferredType) -expectType({} as spec.McpUiStyleVariableKey) -expectType({} as McpUiStylesSchemaInferredType) -expectType({} as spec.McpUiStyles) -expectType({} as McpUiOpenLinkRequestSchemaInferredType) -expectType({} as spec.McpUiOpenLinkRequest) -expectType({} as McpUiOpenLinkResultSchemaInferredType) -expectType({} as spec.McpUiOpenLinkResult) -expectType({} as McpUiMessageResultSchemaInferredType) -expectType({} as spec.McpUiMessageResult) -expectType({} as McpUiSandboxProxyReadyNotificationSchemaInferredType) -expectType({} as spec.McpUiSandboxProxyReadyNotification) -expectType({} as McpUiSandboxResourceReadyNotificationSchemaInferredType) -expectType({} as spec.McpUiSandboxResourceReadyNotification) -expectType({} as McpUiSizeChangedNotificationSchemaInferredType) -expectType({} as spec.McpUiSizeChangedNotification) -expectType({} as McpUiToolInputNotificationSchemaInferredType) -expectType({} as spec.McpUiToolInputNotification) -expectType({} as McpUiToolInputPartialNotificationSchemaInferredType) -expectType({} as spec.McpUiToolInputPartialNotification) -expectType({} as McpUiResourceTeardownRequestSchemaInferredType) -expectType({} as spec.McpUiResourceTeardownRequest) -expectType({} as McpUiResourceTeardownResultSchemaInferredType) -expectType({} as spec.McpUiResourceTeardownResult) -expectType({} as McpUiHostCapabilitiesSchemaInferredType) -expectType({} as spec.McpUiHostCapabilities) -expectType({} as McpUiAppCapabilitiesSchemaInferredType) -expectType({} as spec.McpUiAppCapabilities) -expectType({} as McpUiInitializedNotificationSchemaInferredType) -expectType({} as spec.McpUiInitializedNotification) -expectType({} as McpUiResourceCspSchemaInferredType) -expectType({} as spec.McpUiResourceCsp) -expectType({} as McpUiResourceMetaSchemaInferredType) -expectType({} as spec.McpUiResourceMeta) -expectType({} as McpUiMessageRequestSchemaInferredType) -expectType({} as spec.McpUiMessageRequest) -expectType({} as McpUiToolResultNotificationSchemaInferredType) -expectType({} as spec.McpUiToolResultNotification) -expectType({} as McpUiHostContextSchemaInferredType) -expectType({} as spec.McpUiHostContext) -expectType({} as McpUiHostContextChangedNotificationSchemaInferredType) -expectType({} as spec.McpUiHostContextChangedNotification) -expectType({} as McpUiInitializeRequestSchemaInferredType) -expectType({} as spec.McpUiInitializeRequest) -expectType({} as McpUiInitializeResultSchemaInferredType) -expectType({} as spec.McpUiInitializeResult) +export type McpUiThemeSchemaInferredType = z.infer< + typeof generated.McpUiThemeSchema +>; + +export type McpUiDisplayModeSchemaInferredType = z.infer< + typeof generated.McpUiDisplayModeSchema +>; + +export type McpUiStyleVariableKeySchemaInferredType = z.infer< + typeof generated.McpUiStyleVariableKeySchema +>; + +export type McpUiStylesSchemaInferredType = z.infer< + typeof generated.McpUiStylesSchema +>; + +export type McpUiOpenLinkRequestSchemaInferredType = z.infer< + typeof generated.McpUiOpenLinkRequestSchema +>; + +export type McpUiOpenLinkResultSchemaInferredType = z.infer< + typeof generated.McpUiOpenLinkResultSchema +>; + +export type McpUiMessageResultSchemaInferredType = z.infer< + typeof generated.McpUiMessageResultSchema +>; + +export type McpUiSandboxProxyReadyNotificationSchemaInferredType = z.infer< + typeof generated.McpUiSandboxProxyReadyNotificationSchema +>; + +export type McpUiSandboxResourceReadyNotificationSchemaInferredType = z.infer< + typeof generated.McpUiSandboxResourceReadyNotificationSchema +>; + +export type McpUiSizeChangedNotificationSchemaInferredType = z.infer< + typeof generated.McpUiSizeChangedNotificationSchema +>; + +export type McpUiToolInputNotificationSchemaInferredType = z.infer< + typeof generated.McpUiToolInputNotificationSchema +>; + +export type McpUiToolInputPartialNotificationSchemaInferredType = z.infer< + typeof generated.McpUiToolInputPartialNotificationSchema +>; + +export type McpUiResourceTeardownRequestSchemaInferredType = z.infer< + typeof generated.McpUiResourceTeardownRequestSchema +>; + +export type McpUiResourceTeardownResultSchemaInferredType = z.infer< + typeof generated.McpUiResourceTeardownResultSchema +>; + +export type McpUiHostCapabilitiesSchemaInferredType = z.infer< + typeof generated.McpUiHostCapabilitiesSchema +>; + +export type McpUiAppCapabilitiesSchemaInferredType = z.infer< + typeof generated.McpUiAppCapabilitiesSchema +>; + +export type McpUiInitializedNotificationSchemaInferredType = z.infer< + typeof generated.McpUiInitializedNotificationSchema +>; + +export type McpUiResourceCspSchemaInferredType = z.infer< + typeof generated.McpUiResourceCspSchema +>; + +export type McpUiResourceMetaSchemaInferredType = z.infer< + typeof generated.McpUiResourceMetaSchema +>; + +export type McpUiMessageRequestSchemaInferredType = z.infer< + typeof generated.McpUiMessageRequestSchema +>; + +export type McpUiToolResultNotificationSchemaInferredType = z.infer< + typeof generated.McpUiToolResultNotificationSchema +>; + +export type McpUiHostContextSchemaInferredType = z.infer< + typeof generated.McpUiHostContextSchema +>; + +export type McpUiHostContextChangedNotificationSchemaInferredType = z.infer< + typeof generated.McpUiHostContextChangedNotificationSchema +>; + +export type McpUiInitializeRequestSchemaInferredType = z.infer< + typeof generated.McpUiInitializeRequestSchema +>; + +export type McpUiInitializeResultSchemaInferredType = z.infer< + typeof generated.McpUiInitializeResultSchema +>; + +expectType({} as McpUiThemeSchemaInferredType); +expectType({} as spec.McpUiTheme); +expectType({} as McpUiDisplayModeSchemaInferredType); +expectType({} as spec.McpUiDisplayMode); +expectType( + {} as McpUiStyleVariableKeySchemaInferredType, +); +expectType( + {} as spec.McpUiStyleVariableKey, +); +expectType({} as McpUiStylesSchemaInferredType); +expectType({} as spec.McpUiStyles); +expectType( + {} as McpUiOpenLinkRequestSchemaInferredType, +); +expectType( + {} as spec.McpUiOpenLinkRequest, +); +expectType( + {} as McpUiOpenLinkResultSchemaInferredType, +); +expectType( + {} as spec.McpUiOpenLinkResult, +); +expectType({} as McpUiMessageResultSchemaInferredType); +expectType({} as spec.McpUiMessageResult); +expectType( + {} as McpUiSandboxProxyReadyNotificationSchemaInferredType, +); +expectType( + {} as spec.McpUiSandboxProxyReadyNotification, +); +expectType( + {} as McpUiSandboxResourceReadyNotificationSchemaInferredType, +); +expectType( + {} as spec.McpUiSandboxResourceReadyNotification, +); +expectType( + {} as McpUiSizeChangedNotificationSchemaInferredType, +); +expectType( + {} as spec.McpUiSizeChangedNotification, +); +expectType( + {} as McpUiToolInputNotificationSchemaInferredType, +); +expectType( + {} as spec.McpUiToolInputNotification, +); +expectType( + {} as McpUiToolInputPartialNotificationSchemaInferredType, +); +expectType( + {} as spec.McpUiToolInputPartialNotification, +); +expectType( + {} as McpUiResourceTeardownRequestSchemaInferredType, +); +expectType( + {} as spec.McpUiResourceTeardownRequest, +); +expectType( + {} as McpUiResourceTeardownResultSchemaInferredType, +); +expectType( + {} as spec.McpUiResourceTeardownResult, +); +expectType( + {} as McpUiHostCapabilitiesSchemaInferredType, +); +expectType( + {} as spec.McpUiHostCapabilities, +); +expectType( + {} as McpUiAppCapabilitiesSchemaInferredType, +); +expectType( + {} as spec.McpUiAppCapabilities, +); +expectType( + {} as McpUiInitializedNotificationSchemaInferredType, +); +expectType( + {} as spec.McpUiInitializedNotification, +); +expectType({} as McpUiResourceCspSchemaInferredType); +expectType({} as spec.McpUiResourceCsp); +expectType({} as McpUiResourceMetaSchemaInferredType); +expectType({} as spec.McpUiResourceMeta); +expectType( + {} as McpUiMessageRequestSchemaInferredType, +); +expectType( + {} as spec.McpUiMessageRequest, +); +expectType( + {} as McpUiToolResultNotificationSchemaInferredType, +); +expectType( + {} as spec.McpUiToolResultNotification, +); +expectType({} as McpUiHostContextSchemaInferredType); +expectType({} as spec.McpUiHostContext); +expectType( + {} as McpUiHostContextChangedNotificationSchemaInferredType, +); +expectType( + {} as spec.McpUiHostContextChangedNotification, +); +expectType( + {} as McpUiInitializeRequestSchemaInferredType, +); +expectType( + {} as spec.McpUiInitializeRequest, +); +expectType( + {} as McpUiInitializeResultSchemaInferredType, +); +expectType( + {} as spec.McpUiInitializeResult, +); diff --git a/src/generated/schema.ts b/src/generated/schema.ts index 5024d02c..eac0a93e 100644 --- a/src/generated/schema.ts +++ b/src/generated/schema.ts @@ -13,33 +13,83 @@ import { /** * @description Color theme preference for the host environment. */ -export const McpUiThemeSchema = z.union([z.literal("light"), z.literal("dark")]).describe("Color theme preference for the host environment."); +export const McpUiThemeSchema = z + .union([z.literal("light"), z.literal("dark")]) + .describe("Color theme preference for the host environment."); /** * @description Display mode for UI presentation. */ -export const McpUiDisplayModeSchema = z.union([z.literal("inline"), z.literal("fullscreen"), z.literal("pip")]).describe("Display mode for UI presentation."); +export const McpUiDisplayModeSchema = z + .union([z.literal("inline"), z.literal("fullscreen"), z.literal("pip")]) + .describe("Display mode for UI presentation."); /** * @description CSS variable keys available to MCP apps for theming. */ -export const McpUiStyleVariableKeySchema = z.union([z.literal("--color-background-primary"), z.literal("--color-background-secondary"), z.literal("--color-background-tertiary"), z.literal("--color-background-inverted"), z.literal("--color-text-primary"), z.literal("--color-text-secondary"), z.literal("--color-text-tertiary"), z.literal("--color-text-inverted"), z.literal("--color-icon-primary"), z.literal("--color-icon-secondary"), z.literal("--color-icon-tertiary"), z.literal("--color-icon-inverted"), z.literal("--color-border-primary"), z.literal("--color-border-secondary"), z.literal("--color-accent-info"), z.literal("--color-accent-danger"), z.literal("--color-accent-success"), z.literal("--color-accent-warning"), z.literal("--font-family-sans"), z.literal("--font-size-heading"), z.literal("--font-size-body"), z.literal("--font-size-caption"), z.literal("--font-weight-regular"), z.literal("--font-weight-emphasized"), z.literal("--font-leading-regular"), z.literal("--font-leading-tight"), z.literal("--font-style-heading"), z.literal("--font-style-body"), z.literal("--font-style-body-emphasized"), z.literal("--font-style-caption"), z.literal("--font-style-caption-emphasized"), z.literal("--border-radius-small"), z.literal("--border-radius-medium"), z.literal("--border-radius-large"), z.literal("--border-radius-full"), z.literal("--border-width-regular")]).describe("CSS variable keys available to MCP apps for theming."); +export const McpUiStyleVariableKeySchema = z + .union([ + z.literal("--color-background-primary"), + z.literal("--color-background-secondary"), + z.literal("--color-background-tertiary"), + z.literal("--color-background-inverted"), + z.literal("--color-text-primary"), + z.literal("--color-text-secondary"), + z.literal("--color-text-tertiary"), + z.literal("--color-text-inverted"), + z.literal("--color-icon-primary"), + z.literal("--color-icon-secondary"), + z.literal("--color-icon-tertiary"), + z.literal("--color-icon-inverted"), + z.literal("--color-border-primary"), + z.literal("--color-border-secondary"), + z.literal("--color-accent-info"), + z.literal("--color-accent-danger"), + z.literal("--color-accent-success"), + z.literal("--color-accent-warning"), + z.literal("--font-family-sans"), + z.literal("--font-size-heading"), + z.literal("--font-size-body"), + z.literal("--font-size-caption"), + z.literal("--font-weight-regular"), + z.literal("--font-weight-emphasized"), + z.literal("--font-leading-regular"), + z.literal("--font-leading-tight"), + z.literal("--font-style-heading"), + z.literal("--font-style-body"), + z.literal("--font-style-body-emphasized"), + z.literal("--font-style-caption"), + z.literal("--font-style-caption-emphasized"), + z.literal("--border-radius-small"), + z.literal("--border-radius-medium"), + z.literal("--border-radius-large"), + z.literal("--border-radius-full"), + z.literal("--border-width-regular"), + ]) + .describe("CSS variable keys available to MCP apps for theming."); /** * @description Style variables for theming MCP apps. */ -export const McpUiStylesSchema = z.record(McpUiStyleVariableKeySchema.describe("Style variables for theming MCP apps."), z.string().describe("Style variables for theming MCP apps.")).describe("Style variables for theming MCP apps."); +export const McpUiStylesSchema = z + .record( + McpUiStyleVariableKeySchema.describe( + "Style variables for theming MCP apps.", + ), + z.string().describe("Style variables for theming MCP apps."), + ) + .describe("Style variables for theming MCP apps."); /** * @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 const McpUiOpenLinkRequestSchema = z.object({ - method: z.literal("ui/open-link"), - params: z.object({ - /** @description URL to open in the host's browser */ - url: z.string().describe("URL to open in the host's browser") - }) + method: z.literal("ui/open-link"), + params: z.object({ + /** @description URL to open in the host's browser */ + url: z.string().describe("URL to open in the host's browser"), + }), }); /** @@ -47,8 +97,13 @@ export const McpUiOpenLinkRequestSchema = z.object({ * @see {@link McpUiOpenLinkRequest} */ export const McpUiOpenLinkResultSchema = z.looseObject({ - /** @description True if the host failed to open the URL (e.g., due to security policy). */ - isError: z.boolean().optional().describe("True if the host failed to open the URL (e.g., due to security policy).") + /** @description True if the host failed to open the URL (e.g., due to security policy). */ + isError: z + .boolean() + .optional() + .describe( + "True if the host failed to open the URL (e.g., due to security policy).", + ), }); /** @@ -56,8 +111,11 @@ export const McpUiOpenLinkResultSchema = z.looseObject({ * @see {@link McpUiMessageRequest} */ export const McpUiMessageResultSchema = z.looseObject({ - /** @description True if the host rejected or failed to deliver the message. */ - isError: z.boolean().optional().describe("True if the host rejected or failed to deliver the message.") + /** @description True if the host rejected or failed to deliver the message. */ + isError: z + .boolean() + .optional() + .describe("True if the host rejected or failed to deliver the message."), }); /** @@ -66,8 +124,8 @@ export const McpUiMessageResultSchema = z.looseObject({ * @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy */ export const McpUiSandboxProxyReadyNotificationSchema = z.object({ - method: z.literal("ui/notifications/sandbox-proxy-ready"), - params: z.object({}) + method: z.literal("ui/notifications/sandbox-proxy-ready"), + params: z.object({}), }); /** @@ -76,20 +134,34 @@ export const McpUiSandboxProxyReadyNotificationSchema = z.object({ * @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy */ export const McpUiSandboxResourceReadyNotificationSchema = z.object({ - method: z.literal("ui/notifications/sandbox-resource-ready"), - params: z.object({ - /** @description HTML content to load into the inner iframe. */ - html: z.string().describe("HTML content to load into the inner iframe."), - /** @description Optional override for the inner iframe's sandbox attribute. */ - sandbox: z.string().optional().describe("Optional override for the inner iframe's sandbox attribute."), - /** @description CSP configuration from resource metadata. */ - csp: z.object({ - /** @description Origins for network requests (fetch/XHR/WebSocket). */ - connectDomains: z.array(z.string()).optional().describe("Origins for network requests (fetch/XHR/WebSocket)."), - /** @description Origins for static resources (scripts, images, styles, fonts). */ - resourceDomains: z.array(z.string()).optional().describe("Origins for static resources (scripts, images, styles, fonts).") - }).optional().describe("CSP configuration from resource metadata.") - }) + method: z.literal("ui/notifications/sandbox-resource-ready"), + params: z.object({ + /** @description HTML content to load into the inner iframe. */ + html: z.string().describe("HTML content to load into the inner iframe."), + /** @description Optional override for the inner iframe's sandbox attribute. */ + sandbox: z + .string() + .optional() + .describe("Optional override for the inner iframe's sandbox attribute."), + /** @description CSP configuration from resource metadata. */ + csp: z + .object({ + /** @description Origins for network requests (fetch/XHR/WebSocket). */ + connectDomains: z + .array(z.string()) + .optional() + .describe("Origins for network requests (fetch/XHR/WebSocket)."), + /** @description Origins for static resources (scripts, images, styles, fonts). */ + resourceDomains: z + .array(z.string()) + .optional() + .describe( + "Origins for static resources (scripts, images, styles, fonts).", + ), + }) + .optional() + .describe("CSP configuration from resource metadata."), + }), }); /** @@ -97,35 +169,51 @@ export const McpUiSandboxResourceReadyNotificationSchema = z.object({ * @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI */ export const McpUiSizeChangedNotificationSchema = z.object({ - method: z.literal("ui/notifications/size-changed"), - params: z.object({ - /** @description New width in pixels. */ - width: z.number().optional().describe("New width in pixels."), - /** @description New height in pixels. */ - height: z.number().optional().describe("New height in pixels.") - }) + method: z.literal("ui/notifications/size-changed"), + params: z.object({ + /** @description New width in pixels. */ + width: z.number().optional().describe("New width in pixels."), + /** @description New height in pixels. */ + height: z.number().optional().describe("New height in pixels."), + }), }); /** * @description Notification containing complete tool arguments (Host -> Guest UI). */ export const McpUiToolInputNotificationSchema = z.object({ - method: z.literal("ui/notifications/tool-input"), - params: z.object({ - /** @description Complete tool call arguments as key-value pairs. */ - arguments: z.record(z.string(), z.unknown().describe("Complete tool call arguments as key-value pairs.")).optional().describe("Complete tool call arguments as key-value pairs.") - }) + method: z.literal("ui/notifications/tool-input"), + params: z.object({ + /** @description Complete tool call arguments as key-value pairs. */ + arguments: z + .record( + z.string(), + z + .unknown() + .describe("Complete tool call arguments as key-value pairs."), + ) + .optional() + .describe("Complete tool call arguments as key-value pairs."), + }), }); /** * @description Notification containing partial/streaming tool arguments (Host -> Guest UI). */ export const McpUiToolInputPartialNotificationSchema = z.object({ - method: z.literal("ui/notifications/tool-input-partial"), - params: z.object({ - /** @description Partial tool call arguments (incomplete, may change). */ - arguments: z.record(z.string(), z.unknown().describe("Partial tool call arguments (incomplete, may change).")).optional().describe("Partial tool call arguments (incomplete, may change).") - }) + method: z.literal("ui/notifications/tool-input-partial"), + params: z.object({ + /** @description Partial tool call arguments (incomplete, may change). */ + arguments: z + .record( + z.string(), + z + .unknown() + .describe("Partial tool call arguments (incomplete, may change)."), + ) + .optional() + .describe("Partial tool call arguments (incomplete, may change)."), + }), }); /** @@ -133,37 +221,58 @@ export const McpUiToolInputPartialNotificationSchema = z.object({ * @see {@link app-bridge.AppBridge.sendResourceTeardown} for the host method that sends this */ export const McpUiResourceTeardownRequestSchema = z.object({ - method: z.literal("ui/resource-teardown"), - params: z.object({}) + method: z.literal("ui/resource-teardown"), + params: z.object({}), }); /** * @description Result from graceful shutdown request. * @see {@link McpUiResourceTeardownRequest} */ -export const McpUiResourceTeardownResultSchema = z.record(z.string(), z.unknown()); +export const McpUiResourceTeardownResultSchema = z.record( + z.string(), + z.unknown(), +); /** * @description Capabilities supported by the host application. * @see {@link McpUiInitializeResult} for the initialization result that includes these capabilities */ export const McpUiHostCapabilitiesSchema = z.object({ - /** @description Experimental features (structure TBD). */ - experimental: z.object({}).optional().describe("Experimental features (structure TBD)."), - /** @description Host supports opening external URLs. */ - openLinks: z.object({}).optional().describe("Host supports opening external URLs."), - /** @description Host can proxy tool calls to the MCP server. */ - serverTools: z.object({ - /** @description Host supports tools/list_changed notifications. */ - listChanged: z.boolean().optional().describe("Host supports tools/list_changed notifications.") - }).optional().describe("Host can proxy tool calls to the MCP server."), - /** @description Host can proxy resource reads to the MCP server. */ - serverResources: z.object({ - /** @description Host supports resources/list_changed notifications. */ - listChanged: z.boolean().optional().describe("Host supports resources/list_changed notifications.") - }).optional().describe("Host can proxy resource reads to the MCP server."), - /** @description Host accepts log messages. */ - logging: z.object({}).optional().describe("Host accepts log messages.") + /** @description Experimental features (structure TBD). */ + experimental: z + .object({}) + .optional() + .describe("Experimental features (structure TBD)."), + /** @description Host supports opening external URLs. */ + openLinks: z + .object({}) + .optional() + .describe("Host supports opening external URLs."), + /** @description Host can proxy tool calls to the MCP server. */ + serverTools: z + .object({ + /** @description Host supports tools/list_changed notifications. */ + listChanged: z + .boolean() + .optional() + .describe("Host supports tools/list_changed notifications."), + }) + .optional() + .describe("Host can proxy tool calls to the MCP server."), + /** @description Host can proxy resource reads to the MCP server. */ + serverResources: z + .object({ + /** @description Host supports resources/list_changed notifications. */ + listChanged: z + .boolean() + .optional() + .describe("Host supports resources/list_changed notifications."), + }) + .optional() + .describe("Host can proxy resource reads to the MCP server."), + /** @description Host accepts log messages. */ + logging: z.object({}).optional().describe("Host accepts log messages."), }); /** @@ -171,13 +280,22 @@ export const McpUiHostCapabilitiesSchema = z.object({ * @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities */ export const McpUiAppCapabilitiesSchema = z.object({ - /** @description Experimental features (structure TBD). */ - experimental: z.object({}).optional().describe("Experimental features (structure TBD)."), - /** @description App exposes MCP-style tools that the host can call. */ - tools: z.object({ - /** @description App supports tools/list_changed notifications. */ - listChanged: z.boolean().optional().describe("App supports tools/list_changed notifications.") - }).optional().describe("App exposes MCP-style tools that the host can call.") + /** @description Experimental features (structure TBD). */ + experimental: z + .object({}) + .optional() + .describe("Experimental features (structure TBD)."), + /** @description App exposes MCP-style tools that the host can call. */ + tools: z + .object({ + /** @description App supports tools/list_changed notifications. */ + listChanged: z + .boolean() + .optional() + .describe("App supports tools/list_changed notifications."), + }) + .optional() + .describe("App exposes MCP-style tools that the host can call."), }); /** @@ -185,116 +303,172 @@ export const McpUiAppCapabilitiesSchema = z.object({ * @see {@link app.App.connect} for the method that sends this notification */ export const McpUiInitializedNotificationSchema = z.object({ - method: z.literal("ui/notifications/initialized"), - params: z.object({}).optional() + method: z.literal("ui/notifications/initialized"), + params: z.object({}).optional(), }); /** * @description Content Security Policy configuration for UI resources. */ export const McpUiResourceCspSchema = z.object({ - /** @description Origins for network requests (fetch/XHR/WebSocket). */ - connectDomains: z.array(z.string()).optional().describe("Origins for network requests (fetch/XHR/WebSocket)."), - /** @description Origins for static resources (scripts, images, styles, fonts). */ - resourceDomains: z.array(z.string()).optional().describe("Origins for static resources (scripts, images, styles, fonts).") + /** @description Origins for network requests (fetch/XHR/WebSocket). */ + connectDomains: z + .array(z.string()) + .optional() + .describe("Origins for network requests (fetch/XHR/WebSocket)."), + /** @description Origins for static resources (scripts, images, styles, fonts). */ + resourceDomains: z + .array(z.string()) + .optional() + .describe("Origins for static resources (scripts, images, styles, fonts)."), }); /** * @description UI Resource metadata for security and rendering configuration. */ export const McpUiResourceMetaSchema = z.object({ - /** @description Content Security Policy configuration. */ - csp: McpUiResourceCspSchema.optional().describe("Content Security Policy configuration."), - /** @description Dedicated origin for widget sandbox. */ - domain: z.string().optional().describe("Dedicated origin for widget sandbox."), - /** @description Visual boundary preference - true if UI prefers a visible border. */ - prefersBorder: z.boolean().optional().describe("Visual boundary preference - true if UI prefers a visible border.") + /** @description Content Security Policy configuration. */ + csp: McpUiResourceCspSchema.optional().describe( + "Content Security Policy configuration.", + ), + /** @description Dedicated origin for widget sandbox. */ + domain: z + .string() + .optional() + .describe("Dedicated origin for widget sandbox."), + /** @description Visual boundary preference - true if UI prefers a visible border. */ + prefersBorder: z + .boolean() + .optional() + .describe( + "Visual boundary preference - true if UI prefers a visible border.", + ), }); - - - - - /** * @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 const McpUiMessageRequestSchema = z.object({ - method: z.literal("ui/message"), - params: z.object({ - /** @description Message role, currently only "user" is supported. */ - role: z.literal("user").describe("Message role, currently only \"user\" is supported."), - /** @description Message content blocks (text, image, etc.). */ - content: z.array(ContentBlockSchema).describe("Message content blocks (text, image, etc.).") - }) + method: z.literal("ui/message"), + params: z.object({ + /** @description Message role, currently only "user" is supported. */ + role: z + .literal("user") + .describe('Message role, currently only "user" is supported.'), + /** @description Message content blocks (text, image, etc.). */ + content: z + .array(ContentBlockSchema) + .describe("Message content blocks (text, image, etc.)."), + }), }); /** * @description Notification containing tool execution result (Host -> Guest UI). */ export const McpUiToolResultNotificationSchema = z.object({ - method: z.literal("ui/notifications/tool-result"), - /** @description Standard MCP tool execution result. */ - params: CallToolResultSchema.describe("Standard MCP tool execution result.") + method: z.literal("ui/notifications/tool-result"), + /** @description Standard MCP tool execution result. */ + params: CallToolResultSchema.describe("Standard MCP tool execution result."), }); /** * @description Rich context about the host environment provided to Guest UIs. */ export const McpUiHostContextSchema = z.object({ - /** @description Metadata of the tool call that instantiated this App. */ - toolInfo: z.object({ - /** @description JSON-RPC id of the tools/call request. */ - id: RequestIdSchema.describe("JSON-RPC id of the tools/call request."), - /** @description Tool definition including name, inputSchema, etc. */ - tool: ToolSchema.describe("Tool definition including name, inputSchema, etc.") - }).optional().describe("Metadata of the tool call that instantiated this App."), - /** @description Current color theme preference. */ - theme: McpUiThemeSchema.optional().describe("Current color theme preference."), - /** @description CSS variables for theming the app. */ - styles: McpUiStylesSchema.optional().describe("CSS variables for theming the app."), - /** @description How the UI is currently displayed. */ - displayMode: McpUiDisplayModeSchema.optional().describe("How the UI is currently displayed."), - /** @description Display modes the host supports. */ - availableDisplayModes: z.array(z.string()).optional().describe("Display modes the host supports."), - /** @description Current and maximum dimensions available to the UI. */ - viewport: z.object({ - /** @description Current viewport width in pixels. */ - width: z.number().describe("Current viewport width in pixels."), - /** @description Current viewport height in pixels. */ - height: z.number().describe("Current viewport height in pixels."), - /** @description Maximum available height in pixels (if constrained). */ - maxHeight: z.number().optional().describe("Maximum available height in pixels (if constrained)."), - /** @description Maximum available width in pixels (if constrained). */ - maxWidth: z.number().optional().describe("Maximum available width in pixels (if constrained).") - }).optional().describe("Current and maximum dimensions available to the UI."), - /** @description User's language and region preference in BCP 47 format. */ - locale: z.string().optional().describe("User's language and region preference in BCP 47 format."), - /** @description User's timezone in IANA format. */ - timeZone: z.string().optional().describe("User's timezone in IANA format."), - /** @description Host application identifier. */ - userAgent: z.string().optional().describe("Host application identifier."), - /** @description Platform type for responsive design decisions. */ - platform: z.union([z.literal("web"), z.literal("desktop"), z.literal("mobile")]).optional().describe("Platform type for responsive design decisions."), - /** @description Device input capabilities. */ - deviceCapabilities: z.object({ - /** @description Whether the device supports touch input. */ - touch: z.boolean().optional().describe("Whether the device supports touch input."), - /** @description Whether the device supports hover interactions. */ - hover: z.boolean().optional().describe("Whether the device supports hover interactions.") - }).optional().describe("Device input capabilities."), - /** @description Mobile safe area boundaries in pixels. */ - safeAreaInsets: z.object({ - /** @description Top safe area inset in pixels. */ - top: z.number().describe("Top safe area inset in pixels."), - /** @description Right safe area inset in pixels. */ - right: z.number().describe("Right safe area inset in pixels."), - /** @description Bottom safe area inset in pixels. */ - bottom: z.number().describe("Bottom safe area inset in pixels."), - /** @description Left safe area inset in pixels. */ - left: z.number().describe("Left safe area inset in pixels.") - }).optional().describe("Mobile safe area boundaries in pixels.") + /** @description Metadata of the tool call that instantiated this App. */ + toolInfo: z + .object({ + /** @description JSON-RPC id of the tools/call request. */ + id: RequestIdSchema.describe("JSON-RPC id of the tools/call request."), + /** @description Tool definition including name, inputSchema, etc. */ + tool: ToolSchema.describe( + "Tool definition including name, inputSchema, etc.", + ), + }) + .optional() + .describe("Metadata of the tool call that instantiated this App."), + /** @description Current color theme preference. */ + theme: McpUiThemeSchema.optional().describe( + "Current color theme preference.", + ), + /** @description CSS variables for theming the app. */ + styles: McpUiStylesSchema.optional().describe( + "CSS variables for theming the app.", + ), + /** @description How the UI is currently displayed. */ + displayMode: McpUiDisplayModeSchema.optional().describe( + "How the UI is currently displayed.", + ), + /** @description Display modes the host supports. */ + availableDisplayModes: z + .array(z.string()) + .optional() + .describe("Display modes the host supports."), + /** @description Current and maximum dimensions available to the UI. */ + viewport: z + .object({ + /** @description Current viewport width in pixels. */ + width: z.number().describe("Current viewport width in pixels."), + /** @description Current viewport height in pixels. */ + height: z.number().describe("Current viewport height in pixels."), + /** @description Maximum available height in pixels (if constrained). */ + maxHeight: z + .number() + .optional() + .describe("Maximum available height in pixels (if constrained)."), + /** @description Maximum available width in pixels (if constrained). */ + maxWidth: z + .number() + .optional() + .describe("Maximum available width in pixels (if constrained)."), + }) + .optional() + .describe("Current and maximum dimensions available to the UI."), + /** @description User's language and region preference in BCP 47 format. */ + locale: z + .string() + .optional() + .describe("User's language and region preference in BCP 47 format."), + /** @description User's timezone in IANA format. */ + timeZone: z.string().optional().describe("User's timezone in IANA format."), + /** @description Host application identifier. */ + userAgent: z.string().optional().describe("Host application identifier."), + /** @description Platform type for responsive design decisions. */ + platform: z + .union([z.literal("web"), z.literal("desktop"), z.literal("mobile")]) + .optional() + .describe("Platform type for responsive design decisions."), + /** @description Device input capabilities. */ + deviceCapabilities: z + .object({ + /** @description Whether the device supports touch input. */ + touch: z + .boolean() + .optional() + .describe("Whether the device supports touch input."), + /** @description Whether the device supports hover interactions. */ + hover: z + .boolean() + .optional() + .describe("Whether the device supports hover interactions."), + }) + .optional() + .describe("Device input capabilities."), + /** @description Mobile safe area boundaries in pixels. */ + safeAreaInsets: z + .object({ + /** @description Top safe area inset in pixels. */ + top: z.number().describe("Top safe area inset in pixels."), + /** @description Right safe area inset in pixels. */ + right: z.number().describe("Right safe area inset in pixels."), + /** @description Bottom safe area inset in pixels. */ + bottom: z.number().describe("Bottom safe area inset in pixels."), + /** @description Left safe area inset in pixels. */ + left: z.number().describe("Left safe area inset in pixels."), + }) + .optional() + .describe("Mobile safe area boundaries in pixels."), }); /** @@ -302,9 +476,11 @@ export const McpUiHostContextSchema = z.object({ * @see {@link McpUiHostContext} for the full context structure */ export const McpUiHostContextChangedNotificationSchema = z.object({ - method: z.literal("ui/notifications/host-context-changed"), - /** @description Partial context update containing only changed fields. */ - params: McpUiHostContextSchema.describe("Partial context update containing only changed fields.") + method: z.literal("ui/notifications/host-context-changed"), + /** @description Partial context update containing only changed fields. */ + params: McpUiHostContextSchema.describe( + "Partial context update containing only changed fields.", + ), }); /** @@ -312,15 +488,19 @@ export const McpUiHostContextChangedNotificationSchema = z.object({ * @see {@link app.App.connect} for the method that sends this request */ export const McpUiInitializeRequestSchema = z.object({ - method: z.literal("ui/initialize"), - params: z.object({ - /** @description App identification (name and version). */ - appInfo: ImplementationSchema.describe("App identification (name and version)."), - /** @description Features and capabilities this app provides. */ - appCapabilities: McpUiAppCapabilitiesSchema.describe("Features and capabilities this app provides."), - /** @description Protocol version this app supports. */ - protocolVersion: z.string().describe("Protocol version this app supports.") - }) + method: z.literal("ui/initialize"), + params: z.object({ + /** @description App identification (name and version). */ + appInfo: ImplementationSchema.describe( + "App identification (name and version).", + ), + /** @description Features and capabilities this app provides. */ + appCapabilities: McpUiAppCapabilitiesSchema.describe( + "Features and capabilities this app provides.", + ), + /** @description Protocol version this app supports. */ + protocolVersion: z.string().describe("Protocol version this app supports."), + }), }); /** @@ -328,12 +508,20 @@ export const McpUiInitializeRequestSchema = z.object({ * @see {@link McpUiInitializeRequest} */ export const McpUiInitializeResultSchema = z.looseObject({ - /** @description Negotiated protocol version string (e.g., "2025-11-21"). */ - protocolVersion: z.string().describe("Negotiated protocol version string (e.g., \"2025-11-21\")."), - /** @description Host application identification and version. */ - hostInfo: ImplementationSchema.describe("Host application identification and version."), - /** @description Features and capabilities provided by the host. */ - hostCapabilities: McpUiHostCapabilitiesSchema.describe("Features and capabilities provided by the host."), - /** @description Rich context about the host environment. */ - hostContext: McpUiHostContextSchema.describe("Rich context about the host environment.") + /** @description Negotiated protocol version string (e.g., "2025-11-21"). */ + protocolVersion: z + .string() + .describe('Negotiated protocol version string (e.g., "2025-11-21").'), + /** @description Host application identification and version. */ + hostInfo: ImplementationSchema.describe( + "Host application identification and version.", + ), + /** @description Features and capabilities provided by the host. */ + hostCapabilities: McpUiHostCapabilitiesSchema.describe( + "Features and capabilities provided by the host.", + ), + /** @description Rich context about the host environment. */ + hostContext: McpUiHostContextSchema.describe( + "Rich context about the host environment.", + ), }); From edbe4f58561b781ce7ccaead59451d213eac0424 Mon Sep 17 00:00:00 2001 From: Anton Pidkuiko MacBook Date: Thu, 11 Dec 2025 12:34:19 +0000 Subject: [PATCH 6/7] docs: add styles field to MCP Apps specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add styles field to HostContext interface with reference to Theming section - Add Theming section documenting 36 standardized CSS variables - Document Host/App behavior for theming including light-dark() usage - Add Design Decision #4 explaining CSS variables approach - Include JSON example showing light-dark() pattern 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- specification/draft/apps.mdx | 73 ++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/specification/draft/apps.mdx b/specification/draft/apps.mdx index 8ceae01d..e2355a2c 100644 --- a/specification/draft/apps.mdx +++ b/specification/draft/apps.mdx @@ -401,6 +401,8 @@ interface HostContext { }; /** Current color theme preference */ theme?: "light" | "dark"; + /** CSS variables for theming. See Theming section for standardized variable names. */ + styles?: Record; /** How the UI is currently displayed */ displayMode?: "inline" | "fullscreen" | "pip"; /** Display modes the host supports */ @@ -437,6 +439,8 @@ interface HostContext { All fields are optional. Hosts SHOULD provide relevant context. Guest UIs SHOULD handle missing fields gracefully. +For `styles`, apps SHOULD provide CSS fallback values (e.g., `var(--color-text-primary, #171717)`) to handle hosts that don't supply styles. + Example: ```json @@ -450,6 +454,11 @@ Example: "hostInfo": { "name": "claude-desktop", "version": "1.0.0" }, "hostContext": { "theme": "dark", + "styles": { + "--color-background-primary": "light-dark(#ffffff, #171717)", + "--color-text-primary": "light-dark(#171717, #fafafa)", + "--font-family-sans": "system-ui, sans-serif" + }, "displayMode": "inline", "viewport": { "width": 400, "height": 300 } } @@ -457,6 +466,52 @@ Example: } ``` +### Theming + +Hosts pass CSS custom properties via `HostContext.styles` for visual cohesion with the host environment. + +#### Standardized Variables + +| Category | Variables | +|----------|-----------| +| Background | `--color-background-primary`, `--color-background-secondary`, `--color-background-tertiary`, `--color-background-inverted` | +| Text | `--color-text-primary`, `--color-text-secondary`, `--color-text-tertiary`, `--color-text-inverted` | +| Icons | `--color-icon-primary`, `--color-icon-secondary`, `--color-icon-tertiary`, `--color-icon-inverted` | +| Borders | `--color-border-primary`, `--color-border-secondary` | +| Accents | `--color-accent-info`, `--color-accent-danger`, `--color-accent-success`, `--color-accent-warning` | +| Font Family | `--font-family-sans` | +| Font Sizes | `--font-size-heading`, `--font-size-body`, `--font-size-caption` | +| Font Weights | `--font-weight-regular`, `--font-weight-emphasized` | +| Line Heights | `--font-leading-regular`, `--font-leading-tight` | +| Composite Styles | `--font-style-heading`, `--font-style-body`, `--font-style-body-emphasized`, `--font-style-caption`, `--font-style-caption-emphasized` | +| Border Radius | `--border-radius-small`, `--border-radius-medium`, `--border-radius-large`, `--border-radius-full` | +| Border Width | `--border-width-regular` | + +#### Host Behavior + +- Hosts MAY provide any subset of standardized variables +- Hosts MAY use CSS `light-dark()` function for theme-aware values +- `theme` indicates the active mode; `styles` provides the concrete CSS values + +#### App Behavior + +- Apps SHOULD use fallback values for CSS variables: `var(--color-text-primary, #171717)` +- This ensures graceful degradation when hosts omit `styles` or specific variables +- When the host uses `light-dark()` values, apps MUST set `color-scheme` on their document: + ```css + :root { color-scheme: light dark; } + ``` + +Example CSS: + +```css +.container { + background: var(--color-background-primary, #ffffff); + color: var(--color-text-primary, #171717); + font: var(--font-style-body, 400 16px/1.4 system-ui); +} +``` + ### MCP Apps Specific Messages MCP Apps introduces additional JSON-RPC methods for UI-specific functionality: @@ -1046,6 +1101,24 @@ This proposal synthesizes feedback from the UI CWG and MCP-UI community, host im - **Include external URLs in MVP:** This is one of the easiest content types for servers to adopt, as it's possible to embed regular apps. However, it was deferred due to concerns around model visibility, inability to screenshot content, and review process. - **Support multiple content types:** Deferred to maintain a lean MVP. +#### 4. Host Theming via CSS Variables + +**Decision:** Provide a standardized set of CSS custom properties for visual cohesion. + +**Rationale:** + +- CSS variables are universal, framework-agnostic, and require no runtime +- Apps apply styles via `var(--name)` with fallbacks for graceful degradation +- Limited variable set (colors, typography, borders) ensures hosts can realistically provide all values +- Spacing intentionally excluded—layouts break when spacing varies from original design +- No UI component library—no single library works across all host environments + +**Alternatives considered:** + +- **Full design system:** Rejected as too prescriptive; hosts have different aesthetics +- **Inline styles in tool results:** Rejected; separating theming from data enables caching and updates +- **CSS-in-JS injection:** Rejected; framework-specific and security concerns with injected code + ### Backward Compatibility The proposal builds on the existing core protocol. There are no incompatibilities. From 854fec267a4e14c6320bf6e47cd5d5ce7b9201f4 Mon Sep 17 00:00:00 2001 From: martinalong Date: Thu, 11 Dec 2025 16:30:58 -0800 Subject: [PATCH 7/7] Suggested edits --- specification/draft/apps.mdx | 38 +++++++++++++++++------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/specification/draft/apps.mdx b/specification/draft/apps.mdx index e2355a2c..be52a791 100644 --- a/specification/draft/apps.mdx +++ b/specification/draft/apps.mdx @@ -437,10 +437,6 @@ interface HostContext { } ``` -All fields are optional. Hosts SHOULD provide relevant context. Guest UIs SHOULD handle missing fields gracefully. - -For `styles`, apps SHOULD provide CSS fallback values (e.g., `var(--color-text-primary, #171717)`) to handle hosts that don't supply styles. - Example: ```json @@ -457,7 +453,8 @@ Example: "styles": { "--color-background-primary": "light-dark(#ffffff, #171717)", "--color-text-primary": "light-dark(#171717, #fafafa)", - "--font-family-sans": "system-ui, sans-serif" + "--font-family-sans": "system-ui, sans-serif", + ... }, "displayMode": "inline", "viewport": { "width": 400, "height": 300 } @@ -468,9 +465,9 @@ Example: ### Theming -Hosts pass CSS custom properties via `HostContext.styles` for visual cohesion with the host environment. +Hosts can optionally pass CSS custom properties via `HostContext.styles` for visual cohesion with the host environment. -#### Standardized Variables +#### Current Standardized Variables | Category | Variables | |----------|-----------| @@ -489,26 +486,27 @@ Hosts pass CSS custom properties via `HostContext.styles` for visual cohesion wi #### Host Behavior -- Hosts MAY provide any subset of standardized variables -- Hosts MAY use CSS `light-dark()` function for theme-aware values -- `theme` indicates the active mode; `styles` provides the concrete CSS values +- Hosts can provide any subset of standardized variables, or not pass `styles` at all. However, passing all of the standardized properties is recommended for cohesiveness +- Hosts can use the CSS `light-dark()` function for theme-aware values #### App Behavior -- Apps SHOULD use fallback values for CSS variables: `var(--color-text-primary, #171717)` -- This ensures graceful degradation when hosts omit `styles` or specific variables -- When the host uses `light-dark()` values, apps MUST set `color-scheme` on their document: - ```css - :root { color-scheme: light dark; } - ``` +- Apps should set default fallback values for CSS variables, to account for hosts who don't pass some or all style variables. This ensures graceful degradation when hosts omit `styles` or specific variables: +``` +:root { + --colorTextPrimary: #171717; +} +``` +- Apps can use the `applyHostStyles` utility (or `useHostStyles` if they prefer a React hook) to easily populate the host-provided CSS variables into their style sheet +- Apps can use the `applyDocumentTheme` utility (or `useDocumentTheme` if they prefer a React hook) to easily respond to Host Context `theme` changes in a way that is compatible with the host's light/dark color variables -Example CSS: +Example usage of standardized CSS variables: ```css .container { - background: var(--color-background-primary, #ffffff); - color: var(--color-text-primary, #171717); - font: var(--font-style-body, 400 16px/1.4 system-ui); + background: var(--color-background-primary); + color: var(--color-text-primary); + font: var(--font-style-body); } ```