11using Microsoft . Extensions . AI ;
22using Microsoft . Extensions . DependencyInjection ;
3+ using Microsoft . Extensions . Logging ;
34using Microsoft . Extensions . Options ;
45using ModelContextProtocol . Client ;
56using ModelContextProtocol . Protocol ;
@@ -101,7 +102,7 @@ public async Task Can_List_And_Call_Registered_Prompts()
101102 await using McpClient client = await CreateMcpClientForServer ( ) ;
102103
103104 var prompts = await client . ListPromptsAsync ( cancellationToken : TestContext . Current . CancellationToken ) ;
104- Assert . Equal ( 6 , prompts . Count ) ;
105+ Assert . Equal ( 8 , prompts . Count ) ;
105106
106107 var prompt = prompts . First ( t => t . Name == "returns_chat_messages" ) ;
107108 Assert . Equal ( "Returns chat messages" , prompt . Description ) ;
@@ -130,7 +131,7 @@ public async Task Can_Be_Notified_Of_Prompt_Changes()
130131 await using McpClient client = await CreateMcpClientForServer ( ) ;
131132
132133 var prompts = await client . ListPromptsAsync ( cancellationToken : TestContext . Current . CancellationToken ) ;
133- Assert . Equal ( 6 , prompts . Count ) ;
134+ Assert . Equal ( 8 , prompts . Count ) ;
134135
135136 Channel < JsonRpcNotification > listChanged = Channel . CreateUnbounded < JsonRpcNotification > ( ) ;
136137 var notificationRead = listChanged . Reader . ReadAsync ( TestContext . Current . CancellationToken ) ;
@@ -151,7 +152,7 @@ public async Task Can_Be_Notified_Of_Prompt_Changes()
151152 await notificationRead ;
152153
153154 prompts = await client . ListPromptsAsync ( cancellationToken : TestContext . Current . CancellationToken ) ;
154- Assert . Equal ( 7 , prompts . Count ) ;
155+ Assert . Equal ( 9 , prompts . Count ) ;
155156 Assert . Contains ( prompts , t => t . Name == "NewPrompt" ) ;
156157
157158 notificationRead = listChanged . Reader . ReadAsync ( TestContext . Current . CancellationToken ) ;
@@ -161,7 +162,7 @@ public async Task Can_Be_Notified_Of_Prompt_Changes()
161162 }
162163
163164 prompts = await client . ListPromptsAsync ( cancellationToken : TestContext . Current . CancellationToken ) ;
164- Assert . Equal ( 6 , prompts . Count ) ;
165+ Assert . Equal ( 8 , prompts . Count ) ;
165166 Assert . DoesNotContain ( prompts , t => t . Name == "NewPrompt" ) ;
166167 }
167168
@@ -195,6 +196,75 @@ await Assert.ThrowsAsync<McpProtocolException>(async () => await client.GetPromp
195196 cancellationToken : TestContext . Current . CancellationToken ) ) ;
196197 }
197198
199+ [ Fact ]
200+ public async Task Logs_Prompt_Name_On_Successful_Call ( )
201+ {
202+ await using McpClient client = await CreateMcpClientForServer ( ) ;
203+
204+ var result = await client . GetPromptAsync (
205+ "returns_chat_messages" ,
206+ new Dictionary < string , object ? > { [ "message" ] = "hello" } ,
207+ cancellationToken : TestContext . Current . CancellationToken ) ;
208+
209+ Assert . NotNull ( result ) ;
210+
211+ var infoLog = Assert . Single ( MockLoggerProvider . LogMessages , m => m . Message == "GetPrompt \" returns_chat_messages\" completed." ) ;
212+ Assert . Equal ( LogLevel . Information , infoLog . LogLevel ) ;
213+ }
214+
215+ [ Fact ]
216+ public async Task Logs_Prompt_Name_When_Prompt_Throws ( )
217+ {
218+ await using McpClient client = await CreateMcpClientForServer ( ) ;
219+
220+ await Assert . ThrowsAsync < McpProtocolException > ( async ( ) => await client . GetPromptAsync (
221+ "throws_exception" ,
222+ new Dictionary < string , object ? > { [ "message" ] = "test" } ,
223+ cancellationToken : TestContext . Current . CancellationToken ) ) ;
224+
225+ var errorLog = Assert . Single ( MockLoggerProvider . LogMessages , m => m . LogLevel == LogLevel . Error ) ;
226+ Assert . Equal ( "GetPrompt \" throws_exception\" threw an unhandled exception." , errorLog . Message ) ;
227+ Assert . IsType < FormatException > ( errorLog . Exception ) ;
228+ }
229+
230+ [ Fact ]
231+ public async Task Logs_Prompt_Error_When_Prompt_Throws_OperationCanceledException ( )
232+ {
233+ await using McpClient client = await CreateMcpClientForServer ( ) ;
234+
235+ await Assert . ThrowsAsync < McpProtocolException > ( async ( ) => await client . GetPromptAsync (
236+ "throws_operation_canceled_exception" ,
237+ cancellationToken : TestContext . Current . CancellationToken ) ) ;
238+
239+ Assert . Contains ( MockLoggerProvider . LogMessages , m =>
240+ m . LogLevel == LogLevel . Error &&
241+ m . Message == "GetPrompt \" throws_operation_canceled_exception\" threw an unhandled exception." &&
242+ m . Exception is OperationCanceledException ) ;
243+
244+ Assert . Contains ( MockLoggerProvider . LogMessages , m =>
245+ m . LogLevel == LogLevel . Warning &&
246+ m . Message . Contains ( "request handler failed" ) ) ;
247+ }
248+
249+ [ Fact ]
250+ public async Task Logs_Prompt_Error_When_Prompt_Throws_McpProtocolException ( )
251+ {
252+ await using McpClient client = await CreateMcpClientForServer ( ) ;
253+
254+ await Assert . ThrowsAsync < McpProtocolException > ( async ( ) => await client . GetPromptAsync (
255+ "throws_mcp_protocol_exception" ,
256+ cancellationToken : TestContext . Current . CancellationToken ) ) ;
257+
258+ Assert . Contains ( MockLoggerProvider . LogMessages , m =>
259+ m . LogLevel == LogLevel . Error &&
260+ m . Message == "GetPrompt \" throws_mcp_protocol_exception\" threw an unhandled exception." &&
261+ m . Exception is McpProtocolException ) ;
262+
263+ Assert . Contains ( MockLoggerProvider . LogMessages , m =>
264+ m . LogLevel == LogLevel . Warning &&
265+ m . Message . Contains ( "request handler failed" ) ) ;
266+ }
267+
198268 [ Fact ]
199269 public async Task Throws_Exception_On_Unknown_Prompt ( )
200270 {
@@ -335,6 +405,14 @@ public static ChatMessage[] ReturnsChatMessages([Description("The first paramete
335405 public static ChatMessage [ ] ThrowsException ( [ Description ( "The first parameter" ) ] string message ) =>
336406 throw new FormatException ( "uh oh" ) ;
337407
408+ [ McpServerPrompt , Description ( "Throws OperationCanceledException" ) ]
409+ public static ChatMessage [ ] ThrowsOperationCanceledException ( ) =>
410+ throw new OperationCanceledException ( "Prompt was canceled" ) ;
411+
412+ [ McpServerPrompt , Description ( "Throws McpProtocolException" ) ]
413+ public static ChatMessage [ ] ThrowsMcpProtocolException ( ) =>
414+ throw new McpProtocolException ( "Prompt protocol error" , McpErrorCode . InvalidParams ) ;
415+
338416 [ McpServerPrompt ( Title = "This is a title" , IconSource = "https://example.com/prompt-icon.svg" ) , Description ( "Returns chat messages" ) ]
339417 public string ReturnsString ( [ Description ( "The first parameter" ) ] string message ) =>
340418 $ "The prompt is: { message } . The id is { id } .";
0 commit comments