Make it styles.variables instead of styles

This commit is contained in:
martinalong 2025-12-14 12:28:42 -08:00
commit 445a5836cf
No known key found for this signature in database
9 changed files with 717 additions and 496 deletions

View file

@ -453,11 +453,11 @@ app.onhostcontextchanged = (params) => {
if (params.theme) { if (params.theme) {
applyDocumentTheme(params.theme); applyDocumentTheme(params.theme);
} }
if (params.styles) { if (params.styles?.variables) {
applyHostStyles(params.styles); applyHostStyles(params.styles.variables);
} }
// Recreate chart to pick up new colors // Recreate chart to pick up new colors
if (state.chart && (params.theme || params.styles)) { if (state.chart && (params.theme || params.styles?.variables)) {
state.chart.destroy(); state.chart.destroy();
state.chart = initChart(); state.chart = initChart();
} }
@ -469,8 +469,8 @@ app.connect(new PostMessageTransport(window.parent)).then(() => {
if (ctx?.theme) { if (ctx?.theme) {
applyDocumentTheme(ctx.theme); applyDocumentTheme(ctx.theme);
} }
if (ctx?.styles) { if (ctx?.styles?.variables) {
applyHostStyles(ctx.styles); applyHostStyles(ctx.styles.variables);
} }
}); });

View file

