77using System . Text . Json ;
88using System . Text . Json . Nodes ;
99using System . Text . Json . Serialization . Metadata ;
10- using System . Threading . Channels ;
1110
1211namespace ModelContextProtocol . Server ;
1312
@@ -211,10 +210,7 @@ public override async ValueTask DisposeAsync()
211210 {
212211 if ( _mrtrContinuations . TryRemove ( kvp . Key , out var continuation ) )
213212 {
214- foreach ( var exchange in continuation . PendingExchanges )
215- {
216- exchange . ResponseTcs . TrySetCanceled ( ) ;
217- }
213+ continuation . PendingExchange . ResponseTcs . TrySetCanceled ( ) ;
218214 }
219215 }
220216
@@ -1192,19 +1188,20 @@ private void WrapHandlerWithMrtr(string method)
11921188 inputResponses = JsonSerializer . Deserialize ( responsesNode , McpJsonUtilities . JsonContext . Default . IDictionaryStringInputResponse ) ;
11931189 }
11941190
1195- // Complete pending exchanges with the client's responses.
1196- foreach ( var exchange in continuation . PendingExchanges )
1191+ // Prepare for the next potential exchange before resuming the handler.
1192+ continuation . MrtrContext . ResetForNextExchange ( ) ;
1193+
1194+ // Complete the pending exchange with the client's response.
1195+ var exchange = continuation . PendingExchange ;
1196+ if ( inputResponses is not null &&
1197+ inputResponses . TryGetValue ( exchange . Key , out var response ) )
11971198 {
1198- if ( inputResponses is not null &&
1199- inputResponses . TryGetValue ( exchange . Key , out var response ) )
1200- {
1201- exchange . ResponseTcs . TrySetResult ( response ) ;
1202- }
1203- else
1204- {
1205- exchange . ResponseTcs . TrySetException (
1206- new McpProtocolException ( $ "Missing input response for key '{ exchange . Key } '.", McpErrorCode . InvalidParams ) ) ;
1207- }
1199+ exchange . ResponseTcs . TrySetResult ( response ) ;
1200+ }
1201+ else
1202+ {
1203+ exchange . ResponseTcs . TrySetException (
1204+ new McpProtocolException ( $ "Missing input response for key '{ exchange . Key } '.", McpErrorCode . InvalidParams ) ) ;
12081205 }
12091206
12101207 // Race again: handler completion vs new exchange.
@@ -1228,7 +1225,7 @@ private void WrapHandlerWithMrtr(string method)
12281225 Task < JsonNode ? > handlerTask ;
12291226 try
12301227 {
1231- handlerTask = InvokeOriginalHandlerAsync ( originalHandler , request , mrtrContext , cancellationToken ) ;
1228+ handlerTask = originalHandler ( request , cancellationToken ) ;
12321229 }
12331230 finally
12341231 {
@@ -1241,31 +1238,7 @@ private void WrapHandlerWithMrtr(string method)
12411238 }
12421239
12431240 /// <summary>
1244- /// Invokes the original request handler and marks the MrtrContext as complete when done.
1245- /// </summary>
1246- private static async Task < JsonNode ? > InvokeOriginalHandlerAsync (
1247- Func < JsonRpcRequest , CancellationToken , Task < JsonNode ? > > handler ,
1248- JsonRpcRequest request ,
1249- MrtrContext mrtrContext ,
1250- CancellationToken cancellationToken )
1251- {
1252- try
1253- {
1254- return await handler ( request , cancellationToken ) . ConfigureAwait ( false ) ;
1255- }
1256- catch ( Exception ex )
1257- {
1258- mrtrContext . Fault ( ex ) ;
1259- throw ;
1260- }
1261- finally
1262- {
1263- mrtrContext . Complete ( ) ;
1264- }
1265- }
1266-
1267- /// <summary>
1268- /// Races between handler completion and the MrtrContext exchange channel.
1241+ /// Races between handler completion and the MrtrContext exchange TCS.
12691242 /// If the handler completes, returns its result. If an exchange arrives (handler needs input),
12701243 /// builds and returns an IncompleteResult and stores the continuation for future retries.
12711244 /// </summary>
@@ -1280,10 +1253,7 @@ private void WrapHandlerWithMrtr(string method)
12801253 return await handlerTask . ConfigureAwait ( false ) ;
12811254 }
12821255
1283- // Start reading from the exchange channel.
1284- var readTask = mrtrContext . ExchangeReader . ReadAsync ( cancellationToken ) . AsTask ( ) ;
1285-
1286- var completedTask = await Task . WhenAny ( handlerTask , readTask ) . ConfigureAwait ( false ) ;
1256+ var completedTask = await Task . WhenAny ( handlerTask , mrtrContext . ExchangeTask ) . ConfigureAwait ( false ) ;
12871257
12881258 if ( completedTask == handlerTask )
12891259 {
@@ -1292,40 +1262,17 @@ private void WrapHandlerWithMrtr(string method)
12921262 }
12931263
12941264 // Exchange arrived - handler needs input from the client.
1295- MrtrExchange firstExchange ;
1296- try
1297- {
1298- firstExchange = await readTask . ConfigureAwait ( false ) ;
1299- }
1300- catch ( ChannelClosedException )
1301- {
1302- // Channel was closed (handler completed between WhenAny and ReadAsync).
1303- return await handlerTask . ConfigureAwait ( false ) ;
1304- }
1305-
1306- // Collect all currently available exchanges (handles concurrent ElicitAsync/SampleAsync calls).
1307- var exchanges = new List < MrtrExchange > { firstExchange } ;
1308- while ( mrtrContext . ExchangeReader . TryRead ( out var additionalExchange ) )
1309- {
1310- exchanges . Add ( additionalExchange ) ;
1311- }
1312-
1313- // Build the IncompleteResult with input requests.
1314- var inputRequests = new Dictionary < string , InputRequest > ( exchanges . Count ) ;
1315- foreach ( var exchange in exchanges )
1316- {
1317- inputRequests [ exchange . Key ] = exchange . InputRequest ;
1318- }
1265+ var exchange = await mrtrContext . ExchangeTask . ConfigureAwait ( false ) ;
13191266
13201267 var correlationId = Guid . NewGuid ( ) . ToString ( "N" ) ;
13211268 var incompleteResult = new IncompleteResult
13221269 {
1323- InputRequests = inputRequests ,
1270+ InputRequests = new Dictionary < string , InputRequest > { [ exchange . Key ] = exchange . InputRequest } ,
13241271 RequestState = correlationId ,
13251272 } ;
13261273
13271274 // Store the continuation so the retry can resume the handler.
1328- _mrtrContinuations [ correlationId ] = new MrtrContinuation ( handlerTask , mrtrContext , exchanges ) ;
1275+ _mrtrContinuations [ correlationId ] = new MrtrContinuation ( handlerTask , mrtrContext , exchange ) ;
13291276
13301277 return JsonSerializer . SerializeToNode ( incompleteResult , McpJsonUtilities . JsonContext . Default . IncompleteResult ) ;
13311278 }
0 commit comments