@@ -1241,6 +1241,60 @@ await transport.SendClientMessageAsync(new JsonRpcNotification
12411241 await runTask ;
12421242 }
12431243
1244+ [ Fact ]
1245+ public async Task RunAsync_WaitsForInFlightHandlersBeforeReturning ( )
1246+ {
1247+ // Arrange: Create a tool handler that blocks until we release it.
1248+ var handlerStarted = new TaskCompletionSource < bool > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
1249+ var releaseHandler = new TaskCompletionSource < bool > ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
1250+ bool handlerCompleted = false ;
1251+
1252+ await using var transport = new TestServerTransport ( ) ;
1253+ var options = CreateOptions ( new ServerCapabilities { Tools = new ( ) } ) ;
1254+ options . Handlers . CallToolHandler = async ( request , ct ) =>
1255+ {
1256+ handlerStarted . SetResult ( true ) ;
1257+ await releaseHandler . Task ;
1258+ handlerCompleted = true ;
1259+ return new CallToolResult { Content = [ new TextContentBlock { Text = "done" } ] } ;
1260+ } ;
1261+ options . Handlers . ListToolsHandler = ( request , ct ) => throw new NotImplementedException ( ) ;
1262+
1263+ await using var server = McpServer . Create ( transport , options , LoggerFactory ) ;
1264+ var runTask = server . RunAsync ( TestContext . Current . CancellationToken ) ;
1265+
1266+ // Send a tool call request.
1267+ await transport . SendClientMessageAsync (
1268+ new JsonRpcRequest
1269+ {
1270+ Method = RequestMethods . ToolsCall ,
1271+ Id = new RequestId ( 1 )
1272+ } ,
1273+ TestContext . Current . CancellationToken ) ;
1274+
1275+ // Wait for the handler to start executing.
1276+ await handlerStarted . Task . WaitAsync ( TestConstants . DefaultTimeout , TestContext . Current . CancellationToken ) ;
1277+
1278+ // Dispose the transport to simulate client disconnect while the handler is still running.
1279+ await transport . DisposeAsync ( ) ;
1280+
1281+ // Release the handler after a delay, giving ProcessMessagesCoreAsync time to notice the
1282+ // channel closed. Without the fix, RunAsync would return before the handler completes.
1283+ var ct = TestContext . Current . CancellationToken ;
1284+ _ = Task . Run ( async ( ) =>
1285+ {
1286+ await Task . Delay ( 200 , ct ) ;
1287+ releaseHandler . SetResult ( true ) ;
1288+ } , ct ) ;
1289+
1290+ // Wait for RunAsync to complete.
1291+ await runTask . WaitAsync ( TestConstants . DefaultTimeout , TestContext . Current . CancellationToken ) ;
1292+
1293+ // With the fix, RunAsync waits for in-flight handlers. Without it, it returns immediately
1294+ // after the transport closes (before the 500ms delay releases the handler).
1295+ Assert . True ( handlerCompleted , "RunAsync should wait for in-flight handlers to complete before returning." ) ;
1296+ }
1297+
12441298 private static async Task InitializeServerAsync ( TestServerTransport transport , ClientCapabilities capabilities , CancellationToken cancellationToken = default )
12451299 {
12461300 var initializeRequest = new JsonRpcRequest
0 commit comments