|
4 | 4 | * Generic wrapper that handles MCP App connection and passes all relevant |
5 | 5 | * props to the actual view component. |
6 | 6 | */ |
7 | | -import type { App, McpUiHostContext } from "@modelcontextprotocol/ext-apps"; |
| 7 | +import { |
| 8 | + applyDocumentTheme, |
| 9 | + applyHostStyleVariables, |
| 10 | + type App, |
| 11 | + type McpUiHostContext, |
| 12 | +} from "@modelcontextprotocol/ext-apps"; |
8 | 13 | import { useApp } from "@modelcontextprotocol/ext-apps/react"; |
9 | 14 | import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; |
10 | 15 | import { StrictMode, useState, useEffect } from "react"; |
@@ -37,6 +42,11 @@ export interface ViewProps<TToolInput = Record<string, unknown>> { |
37 | 42 | // MCP App Wrapper |
38 | 43 | // ============================================================================= |
39 | 44 |
|
| 45 | +function applyHostStyle(ctx: McpUiHostContext) { |
| 46 | + if (ctx.theme) applyDocumentTheme(ctx.theme); |
| 47 | + if (ctx.styles?.variables) applyHostStyleVariables(ctx.styles.variables); |
| 48 | +} |
| 49 | + |
40 | 50 | function McpAppWrapper() { |
41 | 51 | const [toolInputs, setToolInputs] = useState<Record<string, unknown> | null>( |
42 | 52 | null, |
@@ -69,44 +79,19 @@ function McpAppWrapper() { |
69 | 79 | // Note: we handle styles here instead of using useHostStyles, |
70 | 80 | // because useHostStyles overwrites onhostcontextchanged. |
71 | 81 | app.onhostcontextchanged = (params) => { |
72 | | - const root = document.documentElement; |
73 | | - if (params.theme) { |
74 | | - root.setAttribute("data-theme", params.theme); |
75 | | - root.style.colorScheme = params.theme; |
76 | | - } |
77 | | - if (params.styles?.variables) { |
78 | | - for (const [k, v] of Object.entries(params.styles.variables)) { |
79 | | - if (v !== undefined) root.style.setProperty(k, v as string); |
80 | | - } |
81 | | - } |
| 82 | + applyHostStyle(params); |
82 | 83 | setHostContext((prev) => ({ ...prev, ...params })); |
83 | 84 | }; |
84 | 85 | }, |
85 | 86 | }); |
86 | 87 |
|
87 | | - // Apply initial host styles |
| 88 | + // Apply initial host styles and context after connection |
88 | 89 | useEffect(() => { |
89 | 90 | if (!app) return; |
90 | 91 | const ctx = app.getHostContext(); |
91 | | - const root = document.documentElement; |
92 | | - if (ctx?.theme) { |
93 | | - root.setAttribute("data-theme", ctx.theme); |
94 | | - root.style.colorScheme = ctx.theme; |
95 | | - } |
96 | | - if (ctx?.styles?.variables) { |
97 | | - for (const [k, v] of Object.entries(ctx.styles.variables)) { |
98 | | - if (v !== undefined) root.style.setProperty(k, v as string); |
99 | | - } |
100 | | - } |
101 | | - }, [app]); |
102 | | - |
103 | | - // Get initial host context after connection |
104 | | - useEffect(() => { |
105 | | - if (app) { |
106 | | - const ctx = app.getHostContext(); |
107 | | - if (ctx) { |
108 | | - setHostContext(ctx); |
109 | | - } |
| 92 | + if (ctx) { |
| 93 | + applyHostStyle(ctx); |
| 94 | + setHostContext(ctx); |
110 | 95 | } |
111 | 96 | }, [app]); |
112 | 97 |
|
|
0 commit comments