Skip to content

Commit 3503ad1

Browse files
committed
Add way to pass fonts
1 parent 7166f75 commit 3503ad1

File tree

12 files changed

+337
-26
lines changed

12 files changed

+337
-26
lines changed

examples/customer-segmentation-server/src/mcp-app.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
:root {
33
color-scheme: light dark;
44

5+
/* Font families */
6+
--font-sans: system-ui, -apple-system, sans-serif;
7+
58
/* Background colors */
69
--color-background-primary: light-dark(#ffffff, #111827);
710
--color-background-secondary: light-dark(#f9fafb, #1f2937);
@@ -33,6 +36,7 @@
3336
html, body {
3437
margin: 0;
3538
padding: 0;
39+
font-family: var(--font-sans);
3640
color: var(--color-text-primary);
3741
overflow: hidden;
3842
}

examples/customer-segmentation-server/src/mcp-app.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import {
55
App,
66
PostMessageTransport,
7-
applyHostStyles,
7+
applyHostStyleVariables,
8+
applyHostFonts,
89
applyDocumentTheme,
910
} from "@modelcontextprotocol/ext-apps";
1011
import { Chart, registerables } from "chart.js";
@@ -448,13 +449,16 @@ applyDocumentTheme(systemDark ? "dark" : "light");
448449
// Register handlers and connect
449450
app.onerror = log.error;
450451

451-
// Handle host context changes (theme and styles from host)
452+
// Handle host context changes (theme, styles, and fonts from host)
452453
app.onhostcontextchanged = (params) => {
453454
if (params.theme) {
454455
applyDocumentTheme(params.theme);
455456
}
456457
if (params.styles?.variables) {
457-
applyHostStyles(params.styles.variables);
458+
applyHostStyleVariables(params.styles.variables);
459+
}
460+
if (params.styles?.css?.fonts) {
461+
applyHostFonts(params.styles.css.fonts);
458462
}
459463
// Recreate chart to pick up new colors
460464
if (state.chart && (params.theme || params.styles?.variables)) {
@@ -470,7 +474,10 @@ app.connect(new PostMessageTransport(window.parent)).then(() => {
470474
applyDocumentTheme(ctx.theme);
471475
}
472476
if (ctx?.styles?.variables) {
473-
applyHostStyles(ctx.styles.variables);
477+
applyHostStyleVariables(ctx.styles.variables);
478+
}
479+
if (ctx?.styles?.css?.fonts) {
480+
applyHostFonts(ctx.styles.css.fonts);
474481
}
475482
});
476483

specification/draft/apps.mdx

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,11 @@ interface HostContext {
409409
styles?: {
410410
/** CSS variables for theming */
411411
variables?: Record<McpUiStyleVariableKey, string | undefined>;
412+
/** CSS blocks that apps can inject */
413+
css?: {
414+
/** CSS for font loading (@font-face rules or @import statements) */
415+
fonts?: string;
416+
};
412417
};
413418
/** How the UI is currently displayed */
414419
displayMode?: "inline" | "fullscreen" | "pip";
@@ -461,8 +466,11 @@ Example:
461466
"variables": {
462467
"--color-background-primary": "light-dark(#ffffff, #171717)",
463468
"--color-text-primary": "light-dark(#171717, #fafafa)",
464-
"--font-family-sans": "system-ui, sans-serif",
469+
"--font-sans": "Anthropic Sans, sans-serif",
465470
...
471+
},
472+
"css": {
473+
"fonts": "@font-face { font-family: \"Custom Font Name\"; src: url(\"https://...\"); }"
466474
}
467475
},
468476
"displayMode": "inline",
@@ -587,16 +595,46 @@ type McpUiStyleVariableKey =
587595
...
588596
}
589597
```
590-
- 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
591-
- 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
598+
- Apps can use the `applyHostStyleVariables` utility (or `useHostStyleVariables` if they prefer a React hook) to easily populate the host-provided CSS variables into their style sheet
599+
- 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
592600

593601
Example usage of standardized CSS variables:
594602

595603
```css
596604
.container {
597605
background: var(--color-background-primary);
598606
color: var(--color-text-primary);
599-
font: var(--font-style-body);
607+
font-family: var(--font-sans);
608+
}
609+
```
610+
611+
#### Custom Fonts
612+
613+
Hosts can provide custom fonts via `styles.css.fonts`, which can contain `@font-face` rules for self-hosted fonts, `@import` statements for font services like Google Fonts, or both:
614+
615+
```typescript
616+
// Self-hosted fonts
617+
hostContext.styles.css.fonts = `
618+
@font-face {
619+
font-family: "Custom Font Name"; // Name should match the font name used in a font variable (`--font-sans`, `--font-mono`)
620+
src: url("https://url-where-font-is-hosted.com/.../Regular.otf") format("opentype");
621+
font-weight: 400;
622+
font-style: normal;
623+
font-display: swap;
624+
}
625+
`;
626+
627+
// Google Fonts
628+
hostContext.styles.css.fonts = `
629+
@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
630+
`;
631+
```
632+
633+
Apps can use the `applyHostFonts` utility to inject the font CSS into the document:
634+
635+
```typescript
636+
if (hostContext.styles?.css?.fonts) {
637+
applyHostFonts(hostContext.styles.css.fonts);
600638
}
601639
```
602640

src/app.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
4848
export { PostMessageTransport } from "./message-transport";
4949
export * from "./types";
5050
export {
51-
applyHostStyles,
51+
applyHostStyleVariables,
52+
applyHostFonts,
5253
getDocumentTheme,
5354
applyDocumentTheme,
5455
} from "./styles";

src/generated/schema.json

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,17 @@
585585
{}
586586
]
587587
}
588+
},
589+
"css": {
590+
"description": "CSS blocks that apps can inject.",
591+
"type": "object",
592+
"properties": {
593+
"fonts": {
594+
"description": "CSS for font loading (@font-face rules or",
595+
"type": "string"
596+
}
597+
},
598+
"additionalProperties": false
588599
}
589600
},
590601
"additionalProperties": false
@@ -1196,6 +1207,17 @@
11961207
{}
11971208
]
11981209
}
1210+
},
1211+
"css": {
1212+
"description": "CSS blocks that apps can inject.",
1213+
"type": "object",
1214+
"properties": {
1215+
"fonts": {
1216+
"description": "CSS for font loading (@font-face rules or",
1217+
"type": "string"
1218+
}
1219+
},
1220+
"additionalProperties": false
11991221
}
12001222
},
12011223
"additionalProperties": false
@@ -1319,6 +1341,17 @@
13191341
},
13201342
"additionalProperties": {}
13211343
},
1344+
"McpUiHostCss": {
1345+
"$schema": "https://json-schema.org/draft/2020-12/schema",
1346+
"type": "object",
1347+
"properties": {
1348+
"fonts": {
1349+
"description": "CSS for font loading (@font-face rules or",
1350+
"type": "string"
1351+
}
1352+
},
1353+
"additionalProperties": false
1354+
},
13221355
"McpUiHostStyles": {
13231356
"$schema": "https://json-schema.org/draft/2020-12/schema",
13241357
"type": "object",
@@ -1640,6 +1673,17 @@
16401673
{}
16411674
]
16421675
}
1676+
},
1677+
"css": {
1678+
"description": "CSS blocks that apps can inject.",
1679+
"type": "object",
1680+
"properties": {
1681+
"fonts": {
1682+
"description": "CSS for font loading (@font-face rules or",
1683+
"type": "string"
1684+
}
1685+
},
1686+
"additionalProperties": false
16431687
}
16441688
},
16451689
"additionalProperties": false
@@ -2314,6 +2358,17 @@
23142358
{}
23152359
]
23162360
}
2361+
},
2362+
"css": {
2363+
"description": "CSS blocks that apps can inject.",
2364+
"type": "object",
2365+
"properties": {
2366+
"fonts": {
2367+
"description": "CSS for font loading (@font-face rules or",
2368+
"type": "string"
2369+
}
2370+
},
2371+
"additionalProperties": false
23172372
}
23182373
},
23192374
"additionalProperties": false

src/generated/schema.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ export type McpUiToolCancelledNotificationSchemaInferredType = z.infer<
6363
typeof generated.McpUiToolCancelledNotificationSchema
6464
>;
6565

66+
export type McpUiHostCssSchemaInferredType = z.infer<
67+
typeof generated.McpUiHostCssSchema
68+
>;
69+
6670
export type McpUiHostStylesSchemaInferredType = z.infer<
6771
typeof generated.McpUiHostStylesSchema
6872
>;
@@ -181,6 +185,8 @@ expectType<spec.McpUiToolCancelledNotification>(
181185
expectType<McpUiToolCancelledNotificationSchemaInferredType>(
182186
{} as spec.McpUiToolCancelledNotification,
183187
);
188+
expectType<spec.McpUiHostCss>({} as McpUiHostCssSchemaInferredType);
189+
expectType<McpUiHostCssSchemaInferredType>({} as spec.McpUiHostCss);
184190
expectType<spec.McpUiHostStyles>({} as McpUiHostStylesSchemaInferredType);
185191
expectType<McpUiHostStylesSchemaInferredType>({} as spec.McpUiHostStyles);
186192
expectType<spec.McpUiResourceTeardownRequest>(

src/generated/schema.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,17 @@ export const McpUiToolCancelledNotificationSchema = z.object({
285285
}),
286286
});
287287

288+
/**
289+
* @description CSS blocks that can be injected by apps.
290+
*/
291+
export const McpUiHostCssSchema = z.object({
292+
/** @description CSS for font loading (@font-face rules or @import statements). Apps must apply using applyHostFonts(). */
293+
fonts: z
294+
.string()
295+
.optional()
296+
.describe("CSS for font loading (@font-face rules or"),
297+
});
298+
288299
/**
289300
* @description Style configuration for theming MCP apps.
290301
*/
@@ -293,6 +304,10 @@ export const McpUiHostStylesSchema = z.object({
293304
variables: McpUiStylesSchema.optional().describe(
294305
"CSS variables for theming the app.",
295306
),
307+
/** @description CSS blocks that apps can inject. */
308+
css: McpUiHostCssSchema.optional().describe(
309+
"CSS blocks that apps can inject.",
310+
),
296311
});
297312

298313
/**

src/react/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
* ## Main Exports
1010
*
1111
* - {@link useApp} - React hook to create and connect an MCP App
12-
* - {@link useHostStyles} - React hook to apply host styles as CSS variables
12+
* - {@link useHostStyleVariables} - React hook to apply host style variables and theme
13+
* - {@link useHostFonts} - React hook to apply host fonts
14+
* - {@link useHostStyles} - Convenience hook combining useHostStyleVariables and useHostFonts
1315
* - {@link useDocumentTheme} - React hook for reactive document theme
1416
* - {@link useAutoResize} - React hook for manual auto-resize control (rarely needed)
1517
*

0 commit comments

Comments
 (0)