HtmlResource Component
The <HtmlResource />
component is currently the main component of the@mcp-ui/client
package. It's the only export you need to render interactive HTML resources in your React app.
Props
typescript
import type { Resource } from '@modelcontextprotocol/sdk/types';
export interface HtmlResourceProps {
resource: Partial<Resource>;
onUiAction?: (
tool: string,
params: Record<string, unknown>,
) => Promise<any>;
style?: React.CSSProperties;
}
resource
: The resource object from anHtmlResourceBlock
. It should includeuri
,mimeType
, and eithertext
orblob
.onUiAction
: An optional callback that fires when the iframe content (forui://
resources) posts a message to your app. The message should look like{ tool: string, params: Record<string, unknown> }
.style
(optional): Custom styles for the iframe.
How It Works
- Checks Content Type: If
resource.mimeType
isn't"text/html"
, you'll see an error. - Handles URI Schemes:
- For
ui-app://
URIs:- Expects
resource.text
orresource.blob
to contain a URL. - If using
blob
, it decodes it from Base64. - Renders an
<iframe>
with itssrc
set to the URL. - Sandbox:
allow-scripts allow-same-origin
(needed for some external sites; be mindful of security).
- Expects
- For
ui://
URIs (or if there's no URI but you provide HTML intext
/blob
):- Expects
resource.text
orresource.blob
to contain HTML. - If using
blob
, it decodes it from Base64. - Renders an
<iframe>
with itssrcdoc
set to the HTML. - Sandbox:
allow-scripts
.
- Expects
- For
- Listens for Messages: Adds a global
message
event listener. If an iframe posts a message withevent.data.tool
, youronUiAction
callback is called.
Styling
By default, the iframe stretches to 100% width and is at least 200px tall. You can override this with the style
prop or your own CSS.
Example Usage
See Client SDK Usage & Examples.
Security Notes
sandbox
attribute: Restricts what the iframe can do.allow-scripts
is needed for interactivity.allow-same-origin
is only used forui-app://
URLs. Caution - it's not a secure way to render untrusted code. We should add more secure methods such as RSC ASAP.postMessage
origin: When sending messages from the iframe, always specify the target origin for safety. The component listens globally, so your iframe content should be explicit.- Content Sanitization: HTML is rendered as-is. If you don't fully trust the source, sanitize the HTML before passing it in, or rely on the iframe's sandboxing.