@@ -159,6 +159,16 @@ enum LoadingMsg {
159159 Terminate { still_loading : Vec < String > } ,
160160}
161161
162+ /// Used to denote the loading outcome associated with a server.
163+ /// This is mainly used in the non-interactive mode to determine if there is any fatal errors to
164+ /// surface (since we would only want to surface fatal errors in non-interactive mode).
165+ #[ derive( Clone , Debug ) ]
166+ pub enum LoadingRecord {
167+ Success ( String ) ,
168+ Warn ( String ) ,
169+ Err ( String ) ,
170+ }
171+
162172// This is to mirror claude's config set up
163173#[ derive( Clone , Serialize , Deserialize , Debug , Default ) ]
164174#[ serde( rename_all = "camelCase" ) ]
@@ -399,7 +409,7 @@ impl ToolManagerBuilder {
399409 let notify = Arc :: new ( Notify :: new ( ) ) ;
400410 let notify_weak = Arc :: downgrade ( & notify) ;
401411 let completed_clone = completed. clone ( ) ;
402- let load_record = Arc :: new ( Mutex :: new ( HashMap :: < String , String > :: new ( ) ) ) ;
412+ let load_record = Arc :: new ( Mutex :: new ( HashMap :: < String , Vec < LoadingRecord > > :: new ( ) ) ) ;
403413 let load_record_clone = load_record. clone ( ) ;
404414 tokio:: spawn ( async move {
405415 let mut record_temp_buf = Vec :: < u8 > :: new ( ) ;
@@ -463,10 +473,10 @@ impl ToolManagerBuilder {
463473 has_new_stuff_clone. store ( true , Ordering :: Release ) ;
464474 // Maintain a record of the server load:
465475 let mut buf_writer = BufWriter :: new ( & mut record_temp_buf) ;
466- if let Err ( e) = process_result {
476+ if let Err ( e) = & process_result {
467477 let _ = queue_warn_message (
468478 server_name. as_str ( ) ,
469- & e,
479+ e,
470480 time_taken. as_str ( ) ,
471481 & mut buf_writer,
472482 ) ;
@@ -480,32 +490,38 @@ impl ToolManagerBuilder {
480490 let _ = buf_writer. flush ( ) ;
481491 drop ( buf_writer) ;
482492 let record = String :: from_utf8_lossy ( & record_temp_buf) . to_string ( ) ;
493+ let record = if process_result. is_err ( ) {
494+ LoadingRecord :: Warn ( record)
495+ } else {
496+ LoadingRecord :: Success ( record)
497+ } ;
483498 load_record_clone
484499 . lock ( )
485500 . await
486501 . entry ( server_name)
487502 . and_modify ( |load_record| {
488- load_record. push_str ( "\n --- tools refreshed ---\n " ) ;
489- load_record. push_str ( record. as_str ( ) ) ;
503+ load_record. push ( record. clone ( ) ) ;
490504 } )
491- . or_insert ( record) ;
505+ . or_insert ( vec ! [ record] ) ;
492506 } ,
493507 Err ( e) => {
508+ // Log error to chat Log
509+ error ! ( "Error loading server {server_name}: {:?}" , e) ;
494510 // Maintain a record of the server load:
495511 let mut buf_writer = BufWriter :: new ( & mut record_temp_buf) ;
496512 let _ = queue_failure_message ( server_name. as_str ( ) , & e, & time_taken, & mut buf_writer) ;
497513 let _ = buf_writer. flush ( ) ;
498514 drop ( buf_writer) ;
499515 let record = String :: from_utf8_lossy ( & record_temp_buf) . to_string ( ) ;
516+ let record = LoadingRecord :: Err ( record) ;
500517 load_record_clone
501518 . lock ( )
502519 . await
503520 . entry ( server_name. clone ( ) )
504521 . and_modify ( |load_record| {
505- load_record. push_str ( "\n --- tools refreshed ---\n " ) ;
506- load_record. push_str ( record. as_str ( ) ) ;
522+ load_record. push ( record. clone ( ) ) ;
507523 } )
508- . or_insert ( record) ;
524+ . or_insert ( vec ! [ record] ) ;
509525 // Errors surfaced at this point (i.e. before [process_tool_specs]
510526 // is called) are fatals and should be considered errors
511527 if let Some ( sender) = & loading_status_sender_clone {
@@ -762,7 +778,7 @@ pub struct ToolManager {
762778 /// (which may be different than how it is written in the config, depending of the presence of
763779 /// invalid characters).
764780 /// The value is the load message (i.e. load time, warnings, and errors)
765- pub mcp_load_record : Arc < Mutex < HashMap < String , String > > > ,
781+ pub mcp_load_record : Arc < Mutex < HashMap < String , Vec < LoadingRecord > > > > ,
766782}
767783
768784impl Clone for ToolManager {
@@ -829,16 +845,7 @@ impl ToolManager {
829845 . settings
830846 . get_int ( Setting :: McpNoInteractiveTimeout )
831847 . map_or ( 30_000_u64 , |s| s as u64 ) ;
832- Box :: pin ( async move {
833- tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( init_timeout) ) . await ;
834- let _ = queue ! (
835- output,
836- style:: Print (
837- "Not all mcp servers loaded. Configure no-interactive timeout with q settings mcp.noInteractiveTimeout"
838- ) ,
839- style:: Print ( "\n " )
840- ) ;
841- } )
848+ Box :: pin ( tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( init_timeout) ) )
842849 } ;
843850 let server_loading_fut: Pin < Box < dyn Future < Output = ( ) > > > = if let Some ( notify) = notify {
844851 Box :: pin ( async move { notify. notified ( ) . await } )
@@ -851,6 +858,13 @@ impl ToolManager {
851858 let still_loading = self . pending_clients. read( ) . await . iter( ) . cloned( ) . collect:: <Vec <_>>( ) ;
852859 let _ = tx. send( LoadingMsg :: Terminate { still_loading } ) . await ;
853860 }
861+ let _ = queue!(
862+ output,
863+ style:: Print (
864+ "Not all mcp servers loaded. Configure no-interactive timeout with q settings mcp.noInteractiveTimeout"
865+ ) ,
866+ style:: Print ( "\n ------\n " )
867+ ) ;
854868 } ,
855869 _ = server_loading_fut => {
856870 if let Some ( tx) = tx {
@@ -869,6 +883,22 @@ impl ToolManager {
869883 }
870884 }
871885 }
886+ if !self . is_interactive
887+ && self
888+ . mcp_load_record
889+ . lock ( )
890+ . await
891+ . iter ( )
892+ . any ( |( _, records) | records. iter ( ) . any ( |record| matches ! ( record, LoadingRecord :: Err ( _) ) ) )
893+ {
894+ queue ! (
895+ output,
896+ style:: Print (
897+ "One or more mcp server did not load correctly. See $TMPDIR/qlog/chat.log for more details."
898+ ) ,
899+ style:: Print ( "\n ------\n " )
900+ ) ?;
901+ }
872902 self . update ( ) . await ;
873903 Ok ( self . schema . clone ( ) )
874904 }
0 commit comments