Follow Discord
Sweep 25 Sep 2026 · 19:33Z Build v2.1.283 504 read Stable v2.1.274 Latest v2.1.283 Next v2.1.283 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · claude-docs

Blend your MCP App with Claude's theme changedconnectors/building/mcp-apps/transparent-theming

Nearest release: v2.1.283, published under an hour after upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Upstream edited this page at 25 Sep 2026 18:00 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 25 Sep 2026 18:07 UTC.

Upstream edited
Recorded here
Lines+22added
Lines−18removed
From line 1 where the diff opens
First seen 14 Aug 2026 this site's first read of the page
Recorded edits2to this page, all time

## Apply the host style variables ## Next steps ## Apply the host's style variables ## Related topics

The whole hunk

from line 1, old and new numbered
/
lines
from line 1
11# Blend your MCP App with Claude's theme
22 
3> Make your widget background transparent and style it with Claude's style variables
3> Make your MCP App's background transparent and style it with Claude's host style variables so it blends into the conversation in light and dark mode.
44 
5Claude renders MCP Apps inside a sandboxed iframe, and every frame between your widget and the chat surface already has a transparent background, so the conversation can show through. When you leave your own background transparent and style text and borders with the host's [style variables](/docs/connectors/building/mcp-apps/design-guidelines#style-variables), your app looks like part of the conversation rather than an embedded box, and it follows the user's light or dark mode automatically.
5Claude renders MCP Apps inside a sandboxed iframe, and every frame between your widget and the chat surface already has a transparent background so the conversation can show through. If you leave your own background transparent and style text and borders with the host's [style variables](/docs/connectors/building/mcp-apps/design-guidelines#style-variables), your app looks like part of the conversation rather than an embedded box. It also follows the user's light or dark mode automatically.
66 
7The snippets on this page assume you have registered a UI resource and created an `App` instance from `@modelcontextprotocol/ext-apps`. See the [SDK Quickstart](https://modelcontextprotocol.github.io/ext-apps/api/documents/Quickstart.html) if you haven't.
7This page is for developers who already have an MCP App rendering in Claude and want it to match the host theme. The snippets assume you have registered a UI resource and created an `App` instance from `@modelcontextprotocol/ext-apps`. If you haven't, start with the [SDK Quickstart](https://modelcontextprotocol.github.io/ext-apps/api/documents/Quickstart.html). To match the host theme, [let the host background show through](#let-the-host-background-show-through), then [apply the host style variables](#apply-the-host-style-variables) at runtime.
88 
99## Let the host background show through
1010 
11Three settings on your side keep the transparency intact.
11Every frame Claude places between your widget and the chat surface is already transparent, so transparency holds as long as your own document doesn't paint over it. Leave the body background unpainted, declare `color-scheme`, and request a borderless frame.
1212 
1313### Don't paint a body background
1414 
from line 24
2424 
2525### Declare `color-scheme` in your document head
2626 
27Browsers give iframe documents an opaque canvas backdrop (white in light mode, near-black in dark mode) when the iframe's [`color-scheme`](https://developer.mozilla.org/docs/Web/CSS/color-scheme) differs from the embedding page. Declaring both schemes opts your document into whichever mode the host is in, so the browser drops the backdrop and makes the CSS [`light-dark()`](https://developer.mozilla.org/docs/Web/CSS/color_value/light-dark) values in Claude's tokens resolve correctly:
27Browsers give iframe documents an opaque canvas backdrop, white in light mode and near-black in dark mode, when the iframe's [`color-scheme`](https://developer.mozilla.org/docs/Web/CSS/color-scheme) differs from the embedding page. Declaring both schemes opts your document into whichever mode the host is in, so the browser drops the backdrop and makes the CSS [`light-dark()`](https://developer.mozilla.org/docs/Web/CSS/color_value/light-dark) values in Claude's tokens resolve correctly:
2828 
2929```html theme={null}
3030<meta name="color-scheme" content="light dark" />
from line 58
5858}));
5959```
6060 
61## Apply the host's style variables
61## Apply the host style variables
6262 
6363Claude passes a [`hostContext`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiHostContext.html) object to your widget during the [`connect()`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#connect) handshake. The fields relevant to theming are:
6464 
from line 72
7272 
7373### Read `hostContext` and listen for changes
7474 
75The [`App`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html) class exposes the initial context via [`getHostContext()`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#gethostcontext) once `connect()` resolves, and delivers subsequent updates (such as the user toggling dark mode) through the [`hostcontextchanged`](https://modelcontextprotocol.github.io/ext-apps/api/types/app.AppEventMap.html) event. Register the listener before you connect so you don't miss an early update.
75The [`App`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html) class exposes the initial context via [`getHostContext()`](https://modelcontextprotocol.github.io/ext-apps/api/classes/app.App.html#gethostcontext) once `connect()` resolves, and delivers subsequent updates, such as the user toggling dark mode, through the [`hostcontextchanged`](https://modelcontextprotocol.github.io/ext-apps/api/types/app.AppEventMap.html) event. Register the listener before you connect so you don't miss an early update.
7676 
77The SDK provides three helpers that do the DOM work for you, plus React hooks that wrap them:
77The SDK provides helpers that do the DOM work for you, and React hooks that wrap them:
7878 
79* [`applyDocumentTheme(theme)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/app.applyDocumentTheme.html) sets `<html data-theme>` and the root `color-scheme`, so `[data-theme="dark"]` selectors and `light-dark()` values resolve correctly.
80* [`applyHostStyleVariables(variables)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/app.applyHostStyleVariables.html) writes every entry in `styles.variables` onto `:root` as a CSS custom property.
81* [`applyHostFonts(fontCss)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/app.applyHostFonts.html) injects the host's `@font-face` rules once.
82* [`useApp(options)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/_modelcontextprotocol_ext-apps_react.useApp.html) creates and connects the `App` instance for you in React.
83* [`useHostStyles(app, hostContext)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/_modelcontextprotocol_ext-apps_react.useHostStyles.html) applies all of the above and re-applies on `hostcontextchanged`.
79* [`applyDocumentTheme(theme)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/app.applyDocumentTheme.html) sets `<html data-theme>` and the root `color-scheme`, so `[data-theme="dark"]` selectors and `light-dark()` values resolve correctly
80* [`applyHostStyleVariables(variables)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/app.applyHostStyleVariables.html) writes every entry in `styles.variables` onto `:root` as a CSS custom property
81* [`applyHostFonts(fontCss)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/app.applyHostFonts.html) injects the host's `@font-face` rules once
82* [`useApp(options)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/_modelcontextprotocol_ext-apps_react.useApp.html) creates and connects the `App` instance for you in React
83* [`useHostStyles(app, hostContext)`](https://modelcontextprotocol.github.io/ext-apps/api/functions/_modelcontextprotocol_ext-apps_react.useHostStyles.html) applies the theme, variables, and fonts and re-applies on `hostcontextchanged`
8484 
85Keep the `<meta name="color-scheme">` tag from the previous section even though `applyDocumentTheme` also sets `color-scheme` at runtime. The tag covers the first paint before your script runs and prevents an opaque-backdrop flash.
85Keep the `<meta name="color-scheme">` tag in your document head even though `applyDocumentTheme` also sets `color-scheme` at runtime. The tag covers the first paint before your script runs and prevents an opaque-backdrop flash.
8686 
87This example applies the theme, variables, and fonts on connect and again on every host context change:
88 
8789<CodeGroup>
8890 ```ts TypeScript theme={null}
8991 import {
from line 148
146148 
147149### Allow the host font origin in your CSP
148150 
149For `applyHostFonts` to load the `@font-face` files, your resource's [`_meta.ui.csp`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceMeta.html#csp) allowlist must include `https://assets.claude.ai` in [`resourceDomains`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceCsp.html#resourcedomains) (shown in the [`registerAppResource` snippet above](#request-a-borderless-frame)). `resourceDomains` also adds the listed origins to `script-src` and `style-src`, so keep it to origins you trust to serve executable code; prefer bundling third-party fonts into your widget rather than allowlisting public CDNs.
151For `applyHostFonts` to load the `@font-face` files, your resource's [`_meta.ui.csp`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceMeta.html#csp) allowlist must include `https://assets.claude.ai` in [`resourceDomains`](https://modelcontextprotocol.github.io/ext-apps/api/interfaces/app.McpUiResourceCsp.html#resourcedomains), as the [`registerAppResource` snippet](#request-a-borderless-frame) shows. `resourceDomains` also adds the listed origins to `script-src` and `style-src`, so keep it to origins you trust to serve executable code. Prefer bundling third-party fonts into your widget rather than allowlisting public CDNs.
150152 
151## Related topics
153## Next steps
152154 
153* [Design guidelines: Style variables](/docs/connectors/building/mcp-apps/design-guidelines#style-variables) and [Visual design](/docs/connectors/building/mcp-apps/design-guidelines#visual-design) for the full variable palette and usage guidance.
154* [SDK API reference](https://modelcontextprotocol.github.io/ext-apps/api/index.html) for `App`, `McpUiHostContext`, and `McpUiResourceMeta`.
155* [Style variables](/docs/connectors/building/mcp-apps/design-guidelines#style-variables): the full variable palette in the design guidelines
156* [Visual design](/docs/connectors/building/mcp-apps/design-guidelines#visual-design): usage guidance for color, typography, and spacing in the design guidelines
157* [Supersede older widget instances](/docs/connectors/building/mcp-apps/instance-supersession): keep only the newest copy of your widget active in a conversation
158* [SDK API reference](https://modelcontextprotocol.github.io/ext-apps/api/index.html): `App`, `McpUiHostContext`, and `McpUiResourceMeta`
155159 
Feedback