@@ -290,6 +290,95 @@ await Can_Handle_Requests(
290290 } ) ;
291291 }
292292
293+ [ Fact ]
294+ public async Task Initialize_IncludesExtensionsInResponse ( )
295+ {
296+ await Can_Handle_Requests (
297+ serverCapabilities : new ServerCapabilities
298+ {
299+ Extensions = new Dictionary < string , object > { [ "io.myext" ] = new JsonObject { [ "required" ] = true } } ,
300+ } ,
301+ method : RequestMethods . Initialize ,
302+ configureOptions : null ,
303+ assertResult : ( _ , response ) =>
304+ {
305+ var result = JsonSerializer . Deserialize < InitializeResult > ( response , McpJsonUtilities . DefaultOptions ) ;
306+ Assert . NotNull ( result ) ;
307+ Assert . NotNull ( result . Capabilities . Extensions ) ;
308+ Assert . True ( result . Capabilities . Extensions . ContainsKey ( "io.myext" ) ) ;
309+ } ) ;
310+ }
311+
312+ [ Fact ]
313+ public async Task Initialize_IncludesExperimentalInResponse ( )
314+ {
315+ await Can_Handle_Requests (
316+ serverCapabilities : new ServerCapabilities
317+ {
318+ Experimental = new Dictionary < string , object > { [ "customFeature" ] = new JsonObject { [ "enabled" ] = true } } ,
319+ } ,
320+ method : RequestMethods . Initialize ,
321+ configureOptions : null ,
322+ assertResult : ( _ , response ) =>
323+ {
324+ var result = JsonSerializer . Deserialize < InitializeResult > ( response , McpJsonUtilities . DefaultOptions ) ;
325+ Assert . NotNull ( result ) ;
326+ Assert . NotNull ( result . Capabilities . Experimental ) ;
327+ Assert . True ( result . Capabilities . Experimental . ContainsKey ( "customFeature" ) ) ;
328+ } ) ;
329+ }
330+
331+ [ Fact ]
332+ public async Task Initialize_CopiesAllCapabilityProperties ( )
333+ {
334+ // Set every public property on ServerCapabilities to a non-null value.
335+ // If a new property is added to ServerCapabilities in the future but the
336+ // server fails to copy it, this reflection-based test will automatically
337+ // detect the missing property and fail.
338+ var inputCapabilities = new ServerCapabilities
339+ {
340+ Experimental = new Dictionary < string , object > { [ "test" ] = new JsonObject ( ) } ,
341+ Logging = new LoggingCapability ( ) ,
342+ Prompts = new PromptsCapability ( ) ,
343+ Resources = new ResourcesCapability ( ) ,
344+ Tools = new ToolsCapability ( ) ,
345+ Completions = new CompletionsCapability ( ) ,
346+ Tasks = new McpTasksCapability ( ) ,
347+ Extensions = new Dictionary < string , object > { [ "io.test" ] = new JsonObject ( ) } ,
348+ } ;
349+
350+ await Can_Handle_Requests (
351+ serverCapabilities : inputCapabilities ,
352+ method : RequestMethods . Initialize ,
353+ configureOptions : options =>
354+ {
355+ // Tasks capability requires a TaskStore
356+ options . TaskStore = new InMemoryMcpTaskStore ( ) ;
357+ } ,
358+ assertResult : ( _ , response ) =>
359+ {
360+ var result = JsonSerializer . Deserialize < InitializeResult > ( response , McpJsonUtilities . DefaultOptions ) ;
361+ Assert . NotNull ( result ) ;
362+
363+ // Use reflection to verify every public property on ServerCapabilities is non-null.
364+ // This catches cases where new capability properties are added but not copied
365+ // from options in McpServerImpl.
366+ foreach ( var property in typeof ( ServerCapabilities ) . GetProperties ( BindingFlags . Public | BindingFlags . Instance ) )
367+ {
368+ if ( ! property . CanRead )
369+ {
370+ continue ;
371+ }
372+
373+ Assert . True (
374+ property . GetValue ( result . Capabilities ) is not null ,
375+ $ "ServerCapabilities.{ property . Name } was set on options but is null in the initialize response. " +
376+ $ "Ensure the property is copied in McpServerImpl's Configure* methods.") ;
377+ }
378+ } ) ;
379+ }
380+ #pragma warning restore MCPEXP001
381+
293382 [ Fact ]
294383 public async Task Can_Handle_Completion_Requests ( )
295384 {
0 commit comments