Skip to content

@mcp-ui/client Usage & Examples

Here’s how to use the <HtmlResource /> component from @mcp-ui/client.

Installation

Make sure you have @mcp-ui/client and its peer dependencies installed in your React project:

bash
pnpm add @mcp-ui/client react @modelcontextprotocol/sdk

Rendering HTML Resources

tsx
import React, { useState } from 'react';
import { HtmlResource } from '@mcp-ui/client';

// Simulate fetching an MCP resource block
const fetchMcpResource = async (id: string): Promise<HtmlResource> => {
  if (id === 'direct') {
    return {
      type: 'resource',
      resource: {
        uri: 'ui://example/direct-html',
        mimeType: 'text/html',
        text: "<h1>Direct HTML via Text</h1><p>Content loaded directly.</p><button onclick=\"window.parent.postMessage({tool: 'uiInteraction', params: { action: 'directClick', value: Date.now() }}, '*')\">Click Me (Direct)</button>",
      },
    };
  } else if (id === 'blob') {
    const html =
      "<h1>HTML from Blob</h1><p>Content was Base64 encoded.</p><button onclick=\"window.parent.postMessage({tool: 'uiInteraction', params: { action: 'blobClick', value: 'test' }}, '*')\">Click Me (Blob)</button>";
    return {
      type: 'resource',
      resource: {
        uri: 'ui://example/blob-html',
        mimeType: 'text/html',
        blob: btoa(html),
      },
    };
  } else if (id === 'external') {
    return {
      type: 'resource',
      resource: {
        uri: 'ui-app://example/external-site',
        mimeType: 'text/html',
        text: 'https://vitepress.dev',
      },
    };
  }
  throw new Error('Unknown resource ID');
};

const App: React.FC = () => {
  const [resourceBlock, setResourceBlock] = useState<HtmlResource | null>(
    null,
  );
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [lastAction, setLastAction] = useState<any>(null);

  const loadResource = async (id: string) => {
    setLoading(true);
    setError(null);
    setResourceBlock(null);
    try {
      const block = await fetchMcpResource(id);
      setResourceBlock(block);
    } catch (e: any) {
      setError(e.message);
    }
    setLoading(false);
  };

  const handleGenericMcpAction = async (
    tool: string,
    params: Record<string, unknown>,
  ) => {
    console.log(`Action received in host app - Tool: ${tool}, Params:`, params);
    setLastAction({ tool, params });
    return {
      status: 'Action handled by host application',
      receivedParams: params,
    };
  };

  return (
    <div>
      <h1>MCP UI Client Demo</h1>
      <button onClick={() => loadResource('direct')}>
        Load Direct HTML (Text)
      </button>
      <button onClick={() => loadResource('blob')}>
        Load Direct HTML (Blob)
      </button>
      <button onClick={() => loadResource('external')}>
        Load External App (URL)
      </button>

      {loading && <p>Loading resource...</p>}
      {error && <p style={{ color: 'red' }}>Error: {error}</p>}

      {resourceBlock && resourceBlock.resource && (
        <div style={{ marginTop: 20, border: '2px solid blue', padding: 10 }}>
          <h2>Rendering Resource: {resourceBlock.resource.uri}</h2>
          <HtmlResource
            resource={resourceBlock.resource}
            onUiAction={handleGenericMcpAction}
          />
        </div>
      )}

      {lastAction && (
        <div style={{ marginTop: 20, border: '1px solid green', padding: 10 }}>
          <h3>Last Action Received by Host:</h3>
          <pre>{JSON.stringify(lastAction, null, 2)}</pre>
        </div>
      )}
    </div>
  );
};

export default App;

That’s it! Just use <HtmlResource /> with the right props and you’re ready to render interactive HTML from MCP resources in your React app. If you need more details, check out the HtmlResource Component page.

Released under the Apache 2.0 License.