@@ -18,6 +18,9 @@ use serde_json;
1818// Global runtime - one runtime per process that stays alive
1919static GLOBAL_RUNTIME : OnceLock < tokio:: runtime:: Runtime > = OnceLock :: new ( ) ;
2020
21+ // Global runtime enter guard - keeps runtime as current for the entire process (Windows fix)
22+ static GLOBAL_RUNTIME_GUARD : OnceLock < Mutex < Option < tokio:: runtime:: EnterGuard < ' static > > > > = OnceLock :: new ( ) ;
23+
2124// Global client instance - one client per process
2225static GLOBAL_CLIENT : OnceLock < Mutex < Option < McpClient > > > = OnceLock :: new ( ) ;
2326
@@ -244,11 +247,24 @@ pub struct McpClient {
244247 server_url : Mutex < Option < String > > ,
245248}
246249
247- /// Get or create the global Tokio runtime
250+ /// Get or create the global Tokio runtime and ensure it's entered
248251fn get_runtime ( ) -> & ' static tokio:: runtime:: Runtime {
249- GLOBAL_RUNTIME . get_or_init ( || {
252+ let runtime = GLOBAL_RUNTIME . get_or_init ( || {
250253 tokio:: runtime:: Runtime :: new ( ) . expect ( "Failed to create Tokio runtime" )
251- } )
254+ } ) ;
255+
256+ // On first call, enter the runtime and keep the guard alive forever (Windows fix for nested spawns)
257+ GLOBAL_RUNTIME_GUARD . get_or_init ( || {
258+ // SAFETY: The runtime is stored in a static and lives for the entire program duration
259+ let guard = unsafe {
260+ let runtime_ptr: * const tokio:: runtime:: Runtime = runtime;
261+ let runtime_ref: & ' static tokio:: runtime:: Runtime = & * runtime_ptr;
262+ runtime_ref. enter ( )
263+ } ;
264+ Mutex :: new ( Some ( guard) )
265+ } ) ;
266+
267+ runtime
252268}
253269
254270/// Create a new MCP client
0 commit comments