@@ -239,8 +239,17 @@ export class MCPServerEndpoint {
239239 // Setup capability synchronization once
240240 this . setupCapabilitySync ( ) ;
241241
242- // Initial capability registration
243- this . syncCapabilities ( ) ;
242+ // Initial capability registration - only sync if there are already connected servers
243+ // This prevents empty tool lists during hub initialization
244+ const hasConnectedServers = Array . from (
245+ this . mcpHub . connections . values ( ) ,
246+ ) . some ( ( conn ) => conn . status === 'connected' ) ;
247+
248+ if ( hasConnectedServers ) {
249+ this . syncCapabilities ( ) ;
250+ }
251+ // If no servers are connected yet, syncCapabilities will be called automatically
252+ // when servers connect via the hubStateChanged event listener
244253 }
245254
246255 getEndpointUrl ( ) : string {
@@ -298,6 +307,13 @@ export class MCPServerEndpoint {
298307 // Setup list handler if schema exists
299308 if ( capType . listSchema ) {
300309 server . setRequestHandler ( capType . listSchema , async ( ) => {
310+ // Wait for servers to be ready before returning the list
311+ // This handles the case where endpoint was created before servers finished connecting
312+ await this . waitForServersReady ( ) ;
313+
314+ // Sync capabilities after servers are ready
315+ this . syncCapabilities ( [ capId ] ) ;
316+
301317 const capabilityMap = this . registeredCapabilities [ capId ] ;
302318 let capabilities = Array . from ( capabilityMap . values ( ) ) ;
303319 const searchTerms =
@@ -533,6 +549,90 @@ export class MCPServerEndpoint {
533549 } ) ;
534550 }
535551
552+ /**
553+ * Wait for all servers to be ready (connected or failed)
554+ * This prevents returning empty capability lists during server initialization
555+ */
556+ async waitForServersReady ( ) : Promise < void > {
557+ const timeout = 30000 ; // 30 seconds total timeout
558+ const startTime = Date . now ( ) ;
559+
560+ // First, wait for connections to be created (if hub is still initializing)
561+ while ( true ) {
562+ const connections = Array . from ( this . mcpHub . connections . values ( ) ) ;
563+
564+ logger . debug (
565+ `waitForServersReady: checking ${ connections . length } connections` ,
566+ ) ;
567+
568+ if ( connections . length > 0 ) {
569+ // Connections exist, break out of waiting loop
570+ break ;
571+ }
572+
573+ if ( Date . now ( ) - startTime > timeout ) {
574+ // Timeout waiting for connections to be created
575+ logger . debug (
576+ 'waitForServersReady: no connections created within timeout' ,
577+ ) ;
578+ return ;
579+ }
580+
581+ // Wait a bit and check again
582+ await new Promise ( ( resolve ) => setTimeout ( resolve , 100 ) ) ;
583+ }
584+
585+ // Now wait for all connections to finish connecting
586+ const connections = Array . from ( this . mcpHub . connections . values ( ) ) ;
587+
588+ // Check if any servers are still connecting
589+ const connectingServers = connections . filter (
590+ ( conn ) => conn . status === 'connecting' && ! conn . disabled ,
591+ ) ;
592+
593+ logger . debug (
594+ `waitForServersReady: ${ connectingServers . length } servers still connecting` ,
595+ {
596+ connecting : connectingServers . map ( ( c ) => c . name ) ,
597+ } ,
598+ ) ;
599+
600+ if ( connectingServers . length === 0 ) {
601+ // All servers are already in a final state (connected/disconnected)
602+ logger . debug ( 'waitForServersReady: all servers in final state' ) ;
603+ return ;
604+ }
605+
606+ // Wait for all connecting servers to finish (reuse timeout from above)
607+ logger . debug ( 'waitForServersReady: waiting for servers to finish...' ) ;
608+
609+ while ( true ) {
610+ const stillConnecting = Array . from (
611+ this . mcpHub . connections . values ( ) ,
612+ ) . filter ( ( conn ) => conn . status === 'connecting' && ! conn . disabled ) ;
613+
614+ if ( stillConnecting . length === 0 ) {
615+ // All servers have finished connecting
616+ logger . debug ( 'waitForServersReady: all servers finished connecting' ) ;
617+ break ;
618+ }
619+
620+ if ( Date . now ( ) - startTime > timeout ) {
621+ // Timeout - log warning but continue
622+ logger . warn (
623+ `Timeout waiting for ${ stillConnecting . length } servers to connect` ,
624+ {
625+ servers : stillConnecting . map ( ( c ) => c . name ) ,
626+ } ,
627+ ) ;
628+ break ;
629+ }
630+
631+ // Wait a bit before checking again
632+ await new Promise ( ( resolve ) => setTimeout ( resolve , 100 ) ) ;
633+ }
634+ }
635+
536636 /**
537637 * Synchronize the servers map with current connection states
538638 * Creates safe server IDs for namespacing capabilities
0 commit comments