6
6
using ModelContextProtocol . Protocol . Transport ;
7
7
using ModelContextProtocol . Protocol . Types ;
8
8
using ModelContextProtocol . Server ;
9
- using ModelContextProtocol . Tests . Transport ;
10
9
using ModelContextProtocol . Tests . Utils ;
11
10
using System . ComponentModel ;
12
11
using System . IO . Pipelines ;
13
12
using System . Threading . Channels ;
14
13
14
+ #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
15
+
15
16
namespace ModelContextProtocol . Tests . Configuration ;
16
17
17
18
public class McpServerBuilderExtensionsPromptsTests : LoggedTest , IAsyncDisposable
@@ -28,7 +29,70 @@ public McpServerBuilderExtensionsPromptsTests(ITestOutputHelper testOutputHelper
28
29
{
29
30
ServiceCollection sc = new ( ) ;
30
31
sc . AddSingleton ( LoggerFactory ) ;
31
- _builder = sc . AddMcpServer ( ) . WithStdioServerTransport ( ) . WithPrompts < SimplePrompts > ( ) ;
32
+ _builder = sc
33
+ . AddMcpServer ( )
34
+ . WithStdioServerTransport ( )
35
+ . WithListPromptsHandler ( async ( request , cancellationToken ) =>
36
+ {
37
+ var cursor = request . Params ? . Cursor ;
38
+ switch ( cursor )
39
+ {
40
+ case null :
41
+ return new ( )
42
+ {
43
+ NextCursor = "abc" ,
44
+ Prompts = [ new ( )
45
+ {
46
+ Name = "FirstCustomPrompt" ,
47
+ Description = "First prompt returned by custom handler" ,
48
+ } ] ,
49
+ } ;
50
+
51
+ case "abc" :
52
+ return new ( )
53
+ {
54
+ NextCursor = "def" ,
55
+ Prompts = [ new ( )
56
+ {
57
+ Name = "SecondCustomPrompt" ,
58
+ Description = "Second prompt returned by custom handler" ,
59
+ } ] ,
60
+ } ;
61
+
62
+ case "def" :
63
+ return new ( )
64
+ {
65
+ NextCursor = null ,
66
+ Prompts = [ new ( )
67
+ {
68
+ Name = "FinalCustomPrompt" ,
69
+ Description = "Final prompt returned by custom handler" ,
70
+ } ] ,
71
+ } ;
72
+
73
+ default :
74
+ throw new Exception ( "Unexpected cursor" ) ;
75
+ }
76
+ } )
77
+ . WithGetPromptHandler ( async ( request , cancellationToken ) =>
78
+ {
79
+ switch ( request . Params ? . Name )
80
+ {
81
+ case "FirstCustomPrompt" :
82
+ case "SecondCustomPrompt" :
83
+ case "FinalCustomPrompt" :
84
+ return new GetPromptResult ( )
85
+ {
86
+ Messages = [ new ( ) { Role = Role . User , Content = new ( ) { Text = $ "hello from { request . Params . Name } ", Type = "text" } } ] ,
87
+ } ;
88
+
89
+ default :
90
+ throw new Exception ( $ "Unknown prompt '{ request . Params ? . Name } '") ;
91
+ }
92
+ } )
93
+ . WithPrompts < SimplePrompts > ( ) ;
94
+
95
+
32
96
// Call WithStdioServerTransport to get the IMcpServer registration, then overwrite default transport with a pipe transport.
33
97
sc . AddSingleton < ITransport > ( new StreamServerTransport ( _clientToServerPipe . Reader . AsStream ( ) , _serverToClientPipe . Writer . AsStream ( ) , loggerFactory : LoggerFactory ) ) ;
34
98
sc . AddSingleton ( new ObjectWithId ( ) ) ;
@@ -85,7 +149,7 @@ public async Task Can_List_And_Call_Registered_Prompts()
85
149
IMcpClient client = await CreateMcpClientForServer ( ) ;
86
150
87
151
var prompts = await client . ListPromptsAsync ( TestContext . Current . CancellationToken ) ;
88
- Assert . Equal ( 3 , prompts . Count ) ;
152
+ Assert . Equal ( 6 , prompts . Count ) ;
89
153
90
154
var prompt = prompts . First ( t => t . Name == nameof ( SimplePrompts . ReturnsChatMessages ) ) ;
91
155
Assert . Equal ( "Returns chat messages" , prompt . Description ) ;
@@ -98,6 +162,14 @@ public async Task Can_List_And_Call_Registered_Prompts()
98
162
Assert . Equal ( 2 , chatMessages . Count ) ;
99
163
Assert . Equal ( "The prompt is: hello" , chatMessages [ 0 ] . Text ) ;
100
164
Assert . Equal ( "Summarize." , chatMessages [ 1 ] . Text ) ;
165
+
166
+ prompt = prompts . First ( t => t . Name == "SecondCustomPrompt" ) ;
167
+ Assert . Equal ( "Second prompt returned by custom handler" , prompt . Description ) ;
168
+ result = await prompt . GetAsync ( cancellationToken : TestContext . Current . CancellationToken ) ;
169
+ chatMessages = result . ToChatMessages ( ) ;
170
+ Assert . NotNull ( chatMessages ) ;
171
+ Assert . Single ( chatMessages ) ;
172
+ Assert . Equal ( "hello from SecondCustomPrompt" , chatMessages [ 0 ] . Text ) ;
101
173
}
102
174
103
175
[ Fact ]
@@ -106,7 +178,7 @@ public async Task Can_Be_Notified_Of_Prompt_Changes()
106
178
IMcpClient client = await CreateMcpClientForServer ( ) ;
107
179
108
180
var prompts = await client . ListPromptsAsync ( TestContext . Current . CancellationToken ) ;
109
- Assert . Equal ( 3 , prompts . Count ) ;
181
+ Assert . Equal ( 6 , prompts . Count ) ;
110
182
111
183
Channel < JsonRpcNotification > listChanged = Channel . CreateUnbounded < JsonRpcNotification > ( ) ;
112
184
client . AddNotificationHandler ( "notifications/prompts/list_changed" , notification =>
@@ -127,7 +199,7 @@ public async Task Can_Be_Notified_Of_Prompt_Changes()
127
199
await notificationRead ;
128
200
129
201
prompts = await client . ListPromptsAsync ( TestContext . Current . CancellationToken ) ;
130
- Assert . Equal ( 4 , prompts . Count ) ;
202
+ Assert . Equal ( 7 , prompts . Count ) ;
131
203
Assert . Contains ( prompts , t => t . Name == "NewPrompt" ) ;
132
204
133
205
notificationRead = listChanged . Reader . ReadAsync ( TestContext . Current . CancellationToken ) ;
@@ -136,7 +208,7 @@ public async Task Can_Be_Notified_Of_Prompt_Changes()
136
208
await notificationRead ;
137
209
138
210
prompts = await client . ListPromptsAsync ( TestContext . Current . CancellationToken ) ;
139
- Assert . Equal ( 3 , prompts . Count ) ;
211
+ Assert . Equal ( 6 , prompts . Count ) ;
140
212
Assert . DoesNotContain ( prompts , t => t . Name == "NewPrompt" ) ;
141
213
}
142
214
0 commit comments