Skip to content

Commit 5748a20

Browse files
committed
refactor(threejs-server): extract applyHostStyle helper
Extract an applyHostStyle(ctx: McpUiHostContext) helper that wraps the SDK's applyDocumentTheme and applyHostStyleVariables, eliminating duplicated inline style-application logic between the onhostcontextchanged handler and the initial useEffect. Also consolidates two useEffect hooks (both depending on [app] and calling getHostContext()) into one. Follow-up to #555.
1 parent 83d82a1 commit 5748a20

1 file changed

Lines changed: 16 additions & 31 deletions

File tree

examples/threejs-server/src/mcp-app-wrapper.tsx

Lines changed: 16 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
* Generic wrapper that handles MCP App connection and passes all relevant
55
* props to the actual view component.
66
*/
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";
813
import { useApp } from "@modelcontextprotocol/ext-apps/react";
914
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
1015
import { StrictMode, useState, useEffect } from "react";
@@ -37,6 +42,11 @@ export interface ViewProps<TToolInput = Record<string, unknown>> {
3742
// MCP App Wrapper
3843
// =============================================================================
3944

45+
function applyHostStyle(ctx: McpUiHostContext) {
46+
if (ctx.theme) applyDocumentTheme(ctx.theme);
47+
if (ctx.styles?.variables) applyHostStyleVariables(ctx.styles.variables);
48+
}
49+
4050
function McpAppWrapper() {
4151
const [toolInputs, setToolInputs] = useState<Record<string, unknown> | null>(
4252
null,
@@ -69,44 +79,19 @@ function McpAppWrapper() {
6979
// Note: we handle styles here instead of using useHostStyles,
7080
// because useHostStyles overwrites onhostcontextchanged.
7181
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);
8283
setHostContext((prev) => ({ ...prev, ...params }));
8384
};
8485
},
8586
});
8687

87-
// Apply initial host styles
88+
// Apply initial host styles and context after connection
8889
useEffect(() => {
8990
if (!app) return;
9091
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);
11095
}
11196
}, [app]);
11297

0 commit comments

Comments
 (0)