@@ -4,113 +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- ] as const ;
17-
18- function serverUrl ( port : number ) : string {
19- return `http://localhost:${ port } /mcp` ;
20- }
21-
22- // Cache server connections to avoid reconnecting when switching between servers
23- const serverInfoCache = new Map < number , Promise < ServerInfo > > ( ) ;
24-
25- function getServerInfo ( port : number ) : Promise < ServerInfo > {
26- let promise = serverInfoCache . get ( port ) ;
27- if ( ! promise ) {
28- promise = connectToServer ( new URL ( serverUrl ( port ) ) ) ;
29- // Remove from cache on failure so retry is possible
30- promise . catch ( ( ) => serverInfoCache . delete ( port ) ) ;
31- serverInfoCache . set ( port , promise ) ;
32- }
33- return promise ;
34- }
35-
36-
377// Wrapper to track server name with each tool call
388interface ToolCallEntry {
399 serverName : string ;
4010 info : ToolCallInfo ;
4111}
4212
43- // Host just manages tool call results - no server dependency
44- 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 ) ;
4519 const [ toolCalls , setToolCalls ] = useState < ToolCallEntry [ ] > ( [ ] ) ;
4620
21+ if ( servers . length === 0 ) {
22+ return < p > No servers configured. Set SERVERS environment variable.</ p > ;
23+ }
24+
4725 return (
4826 < >
4927 { toolCalls . map ( ( entry , i ) => (
5028 < ToolCallInfoPanel key = { i } serverName = { entry . serverName } toolCallInfo = { entry . info } />
5129 ) ) }
5230 < CallToolPanel
31+ servers = { servers }
5332 addToolCall = { ( serverName , info ) => setToolCalls ( [ ...toolCalls , { serverName, info } ] ) }
5433 />
5534 </ >
5635 ) ;
5736}
5837
5938
60- // CallToolPanel includes server selection with its own Suspense boundary
39+ // CallToolPanel manages server selection from already-connected servers
6140interface CallToolPanelProps {
41+ servers : ServerInfo [ ] ;
6242 addToolCall : ( serverName : string , info : ToolCallInfo ) => void ;
6343}
64- function CallToolPanel ( { addToolCall } : CallToolPanelProps ) {
65- const [ selectedServer , setSelectedServer ] = useState ( SERVERS [ 0 ] ) ;
66- const [ serverInfoPromise , setServerInfoPromise ] = useState (
67- ( ) => getServerInfo ( selectedServer . port )
68- ) ;
69-
70- const handleServerChange = ( port : number ) => {
71- const server = SERVERS . find ( s => s . port === port ) ?? SERVERS [ 0 ] ;
72- setSelectedServer ( server ) ;
73- setServerInfoPromise ( getServerInfo ( port ) ) ;
74- } ;
44+ function CallToolPanel ( { servers, addToolCall } : CallToolPanelProps ) {
45+ const [ selectedIndex , setSelectedIndex ] = useState ( 0 ) ;
46+ const selectedServer = servers [ selectedIndex ] ;
7547
7648 return (
7749 < div className = { styles . callToolPanel } >
7850 < label >
7951 Server
8052 < select
81- value = { selectedServer . port }
82- onChange = { ( e ) => handleServerChange ( Number ( e . target . value ) ) }
53+ value = { selectedIndex }
54+ onChange = { ( e ) => setSelectedIndex ( Number ( e . target . value ) ) }
8355 >
84- { SERVERS . map ( ( { name , port } ) => (
85- < option key = { port } value = { port } >
86- { name } (: { port } )
56+ { servers . map ( ( server , i ) => (
57+ < option key = { i } value = { i } >
58+ { server . name }
8759 </ option >
8860 ) ) }
8961 </ select >
9062 </ label >
91- < ErrorBoundary >
92- < Suspense fallback = { < p className = { styles . connecting } > Connecting to { serverUrl ( selectedServer . port ) } ...</ p > } >
93- < ToolCallForm
94- key = { selectedServer . port }
95- serverName = { selectedServer . name }
96- serverInfoPromise = { serverInfoPromise }
97- addToolCall = { addToolCall }
98- />
99- </ Suspense >
100- </ ErrorBoundary >
63+ < ToolCallForm
64+ key = { selectedIndex }
65+ serverName = { selectedServer . name }
66+ serverInfo = { selectedServer }
67+ addToolCall = { addToolCall }
68+ />
10169 </ div >
10270 ) ;
10371}
10472
10573
106- // ToolCallForm renders inside Suspense - needs serverInfo for tool list
74+ // ToolCallForm receives already-resolved serverInfo
10775interface ToolCallFormProps {
10876 serverName : string ;
109- serverInfoPromise : Promise < ServerInfo > ;
77+ serverInfo : ServerInfo ;
11078 addToolCall : ( serverName : string , info : ToolCallInfo ) => void ;
11179}
112- function ToolCallForm ( { serverName, serverInfoPromise, addToolCall } : ToolCallFormProps ) {
113- const serverInfo = use ( serverInfoPromise ) ;
80+ function ToolCallForm ( { serverName, serverInfo, addToolCall } : ToolCallFormProps ) {
11481 const toolNames = Array . from ( serverInfo . tools . keys ( ) ) ;
11582 const [ selectedTool , setSelectedTool ] = useState ( toolNames [ 0 ] ?? "" ) ;
11683 const [ inputJson , setInputJson ] = useState ( "{}" ) ;
@@ -263,8 +230,18 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
263230}
264231
265232
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+
266239createRoot ( document . getElementById ( "root" ) ! ) . render (
267240 < StrictMode >
268- < Host />
241+ < ErrorBoundary >
242+ < Suspense fallback = { < p className = { styles . connecting } > Connecting to servers...</ p > } >
243+ < Host serversPromise = { connectToAllServers ( ) } />
244+ </ Suspense >
245+ </ ErrorBoundary >
269246 </ StrictMode > ,
270247) ;
0 commit comments