1
1
using ModelContextProtocol . Client ;
2
- using ModelContextProtocol . Configuration ;
3
- using ModelContextProtocol . Protocol . Messages ;
4
- using ModelContextProtocol . Protocol . Transport ;
5
- using ModelContextProtocol . Protocol . Types ;
6
2
using Microsoft . Extensions . AI ;
7
3
using OpenAI ;
4
+ using ModelContextProtocol . Protocol . Types ;
5
+ using ModelContextProtocol . Protocol . Messages ;
8
6
using System . Text . Json ;
7
+ using ModelContextProtocol . Configuration ;
8
+ using ModelContextProtocol . Protocol . Transport ;
9
+ using Xunit . Sdk ;
9
10
10
11
namespace ModelContextProtocol . Tests ;
11
12
@@ -61,8 +62,8 @@ public async Task ListTools_Stdio(string clientId)
61
62
62
63
// act
63
64
await using var client = await _fixture . CreateClientAsync ( clientId ) ;
64
- var tools = await client . ListToolsAsync ( ) . ToListAsync ( ) ;
65
- var aiFunctions = await client . GetAIFunctionsAsync ( ) ;
65
+ var tools = await client . ListToolsAsync ( TestContext . Current . CancellationToken ) . ToListAsync ( TestContext . Current . CancellationToken ) ;
66
+ var aiFunctions = await client . GetAIFunctionsAsync ( TestContext . Current . CancellationToken ) ;
66
67
67
68
// assert
68
69
Assert . NotEmpty ( tools ) ;
@@ -102,9 +103,9 @@ public async Task CallTool_Stdio_ViaAIFunction_EchoServer(string clientId)
102
103
103
104
// act
104
105
await using var client = await _fixture . CreateClientAsync ( clientId ) ;
105
- var aiFunctions = await client . GetAIFunctionsAsync ( ) ;
106
+ var aiFunctions = await client . GetAIFunctionsAsync ( TestContext . Current . CancellationToken ) ;
106
107
var echo = aiFunctions . Single ( t => t . Name == "echo" ) ;
107
- var result = await echo . InvokeAsync ( [ new KeyValuePair < string , object ? > ( "message" , "Hello MCP!" ) ] ) ;
108
+ var result = await echo . InvokeAsync ( [ new KeyValuePair < string , object ? > ( "message" , "Hello MCP!" ) ] , TestContext . Current . CancellationToken ) ;
108
109
109
110
// assert
110
111
Assert . NotNull ( result ) ;
@@ -119,7 +120,7 @@ public async Task ListPrompts_Stdio(string clientId)
119
120
120
121
// act
121
122
await using var client = await _fixture . CreateClientAsync ( clientId ) ;
122
- var prompts = await client . ListPromptsAsync ( ) . ToListAsync ( ) ;
123
+ var prompts = await client . ListPromptsAsync ( TestContext . Current . CancellationToken ) . ToListAsync ( TestContext . Current . CancellationToken ) ;
123
124
124
125
// assert
125
126
Assert . NotEmpty ( prompts ) ;
@@ -251,7 +252,7 @@ public async Task SubscribeResource_Stdio()
251
252
await client . SubscribeToResourceAsync ( "test://static/resource/1" , CancellationToken . None ) ;
252
253
253
254
// notifications happen every 5 seconds, so we wait for 10 seconds to ensure we get at least one notification
254
- await Task . Delay ( 10000 ) ;
255
+ await Task . Delay ( 10000 , TestContext . Current . CancellationToken ) ;
255
256
256
257
// assert
257
258
Assert . True ( counter > 0 ) ;
@@ -276,17 +277,17 @@ public async Task UnsubscribeResource_Stdio()
276
277
await client . SubscribeToResourceAsync ( "test://static/resource/1" , CancellationToken . None ) ;
277
278
278
279
// notifications happen every 5 seconds, so we wait for 10 seconds to ensure we get at least one notification
279
- await Task . Delay ( 10000 ) ;
280
+ await Task . Delay ( 10000 , TestContext . Current . CancellationToken ) ;
280
281
281
282
// reset counter
282
283
int counterAfterSubscribe = counter ;
283
-
284
+
284
285
// unsubscribe
285
286
await client . UnsubscribeFromResourceAsync ( "test://static/resource/1" , CancellationToken . None ) ;
286
287
counter = 0 ;
287
288
288
289
// notifications happen every 5 seconds, so we wait for 10 seconds to ensure we would've gotten at least one notification
289
- await Task . Delay ( 10000 ) ;
290
+ await Task . Delay ( 10000 , TestContext . Current . CancellationToken ) ;
290
291
291
292
// assert
292
293
Assert . True ( counterAfterSubscribe > 0 ) ;
@@ -340,7 +341,7 @@ public async Task GetCompletion_Stdio_PromptReference(string clientId)
340
341
[ Theory ]
341
342
[ MemberData ( nameof ( GetClients ) ) ]
342
343
public async Task Sampling_Stdio ( string clientId )
343
- {
344
+ {
344
345
// Set up the sampling handler
345
346
int samplingHandlerCalls = 0 ;
346
347
await using var client = await _fixture . CreateClientAsync ( clientId , new ( )
@@ -375,8 +376,8 @@ public async Task Sampling_Stdio(string clientId)
375
376
{
376
377
[ "prompt" ] = "Test prompt" ,
377
378
[ "maxTokens" ] = 100
378
- }
379
- ) ;
379
+ } ,
380
+ TestContext . Current . CancellationToken ) ;
380
381
381
382
// assert
382
383
Assert . NotNull ( result ) ;
@@ -423,8 +424,8 @@ public async Task Notifications_Stdio(string clientId)
423
424
await using var client = await _fixture . CreateClientAsync ( clientId ) ;
424
425
425
426
// Verify we can send notifications without errors
426
- await client . SendNotificationAsync ( NotificationMethods . RootsUpdatedNotification ) ;
427
- await client . SendNotificationAsync ( "test/notification" , new { test = true } ) ;
427
+ await client . SendNotificationAsync ( NotificationMethods . RootsUpdatedNotification , cancellationToken : TestContext . Current . CancellationToken ) ;
428
+ await client . SendNotificationAsync ( "test/notification" , new { test = true } , TestContext . Current . CancellationToken ) ;
428
429
429
430
// assert
430
431
// no response to check, if no exception is thrown, it's a success
@@ -452,13 +453,17 @@ public async Task CallTool_Stdio_MemoryServer()
452
453
ClientInfo = new ( ) { Name = "IntegrationTestClient" , Version = "1.0.0" }
453
454
} ;
454
455
455
- await using var client = await McpClientFactory . CreateAsync ( serverConfig , clientOptions , loggerFactory : _fixture . LoggerFactory ) ;
456
+ await using var client = await McpClientFactory . CreateAsync (
457
+ serverConfig ,
458
+ clientOptions ,
459
+ loggerFactory : _fixture . LoggerFactory ,
460
+ cancellationToken : TestContext . Current . CancellationToken ) ;
456
461
457
462
// act
458
463
var result = await client . CallToolAsync (
459
464
"read_graph" ,
460
- [ ]
461
- ) ;
465
+ [ ] ,
466
+ TestContext . Current . CancellationToken ) ;
462
467
463
468
// assert
464
469
Assert . NotNull ( result ) ;
@@ -471,14 +476,14 @@ public async Task CallTool_Stdio_MemoryServer()
471
476
[ Fact ]
472
477
public async Task GetAIFunctionsAsync_UsingEverythingServer_ToolsAreProperlyCalled ( )
473
478
{
474
- if ( s_openAIKey is null )
475
- {
476
- return ; // Skip the test if the OpenAI key is not provided
477
- }
479
+ SkipTestIfNoOpenAIKey ( ) ;
478
480
479
481
// Get the MCP client and tools from it.
480
- await using var client = await McpClientFactory . CreateAsync ( _fixture . EverythingServerConfig , _fixture . DefaultOptions ) ; ;
481
- var mappedTools = await client . GetAIFunctionsAsync ( ) ;
482
+ await using var client = await McpClientFactory . CreateAsync (
483
+ _fixture . EverythingServerConfig ,
484
+ _fixture . DefaultOptions ,
485
+ cancellationToken : TestContext . Current . CancellationToken ) ;
486
+ var mappedTools = await client . GetAIFunctionsAsync ( TestContext . Current . CancellationToken ) ;
482
487
483
488
// Create the chat client.
484
489
using IChatClient chatClient = new OpenAIClient ( s_openAIKey ) . AsChatClient ( "gpt-4o-mini" )
@@ -495,7 +500,7 @@ public async Task GetAIFunctionsAsync_UsingEverythingServer_ToolsAreProperlyCall
495
500
messages . Add ( new ( ChatRole . User , "Please call the echo tool with the string 'Hello MCP!' and output the response ad verbatim." ) ) ;
496
501
497
502
// Call the chat client
498
- var response = await chatClient . GetResponseAsync ( messages , new ( ) { Tools = [ .. mappedTools ] , Temperature = 0 } ) ;
503
+ var response = await chatClient . GetResponseAsync ( messages , new ( ) { Tools = [ .. mappedTools ] , Temperature = 0 } , TestContext . Current . CancellationToken ) ;
499
504
500
505
// Assert
501
506
Assert . Contains ( "Echo: Hello MCP!" , response . Text ) ;
@@ -504,10 +509,7 @@ public async Task GetAIFunctionsAsync_UsingEverythingServer_ToolsAreProperlyCall
504
509
[ Fact ]
505
510
public async Task SamplingViaChatClient_RequestResponseProperlyPropagated ( )
506
511
{
507
- if ( s_openAIKey is null )
508
- {
509
- return ; // Skip the test if the OpenAI key is not provided
510
- }
512
+ SkipTestIfNoOpenAIKey ( ) ;
511
513
512
514
await using var client = await McpClientFactory . CreateAsync ( _fixture . EverythingServerConfig , new ( )
513
515
{
@@ -519,17 +521,22 @@ public async Task SamplingViaChatClient_RequestResponseProperlyPropagated()
519
521
SamplingHandler = new OpenAIClient ( s_openAIKey ) . AsChatClient ( "gpt-4o-mini" ) . CreateSamplingHandler ( ) ,
520
522
} ,
521
523
} ,
522
- } ) ;
524
+ } , cancellationToken : TestContext . Current . CancellationToken ) ;
523
525
524
526
var result = await client . CallToolAsync ( "sampleLLM" , new ( )
525
527
{
526
528
[ "prompt" ] = "In just a few words, what is the most famous tower in Paris?" ,
527
- } ) ;
529
+ } , TestContext . Current . CancellationToken ) ;
528
530
529
531
Assert . NotNull ( result ) ;
530
532
Assert . NotEmpty ( result . Content ) ;
531
533
Assert . Equal ( "text" , result . Content [ 0 ] . Type ) ;
532
534
Assert . Contains ( "LLM sampling result:" , result . Content [ 0 ] . Text ) ;
533
535
Assert . Contains ( "Eiffel" , result . Content [ 0 ] . Text ) ;
534
536
}
537
+
538
+ private static void SkipTestIfNoOpenAIKey ( )
539
+ {
540
+ Assert . SkipWhen ( s_openAIKey is null , "No OpenAI key provided. Skipping test." ) ;
541
+ }
535
542
}
0 commit comments