@@ -29,7 +29,6 @@ protected override void ConfigureServices(ServiceCollection services, IMcpServer
29
29
}
30
30
services . AddSingleton ( McpServerTool . Create ( [ McpServerTool ( Destructive = false , OpenWorld = true ) ] ( string i ) => $ "{ i } Result", new ( ) { Name = "ValuesSetViaAttr" } ) ) ;
31
31
services . AddSingleton ( McpServerTool . Create ( [ McpServerTool ( Destructive = false , OpenWorld = true ) ] ( string i ) => $ "{ i } Result", new ( ) { Name = "ValuesSetViaOptions" , Destructive = true , OpenWorld = false , ReadOnly = true } ) ) ;
32
-
33
32
}
34
33
35
34
[ Theory ]
@@ -209,7 +208,7 @@ public async Task CreateSamplingHandler_ShouldHandleResourceMessages()
209
208
[ Fact ]
210
209
public async Task ListToolsAsync_AllToolsReturned ( )
211
210
{
212
- IMcpClient client = await CreateMcpClientForServer ( ) ;
211
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
213
212
214
213
var tools = await client . ListToolsAsync ( cancellationToken : TestContext . Current . CancellationToken ) ;
215
214
Assert . Equal ( 12 , tools . Count ) ;
@@ -235,7 +234,7 @@ public async Task ListToolsAsync_AllToolsReturned()
235
234
[ Fact ]
236
235
public async Task EnumerateToolsAsync_AllToolsReturned ( )
237
236
{
238
- IMcpClient client = await CreateMcpClientForServer ( ) ;
237
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
239
238
240
239
await foreach ( var tool in client . EnumerateToolsAsync ( cancellationToken : TestContext . Current . CancellationToken ) )
241
240
{
@@ -254,7 +253,7 @@ public async Task EnumerateToolsAsync_AllToolsReturned()
254
253
public async Task EnumerateToolsAsync_FlowsJsonSerializerOptions ( )
255
254
{
256
255
JsonSerializerOptions options = new ( JsonSerializerOptions . Default ) ;
257
- IMcpClient client = await CreateMcpClientForServer ( ) ;
256
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
258
257
bool hasTools = false ;
259
258
260
259
await foreach ( var tool in client . EnumerateToolsAsync ( options , TestContext . Current . CancellationToken ) )
@@ -275,7 +274,7 @@ public async Task EnumerateToolsAsync_FlowsJsonSerializerOptions()
275
274
public async Task EnumerateToolsAsync_HonorsJsonSerializerOptions ( )
276
275
{
277
276
JsonSerializerOptions emptyOptions = new ( ) { TypeInfoResolver = JsonTypeInfoResolver . Combine ( ) } ;
278
- IMcpClient client = await CreateMcpClientForServer ( ) ;
277
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
279
278
280
279
var tool = ( await client . ListToolsAsync ( emptyOptions , TestContext . Current . CancellationToken ) ) . First ( ) ;
281
280
await Assert . ThrowsAsync < NotSupportedException > ( async ( ) => await tool . InvokeAsync ( new ( ) { [ "i" ] = 42 } , TestContext . Current . CancellationToken ) ) ;
@@ -285,7 +284,7 @@ public async Task EnumerateToolsAsync_HonorsJsonSerializerOptions()
285
284
public async Task SendRequestAsync_HonorsJsonSerializerOptions ( )
286
285
{
287
286
JsonSerializerOptions emptyOptions = new ( ) { TypeInfoResolver = JsonTypeInfoResolver . Combine ( ) } ;
288
- IMcpClient client = await CreateMcpClientForServer ( ) ;
287
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
289
288
290
289
await Assert . ThrowsAsync < NotSupportedException > ( ( ) => client . SendRequestAsync < CallToolRequestParams , CallToolResponse > ( "Method4" , new ( ) { Name = "tool" } , emptyOptions , cancellationToken : TestContext . Current . CancellationToken ) ) ;
291
290
}
@@ -294,7 +293,7 @@ public async Task SendRequestAsync_HonorsJsonSerializerOptions()
294
293
public async Task SendNotificationAsync_HonorsJsonSerializerOptions ( )
295
294
{
296
295
JsonSerializerOptions emptyOptions = new ( ) { TypeInfoResolver = JsonTypeInfoResolver . Combine ( ) } ;
297
- IMcpClient client = await CreateMcpClientForServer ( ) ;
296
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
298
297
299
298
await Assert . ThrowsAsync < NotSupportedException > ( ( ) => client . SendNotificationAsync ( "Method4" , new { Value = 42 } , emptyOptions , cancellationToken : TestContext . Current . CancellationToken ) ) ;
300
299
}
@@ -303,7 +302,7 @@ public async Task SendNotificationAsync_HonorsJsonSerializerOptions()
303
302
public async Task GetPromptsAsync_HonorsJsonSerializerOptions ( )
304
303
{
305
304
JsonSerializerOptions emptyOptions = new ( ) { TypeInfoResolver = JsonTypeInfoResolver . Combine ( ) } ;
306
- IMcpClient client = await CreateMcpClientForServer ( ) ;
305
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
307
306
308
307
await Assert . ThrowsAsync < NotSupportedException > ( ( ) => client . GetPromptAsync ( "Prompt" , new Dictionary < string , object ? > { [ "i" ] = 42 } , emptyOptions , cancellationToken : TestContext . Current . CancellationToken ) ) ;
309
308
}
@@ -312,7 +311,7 @@ public async Task GetPromptsAsync_HonorsJsonSerializerOptions()
312
311
public async Task WithName_ChangesToolName ( )
313
312
{
314
313
JsonSerializerOptions options = new ( JsonSerializerOptions . Default ) ;
315
- IMcpClient client = await CreateMcpClientForServer ( ) ;
314
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
316
315
317
316
var tool = ( await client . ListToolsAsync ( options , TestContext . Current . CancellationToken ) ) . First ( ) ;
318
317
var originalName = tool . Name ;
@@ -327,7 +326,7 @@ public async Task WithName_ChangesToolName()
327
326
public async Task WithDescription_ChangesToolDescription ( )
328
327
{
329
328
JsonSerializerOptions options = new ( JsonSerializerOptions . Default ) ;
330
- IMcpClient client = await CreateMcpClientForServer ( ) ;
329
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
331
330
var tool = ( await client . ListToolsAsync ( options , TestContext . Current . CancellationToken ) ) . FirstOrDefault ( ) ;
332
331
var originalDescription = tool ? . Description ;
333
332
var redescribedTool = tool ? . WithDescription ( "ToolWithNewDescription" ) ;
@@ -336,10 +335,55 @@ public async Task WithDescription_ChangesToolDescription()
336
335
Assert . Equal ( originalDescription , tool ? . Description ) ;
337
336
}
338
337
338
+ [ Fact ]
339
+ public async Task WithProgress_ProgressReported ( )
340
+ {
341
+ const int TotalNotifications = 3 ;
342
+ int remainingProgress = TotalNotifications ;
343
+ TaskCompletionSource < bool > allProgressReceived = new ( TaskCreationOptions . RunContinuationsAsynchronously ) ;
344
+
345
+ Server . ServerOptions . Capabilities ? . Tools ? . ToolCollection ? . Add ( McpServerTool . Create ( async ( IProgress < ProgressNotificationValue > progress ) =>
346
+ {
347
+ for ( int i = 0 ; i < TotalNotifications ; i ++ )
348
+ {
349
+ progress . Report ( new ProgressNotificationValue { Progress = i * 10 , Message = "making progress" } ) ;
350
+ await Task . Delay ( 1 ) ;
351
+ }
352
+
353
+ await allProgressReceived . Task ;
354
+
355
+ return 42 ;
356
+ } , new ( ) { Name = "ProgressReporter" } ) ) ;
357
+
358
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
359
+
360
+ var tool = ( await client . ListToolsAsync ( cancellationToken : TestContext . Current . CancellationToken ) ) . First ( t => t . Name == "ProgressReporter" ) ;
361
+
362
+ IProgress < ProgressNotificationValue > progress = new SynchronousProgress ( value =>
363
+ {
364
+ Assert . True ( value . Progress >= 0 && value . Progress <= 100 ) ;
365
+ Assert . Equal ( "making progress" , value . Message ) ;
366
+ if ( Interlocked . Decrement ( ref remainingProgress ) == 0 )
367
+ {
368
+ allProgressReceived . SetResult ( true ) ;
369
+ }
370
+ } ) ;
371
+
372
+ Assert . Throws < ArgumentNullException > ( "progress" , ( ) => tool . WithProgress ( null ! ) ) ;
373
+
374
+ var result = await tool . WithProgress ( progress ) . InvokeAsync ( cancellationToken : TestContext . Current . CancellationToken ) ;
375
+ Assert . Contains ( "42" , result ? . ToString ( ) ) ;
376
+ }
377
+
378
+ private sealed class SynchronousProgress ( Action < ProgressNotificationValue > callback ) : IProgress < ProgressNotificationValue >
379
+ {
380
+ public void Report ( ProgressNotificationValue value ) => callback ( value ) ;
381
+ }
382
+
339
383
[ Fact ]
340
384
public async Task AsClientLoggerProvider_MessagesSentToClient ( )
341
385
{
342
- IMcpClient client = await CreateMcpClientForServer ( ) ;
386
+ await using IMcpClient client = await CreateMcpClientForServer ( ) ;
343
387
344
388
ILoggerProvider loggerProvider = Server . AsClientLoggerProvider ( ) ;
345
389
Assert . Throws < ArgumentNullException > ( "categoryName" , ( ) => loggerProvider . CreateLogger ( null ! ) ) ;
0 commit comments