@ -404,8 +404,11 @@ interface HostContext {
}; };
/** Current color theme preference */ /** Current color theme preference */
theme?: "light" | "dark"; theme?: "light" | "dark";
/** CSS variables for theming. See Theming section for standardized variable names. */ /** Style configuration for theming. See Theming section for standardized variable names. */
styles?: Record<McpUiStyleVariableKey, string | undefined>; styles?: {
/** CSS variables for theming */
variables?: Record<McpUiStyleVariableKey, string | undefined>;
};
/** How the UI is currently displayed */ /** How the UI is currently displayed */
displayMode?: "inline" | "fullscreen" | "pip"; displayMode?: "inline" | "fullscreen" | "pip";
/** Display modes the host supports */ /** Display modes the host supports */
@ -454,10 +457,12 @@ Example:
"hostContext": { "hostContext": {
"theme": "dark", "theme": "dark",
"styles": { "styles": {
"--color-background-primary": "light-dark(#ffffff, #171717)", "variables": {
"--color-text-primary": "light-dark(#171717, #fafafa)", "--color-background-primary": "light-dark(#ffffff, #171717)",
"--font-family-sans": "system-ui, sans-serif", "--color-text-primary": "light-dark(#171717, #fafafa)",
... "--font-family-sans": "system-ui, sans-serif",
...
}
}, },
"displayMode": "inline", "displayMode": "inline",
"viewport": { "width": 400, "height": 300 } "viewport": { "width": 400, "height": 300 }
@ -468,7 +473,7 @@ Example:
### Theming ### Theming
Hosts can optionally pass CSS custom properties via `HostContext.styles` for visual cohesion with the host environment. Hosts can optionally pass CSS custom properties via `HostContext.styles.variables` for visual cohesion with the host environment.
#### Current Standardized Variables #### Current Standardized Variables

File diff suppressed because it is too large Load diff

View file

@ -63,6 +63,10 @@ export type McpUiToolCancelledNotificationSchemaInferredType = z.infer<
typeof generated.McpUiToolCancelledNotificationSchema typeof generated.McpUiToolCancelledNotificationSchema
>; >;
export type McpUiHostStylesSchemaInferredType = z.infer<
typeof generated.McpUiHostStylesSchema
>;
export type McpUiResourceTeardownRequestSchemaInferredType = z.infer< export type McpUiResourceTeardownRequestSchemaInferredType = z.infer<
typeof generated.McpUiResourceTeardownRequestSchema typeof generated.McpUiResourceTeardownRequestSchema
>; >;
@ -177,6 +181,8 @@ expectType<spec.McpUiToolCancelledNotification>(
expectType<McpUiToolCancelledNotificationSchemaInferredType>( expectType<McpUiToolCancelledNotificationSchemaInferredType>(
{} as spec.McpUiToolCancelledNotification, {} as spec.McpUiToolCancelledNotification,
); );
expectType<spec.McpUiHostStyles>({} as McpUiHostStylesSchemaInferredType);
expectType<McpUiHostStylesSchemaInferredType>({} as spec.McpUiHostStyles);
expectType<spec.McpUiResourceTeardownRequest>( expectType<spec.McpUiResourceTeardownRequest>(
{} as McpUiResourceTeardownRequestSchemaInferredType, {} as McpUiResourceTeardownRequestSchemaInferredType,
); );

View file

@ -246,6 +246,16 @@ export const McpUiToolCancelledNotificationSchema = z.object({
}), }),
}); });
/**
* @description Style configuration for theming MCP apps.
*/
export const McpUiHostStylesSchema = z.object({
/** @description CSS variables for theming the app. */
variables: McpUiStylesSchema.optional().describe(
"CSS variables for theming the app.",
),
});
/** /**
* @description Request for graceful shutdown of the Guest UI (Host -> Guest UI). * @description Request for graceful shutdown of the Guest UI (Host -> Guest UI).
* @see {@link app-bridge.AppBridge.sendResourceTeardown} for the host method that sends this * @see {@link app-bridge.AppBridge.sendResourceTeardown} for the host method that sends this
@ -422,9 +432,9 @@ export const McpUiHostContextSchema = z.looseObject({
theme: McpUiThemeSchema.optional().describe( theme: McpUiThemeSchema.optional().describe(
"Current color theme preference.", "Current color theme preference.",
), ),
/** @description CSS variables for theming the app. */ /** @description Style configuration for theming the app. */
styles: McpUiStylesSchema.optional().describe( styles: McpUiHostStylesSchema.optional().describe(
"CSS variables for theming the app.", "Style configuration for theming the app.",
), ),
/** @description How the UI is currently displayed. */ /** @description How the UI is currently displayed. */
displayMode: McpUiDisplayModeSchema.optional().describe( displayMode: McpUiDisplayModeSchema.optional().describe(

View file

@ -7,7 +7,7 @@ import { McpUiHostContext } from "../types";
* React hook that applies host styles and theme 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: * This hook listens to host context changes and automatically applies:
* - `styles` CSS variables to `document.documentElement` (e.g., `--color-background-primary`) * - `styles.variables` CSS variables to `document.documentElement` (e.g., `--color-background-primary`)
* - `theme` via `color-scheme` CSS property, enabling `light-dark()` CSS function support * - `theme` via `color-scheme` CSS property, enabling `light-dark()` CSS function support
* *
* The hook also applies styles and theme from the initial host context when * The hook also applies styles and theme from the initial host context when
@ -70,10 +70,10 @@ export function useHostStyles(
if (initialContext?.theme) { if (initialContext?.theme) {
applyDocumentTheme(initialContext.theme); applyDocumentTheme(initialContext.theme);
} }
if (initialContext?.styles) { if (initialContext?.styles?.variables) {
applyHostStyles(initialContext.styles); applyHostStyles(initialContext.styles.variables);
} }
if (initialContext?.theme || initialContext?.styles) { if (initialContext?.theme || initialContext?.styles?.variables) {
initialApplied.current = true; initialApplied.current = true;
} }
}, [initialContext]); }, [initialContext]);
@ -88,8 +88,8 @@ export function useHostStyles(
if (params.theme) { if (params.theme) {
applyDocumentTheme(params.theme); applyDocumentTheme(params.theme);
} }
if (params.styles) { if (params.styles?.variables) {
applyHostStyles(params.styles); applyHostStyles(params.styles.variables);
} }
}; };
}, [app]); }, [app]);

View file

