@@ -4,114 +4,80 @@ import { callTool, connectToServer, hasAppHtml, initializeApp, loadSandboxProxy,
44import styles from "./index.module.css" ;
55
66
7- // Available MCP servers - using ports 3101+ to avoid conflicts with common dev ports
8- const SERVERS = [
9- { name : "Basic React" , port : 3101 } ,
10- { name : "Vanilla JS" , port : 3102 } ,
11- { name : "Budget Allocator" , port : 3103 } ,
12- { name : "Cohort Heatmap" , port : 3104 } ,
13- { name : "Customer Segmentation" , port : 3105 } ,
14- { name : "Scenario Modeler" , port : 3106 } ,
15- { name : "System Monitor" , port : 3107 } ,
16- { name : "Three.js" , port : 3109 } ,
17- ] as const ;
18-
19- function serverUrl ( port : number ) : string {
20- return `http://localhost:${ port } /mcp` ;
21- }
22-
23- // Cache server connections to avoid reconnecting when switching between servers
24- const serverInfoCache = new Map < number , Promise < ServerInfo > > ( ) ;
25-
26- function getServerInfo ( port : number ) : Promise < ServerInfo > {
27- let promise = serverInfoCache . get ( port ) ;
28- if ( ! promise ) {
29- promise = connectToServer ( new URL ( serverUrl ( port ) ) ) ;
30- // Remove from cache on failure so retry is possible
31- promise . catch ( ( ) => serverInfoCache . delete ( port ) ) ;
32- serverInfoCache . set ( port , promise ) ;
33- }
34- return promise ;
35- }
36-
37-
387// Wrapper to track server name with each tool call
398interface ToolCallEntry {
409 serverName : string ;
4110 info : ToolCallInfo ;
4211}
4312
44- // Host just manages tool call results - no server dependency
45- function Host ( ) {
13+ // Host receives connected servers via promise, uses single use() call
14+ interface HostProps {
15+ serversPromise : Promise < ServerInfo [ ] > ;
16+ }
17+ function Host ( { serversPromise } : HostProps ) {
18+ const servers = use ( serversPromise ) ;
4619 const [ toolCalls , setToolCalls ] = useState < ToolCallEntry [ ] > ( [ ] ) ;
4720
21+ if ( servers . length === 0 ) {
22+ return < p > No servers configured. Set SERVERS environment variable.</ p > ;
23+ }
24+
4825 return (
4926 < >
5027 { toolCalls . map ( ( entry , i ) => (
5128 < ToolCallInfoPanel key = { i } serverName = { entry . serverName } toolCallInfo = { entry . info } />
5229 ) ) }
5330 < CallToolPanel
31+ servers = { servers }
5432 addToolCall = { ( serverName , info ) => setToolCalls ( [ ...toolCalls , { serverName, info } ] ) }
5533 />
5634 </ >
5735 ) ;
5836}
5937
6038
61- // CallToolPanel includes server selection with its own Suspense boundary
39+ // CallToolPanel manages server selection from already-connected servers
6240interface CallToolPanelProps {
41+ servers : ServerInfo [ ] ;
6342 addToolCall : ( serverName : string , info : ToolCallInfo ) => void ;
6443}
65- function CallToolPanel ( { addToolCall } : CallToolPanelProps ) {
66- const [ selectedServer , setSelectedServer ] = useState ( SERVERS [ 0 ] ) ;
67- const [ serverInfoPromise , setServerInfoPromise ] = useState (
68- ( ) => getServerInfo ( selectedServer . port )
69- ) ;
70-
71- const handleServerChange = ( port : number ) => {
72- const server = SERVERS . find ( s => s . port === port ) ?? SERVERS [ 0 ] ;
73- setSelectedServer ( server ) ;
74- setServerInfoPromise ( getServerInfo ( port ) ) ;
75- } ;
44+ function CallToolPanel ( { servers, addToolCall } : CallToolPanelProps ) {
45+ const [ selectedIndex , setSelectedIndex ] = useState ( 0 ) ;
46+ const selectedServer = servers [ selectedIndex ] ;
7647
7748 return (
7849 < div className = { styles . callToolPanel } >
7950 < label >
8051 Server
8152 < select
82- value = { selectedServer . port }
83- onChange = { ( e ) => handleServerChange ( Number ( e . target . value ) ) }
53+ value = { selectedIndex }
54+ onChange = { ( e ) => setSelectedIndex ( Number ( e . target . value ) ) }
8455 >
85- { SERVERS . map ( ( { name , port } ) => (
86- < option key = { port } value = { port } >
87- { name } (: { port } )
56+ { servers . map ( ( server , i ) => (
57+ < option key = { i } value = { i } >
58+ { server . name }
8859 </ option >
8960 ) ) }
9061 </ select >
9162 </ label >
92- < ErrorBoundary >
93- < Suspense fallback = { < p className = { styles . connecting } > Connecting to { serverUrl ( selectedServer . port ) } ...</ p > } >
94- < ToolCallForm
95- key = { selectedServer . port }
96- serverName = { selectedServer . name }
97- serverInfoPromise = { serverInfoPromise }
98- addToolCall = { addToolCall }
99- />
100- </ Suspense >
101- </ ErrorBoundary >
63+ < ToolCallForm
64+ key = { selectedIndex }
65+ serverName = { selectedServer . name }
66+ serverInfo = { selectedServer }
67+ addToolCall = { addToolCall }
68+ />
10269 </ div >
10370 ) ;
10471}
10572
10673
107- // ToolCallForm renders inside Suspense - needs serverInfo for tool list
74+ // ToolCallForm receives already-resolved serverInfo
10875interface ToolCallFormProps {
10976 serverName : string ;
110- serverInfoPromise : Promise < ServerInfo > ;
77+ serverInfo : ServerInfo ;
11178 addToolCall : ( serverName : string , info : ToolCallInfo ) => void ;
11279}
113- function ToolCallForm ( { serverName, serverInfoPromise, addToolCall } : ToolCallFormProps ) {
114- const serverInfo = use ( serverInfoPromise ) ;
80+ function ToolCallForm ( { serverName, serverInfo, addToolCall } : ToolCallFormProps ) {
11581 const toolNames = Array . from ( serverInfo . tools . keys ( ) ) ;
11682 const [ selectedTool , setSelectedTool ] = useState ( toolNames [ 0 ] ?? "" ) ;
11783 const [ inputJson , setInputJson ] = useState ( "{}" ) ;
@@ -264,8 +230,18 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
264230}
265231
266232
233+ async function connectToAllServers ( ) : Promise < ServerInfo [ ] > {
234+ const serverUrlsResponse = await fetch ( "/api/servers" ) ;
235+ const serverUrls = ( await serverUrlsResponse . json ( ) ) as string [ ] ;
236+ return Promise . all ( serverUrls . map ( ( url ) => connectToServer ( new URL ( url ) ) ) ) ;
237+ }
238+
267239createRoot ( document . getElementById ( "root" ) ! ) . render (
268240 < StrictMode >
269- < Host />
241+ < ErrorBoundary >
242+ < Suspense fallback = { < p className = { styles . connecting } > Connecting to servers...</ p > } >
243+ < Host serversPromise = { connectToAllServers ( ) } />
244+ </ Suspense >
245+ </ ErrorBoundary >
270246 </ StrictMode > ,
271247) ;
0 commit comments