import { Component, type ErrorInfo, type ReactNode, StrictMode, Suspense, use, useEffect, useMemo, useRef, useState } from "react"; import { createRoot } from "react-dom/client"; import { callTool, connectToServer, hasAppHtml, initializeApp, loadSandboxProxy, log, newAppBridge, type ServerInfo, type ToolCallInfo } from "./implementation"; import styles from "./index.module.css"; // Available MCP servers - using ports 3101+ to avoid conflicts with common dev ports const SERVERS = [ { name: "Basic React", port: 3101 }, { name: "Vanilla JS", port: 3102 }, { name: "Budget Allocator", port: 3103 }, { name: "Cohort Heatmap", port: 3104 }, { name: "Customer Segmentation", port: 3105 }, { name: "Scenario Modeler", port: 3106 }, { name: "System Monitor", port: 3107 }, { name: "Three.js", port: 3109 }, ] as const; function serverUrl(port: number): string { return `http://localhost:${port}/mcp`; } // Cache server connections to avoid reconnecting when switching between servers const serverInfoCache = new Map>(); function getServerInfo(port: number): Promise { let promise = serverInfoCache.get(port); if (!promise) { promise = connectToServer(new URL(serverUrl(port))); // Remove from cache on failure so retry is possible promise.catch(() => serverInfoCache.delete(port)); serverInfoCache.set(port, promise); } return promise; } // Wrapper to track server name with each tool call interface ToolCallEntry { serverName: string; info: ToolCallInfo; } // Host just manages tool call results - no server dependency function Host() { const [toolCalls, setToolCalls] = useState([]); return ( <> {toolCalls.map((entry, i) => ( ))} setToolCalls([...toolCalls, { serverName, info }])} /> ); } // CallToolPanel includes server selection with its own Suspense boundary interface CallToolPanelProps { addToolCall: (serverName: string, info: ToolCallInfo) => void; } function CallToolPanel({ addToolCall }: CallToolPanelProps) { const [selectedServer, setSelectedServer] = useState(SERVERS[0]); const [serverInfoPromise, setServerInfoPromise] = useState( () => getServerInfo(selectedServer.port) ); const handleServerChange = (port: number) => { const server = SERVERS.find(s => s.port === port) ?? SERVERS[0]; setSelectedServer(server); setServerInfoPromise(getServerInfo(port)); }; return (
Connecting to {serverUrl(selectedServer.port)}...

}>
); } // ToolCallForm renders inside Suspense - needs serverInfo for tool list interface ToolCallFormProps { serverName: string; serverInfoPromise: Promise; addToolCall: (serverName: string, info: ToolCallInfo) => void; } function ToolCallForm({ serverName, serverInfoPromise, addToolCall }: ToolCallFormProps) { const serverInfo = use(serverInfoPromise); const toolNames = Array.from(serverInfo.tools.keys()); const [selectedTool, setSelectedTool] = useState(toolNames[0] ?? ""); const [inputJson, setInputJson] = useState("{}"); const isValidJson = useMemo(() => { try { JSON.parse(inputJson); return true; } catch { return false; } }, [inputJson]); const handleSubmit = () => { const toolCallInfo = callTool(serverInfo, selectedTool, JSON.parse(inputJson)); addToolCall(serverName, toolCallInfo); }; return (
{ e.preventDefault(); handleSubmit(); }}>