@ -244,6 +244,14 @@ export interface McpUiToolCancelledNotification {
}; };
} }
/**
* @description Style configuration for theming MCP apps.
*/
export interface McpUiHostStyles {
/** @description CSS variables for theming the app. */
variables?: McpUiStyles;
}
/** /**
* @description Rich context about the host environment provided to Guest UIs. * @description Rich context about the host environment provided to Guest UIs.
*/ */
@ -259,8 +267,8 @@ export interface McpUiHostContext {
}; };
/** @description Current color theme preference. */ /** @description Current color theme preference. */
theme?: McpUiTheme; theme?: McpUiTheme;
/** @description CSS variables for theming the app. */ /** @description Style configuration for theming the app. */
styles?: McpUiStyles; styles?: McpUiHostStyles;
/** @description How the UI is currently displayed. */ /** @description How the UI is currently displayed. */
displayMode?: McpUiDisplayMode; displayMode?: McpUiDisplayMode;
/** @description Display modes the host supports. */ /** @description Display modes the host supports. */

View file

@ -76,12 +76,12 @@ export function applyDocumentTheme(theme: McpUiTheme): void {
/** /**
* Apply host styles as CSS custom properties on an element. * Apply host styles as CSS custom properties on an element.
* *
* This function takes the `styles` object from `McpUiHostContext` and sets * This function takes the `variables` object from `McpUiHostContext.styles` and sets
* each CSS variable on the specified root element (defaults to `document.documentElement`). * each CSS variable on the specified root element (defaults to `document.documentElement`).
* This allows apps to use the host's theming values via CSS variables like * This allows apps to use the host's theming values via CSS variables like
* `var(--color-background-primary)`. * `var(--color-background-primary)`.
* *
* @param styles - The styles object from `McpUiHostContext.styles` * @param styles - The styles object from `McpUiHostContext.styles.variables`
* @param root - The element to apply styles to (defaults to `document.documentElement`) * @param root - The element to apply styles to (defaults to `document.documentElement`)
* *
* @example Apply styles from host context * @example Apply styles from host context
@ -89,8 +89,8 @@ export function applyDocumentTheme(theme: McpUiTheme): void {
* import { applyHostStyles } from '@modelcontextprotocol/ext-apps'; * import { applyHostStyles } from '@modelcontextprotocol/ext-apps';
* *
* app.onhostcontextchanged = (params) => { * app.onhostcontextchanged = (params) => {
* if (params.styles) { * if (params.styles?.variables) {
* applyHostStyles(params.styles); * applyHostStyles(params.styles.variables);
* } * }
* }; * };
* ``` * ```
@ -98,7 +98,7 @@ export function applyDocumentTheme(theme: McpUiTheme): void {
* @example Apply to a specific element * @example Apply to a specific element
* ```typescript * ```typescript
* const container = document.getElementById('app-root'); * const container = document.getElementById('app-root');
* applyHostStyles(hostContext.styles, container); * applyHostStyles(hostContext.styles?.variables, container);
* ``` * ```
* *
* @see {@link McpUiStyles} for the available CSS variables * @see {@link McpUiStyles} for the available CSS variables

View file

@ -16,6 +16,7 @@ export {
type McpUiDisplayMode, type McpUiDisplayMode,
type McpUiStyleVariableKey, type McpUiStyleVariableKey,
type McpUiStyles, type McpUiStyles,
type McpUiHostStyles,
type McpUiOpenLinkRequest, type McpUiOpenLinkRequest,
type McpUiOpenLinkResult, type McpUiOpenLinkResult,
type McpUiMessageRequest, type McpUiMessageRequest,
@ -65,6 +66,7 @@ import type {
export { export {
McpUiThemeSchema, McpUiThemeSchema,
McpUiDisplayModeSchema, McpUiDisplayModeSchema,
McpUiHostStylesSchema,
McpUiOpenLinkRequestSchema, McpUiOpenLinkRequestSchema,
McpUiOpenLinkResultSchema, McpUiOpenLinkResultSchema,
McpUiMessageRequestSchema, McpUiMessageRequestSchema,