import { useEffect, useState } from "react"; import { createRoot } from "react-dom/client"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; import { Tool } from "@modelcontextprotocol/sdk/types.js"; import { AppRenderer, AppRendererProps } from "../src/AppRenderer"; import { AppBridge } from "../../../dist/src/app-bridge"; const SANDBOX_PROXY_URL = URL.parse("/sandbox.html", location.href)!; /** * Example React application demonstrating the AppRenderer component. * * This shows how to: * - Connect to an MCP server * - List available tools * - Render tool UIs using AppRenderer * - Handle UI actions from the tool */ function ExampleApp() { const [client, setClient] = useState(null); const [tools, setTools] = useState([]); const [activeTools, setActiveTools] = useState< Array<{ id: string; name: string; input: Record }> >([]); const [error, setError] = useState(null); // Connect to MCP server on mount useEffect(() => { let mounted = true; async function connect() { try { const newClient = new Client({ name: "MCP UI React Host", version: "1.0.0", }); const mcpServerUrl = new URL("http://localhost:3001/mcp"); console.log( "[React Host] Attempting SSE connection to", mcpServerUrl.href, ); try { await newClient.connect(new SSEClientTransport(mcpServerUrl)); console.log("[React Host] SSE connection successful"); } catch (err) { console.warn( "[React Host] SSE connection failed, falling back to HTTP:", err, ); await newClient.connect( new StreamableHTTPClientTransport(mcpServerUrl), ); console.log("[React Host] HTTP connection successful"); } if (!mounted) return; // List available tools const toolsResult = await newClient.listTools(); if (!mounted) return; setClient(newClient); setTools(toolsResult.tools); } catch (err) { if (!mounted) return; const errorMsg = err instanceof Error ? err.message : String(err); setError(`Failed to connect to MCP server: ${errorMsg}`); console.error("[React Host] Connection error:", err); } } connect(); return () => { mounted = false; }; }, []); const handleAddToolUI = ( toolName: string, input: Record, ) => { const id = `${toolName}-${Date.now()}`; setActiveTools((prev) => [...prev, { id, name: toolName, input }]); }; const handleRemoveToolUI = (id: string) => { setActiveTools((prev) => prev.filter((t) => t.id !== id)); }; const handleMessage: AppRendererProps["onmessage"] = async ( params, _extra, ) => { console.log("[React Host] Message:", params); return {}; }; const handleLoggingMessage: AppRendererProps["onloggingmessage"] = ( params, ) => { console.log("[React Host] Logging message:", params); }; const handleOpenLink: AppRendererProps["onopenlink"] = async ( params, _extra, ) => { console.log("[React Host] Open link request:", params); window.open(params.url, "_blank", "noopener,noreferrer"); return { isError: false }; }; const handleError = (toolId: string, err: Error) => { console.error(`[React Host] Error from tool ${toolId}:`, err); setError(`Tool ${toolId}: ${err.message}`); }; if (error) { return (

Example MCP-UI React Host

Error: {error}
); } if (!client) { return (

Example MCP-UI React Host

Connecting to MCP server...

); } return (

Example MCP-UI React Host

Available Tools

{tools.length === 0 ? (

No tools available with UI resources.

) : (
{tools.map((tool) => ( ))}
)}
{activeTools.map((tool) => (

{tool.name}

handleError(tool.id, err)} />
))} {activeTools.length === 0 && (

No tool UIs active. Click a button above to add one.

)}
); } // Mount the React app const root = document.getElementById("root"); if (root) { createRoot(root).render(); } else { console.error("Root element not found"); }