From b35a18d3ba4c6f08c5890c21e4484a5cb0019069 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Thu, 19 Feb 2026 09:56:40 -0800 Subject: [PATCH] Don't treat McpServerHandlers as an independent options type --- .../McpServerBuilderExtensions.cs | 79 ++++++++++++++++--- .../McpServerOptionsSetup.cs | 70 +--------------- .../McpServerBuilderExtensionsHandlerTests.cs | 40 +++++----- 3 files changed, 89 insertions(+), 100 deletions(-) diff --git a/src/ModelContextProtocol/McpServerBuilderExtensions.cs b/src/ModelContextProtocol/McpServerBuilderExtensions.cs index b77533574..8369256b7 100644 --- a/src/ModelContextProtocol/McpServerBuilderExtensions.cs +++ b/src/ModelContextProtocol/McpServerBuilderExtensions.cs @@ -583,7 +583,12 @@ public static IMcpServerBuilder WithListResourceTemplatesHandler(this IMcpServer { Throw.IfNull(builder); - builder.Services.Configure(s => s.ListResourceTemplatesHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.ListResourceTemplatesHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Resources ??= new(); + }); return builder; } @@ -616,7 +621,12 @@ public static IMcpServerBuilder WithListToolsHandler(this IMcpServerBuilder buil { Throw.IfNull(builder); - builder.Services.Configure(s => s.ListToolsHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.ListToolsHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Tools ??= new(); + }); return builder; } @@ -636,7 +646,12 @@ public static IMcpServerBuilder WithCallToolHandler(this IMcpServerBuilder build { Throw.IfNull(builder); - builder.Services.Configure(s => s.CallToolHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.CallToolHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Tools ??= new(); + }); return builder; } @@ -669,7 +684,12 @@ public static IMcpServerBuilder WithListPromptsHandler(this IMcpServerBuilder bu { Throw.IfNull(builder); - builder.Services.Configure(s => s.ListPromptsHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.ListPromptsHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Prompts ??= new(); + }); return builder; } @@ -684,7 +704,12 @@ public static IMcpServerBuilder WithGetPromptHandler(this IMcpServerBuilder buil { Throw.IfNull(builder); - builder.Services.Configure(s => s.GetPromptHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.GetPromptHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Prompts ??= new(); + }); return builder; } @@ -705,7 +730,12 @@ public static IMcpServerBuilder WithListResourcesHandler(this IMcpServerBuilder { Throw.IfNull(builder); - builder.Services.Configure(s => s.ListResourcesHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.ListResourcesHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Resources ??= new(); + }); return builder; } @@ -724,7 +754,12 @@ public static IMcpServerBuilder WithReadResourceHandler(this IMcpServerBuilder b { Throw.IfNull(builder); - builder.Services.Configure(s => s.ReadResourceHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.ReadResourceHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Resources ??= new(); + }); return builder; } @@ -743,7 +778,12 @@ public static IMcpServerBuilder WithCompleteHandler(this IMcpServerBuilder build { Throw.IfNull(builder); - builder.Services.Configure(s => s.CompleteHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.CompleteHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Completions ??= new(); + }); return builder; } @@ -773,7 +813,13 @@ public static IMcpServerBuilder WithSubscribeToResourcesHandler(this IMcpServerB { Throw.IfNull(builder); - builder.Services.Configure(s => s.SubscribeToResourcesHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.SubscribeToResourcesHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Resources ??= new(); + options.Capabilities.Resources.Subscribe = true; + }); return builder; } @@ -803,7 +849,13 @@ public static IMcpServerBuilder WithUnsubscribeFromResourcesHandler(this IMcpSer { Throw.IfNull(builder); - builder.Services.Configure(s => s.UnsubscribeFromResourcesHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.UnsubscribeFromResourcesHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Resources ??= new(); + options.Capabilities.Resources.Subscribe = true; + }); return builder; } @@ -830,7 +882,12 @@ public static IMcpServerBuilder WithSetLoggingLevelHandler(this IMcpServerBuilde { Throw.IfNull(builder); - builder.Services.Configure(s => s.SetLoggingLevelHandler = handler); + builder.Services.Configure(options => + { + options.Handlers.SetLoggingLevelHandler = handler; + options.Capabilities ??= new(); + options.Capabilities.Logging ??= new(); + }); return builder; } #endregion diff --git a/src/ModelContextProtocol/McpServerOptionsSetup.cs b/src/ModelContextProtocol/McpServerOptionsSetup.cs index 2dc7e0ed6..2042ead53 100644 --- a/src/ModelContextProtocol/McpServerOptionsSetup.cs +++ b/src/ModelContextProtocol/McpServerOptionsSetup.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.Options; -using ModelContextProtocol.Protocol; using ModelContextProtocol.Server; namespace ModelContextProtocol; @@ -7,19 +6,17 @@ namespace ModelContextProtocol; /// /// Configures the McpServerOptions using addition services from DI. /// -/// The server handlers configuration options. /// The individually registered tools. /// The individually registered prompts. /// The individually registered resources. internal sealed class McpServerOptionsSetup( - IOptions serverHandlers, IEnumerable serverTools, IEnumerable serverPrompts, IEnumerable serverResources) : IConfigureOptions { /// /// Configures the given McpServerOptions instance by setting server information - /// and applying custom server handlers and tools. + /// and collecting registered server primitives. /// /// The options instance to be configured. public void Configure(McpServerOptions options) @@ -70,70 +67,5 @@ public void Configure(McpServerOptions options) { options.ResourceCollection = resourceCollection; } - - // Apply custom server handlers. - OverwriteWithSetHandlers(serverHandlers.Value, options); - } - - /// - /// Overwrite any handlers in McpServerOptions with non-null handlers from this instance. - /// - private static void OverwriteWithSetHandlers(McpServerHandlers handlers, McpServerOptions options) - { - McpServerHandlers optionsHandlers = options.Handlers; - - PromptsCapability? promptsCapability = options.Capabilities?.Prompts; - if (handlers.ListPromptsHandler is not null || handlers.GetPromptHandler is not null) - { - promptsCapability ??= new(); - optionsHandlers.ListPromptsHandler = handlers.ListPromptsHandler ?? optionsHandlers.ListPromptsHandler; - optionsHandlers.GetPromptHandler = handlers.GetPromptHandler ?? optionsHandlers.GetPromptHandler; - } - - ResourcesCapability? resourcesCapability = options.Capabilities?.Resources; - if (handlers.ListResourceTemplatesHandler is not null || handlers.ListResourcesHandler is not null || handlers.ReadResourceHandler is not null) - { - resourcesCapability ??= new(); - optionsHandlers.ListResourceTemplatesHandler = handlers.ListResourceTemplatesHandler ?? optionsHandlers.ListResourceTemplatesHandler; - optionsHandlers.ListResourcesHandler = handlers.ListResourcesHandler ?? optionsHandlers.ListResourcesHandler; - optionsHandlers.ReadResourceHandler = handlers.ReadResourceHandler ?? optionsHandlers.ReadResourceHandler; - } - - if (handlers.SubscribeToResourcesHandler is not null || handlers.UnsubscribeFromResourcesHandler is not null) - { - resourcesCapability ??= new(); - optionsHandlers.SubscribeToResourcesHandler = handlers.SubscribeToResourcesHandler ?? optionsHandlers.SubscribeToResourcesHandler; - optionsHandlers.UnsubscribeFromResourcesHandler = handlers.UnsubscribeFromResourcesHandler ?? optionsHandlers.UnsubscribeFromResourcesHandler; - resourcesCapability.Subscribe = true; - } - - ToolsCapability? toolsCapability = options.Capabilities?.Tools; - if (handlers.ListToolsHandler is not null || handlers.CallToolHandler is not null) - { - toolsCapability ??= new(); - optionsHandlers.ListToolsHandler = handlers.ListToolsHandler ?? optionsHandlers.ListToolsHandler; - optionsHandlers.CallToolHandler = handlers.CallToolHandler ?? optionsHandlers.CallToolHandler; - } - - LoggingCapability? loggingCapability = options.Capabilities?.Logging; - if (handlers.SetLoggingLevelHandler is not null) - { - loggingCapability ??= new(); - optionsHandlers.SetLoggingLevelHandler = handlers.SetLoggingLevelHandler; - } - - CompletionsCapability? completionsCapability = options.Capabilities?.Completions; - if (handlers.CompleteHandler is not null) - { - completionsCapability ??= new(); - optionsHandlers.CompleteHandler = handlers.CompleteHandler; - } - - options.Capabilities ??= new(); - options.Capabilities.Prompts = promptsCapability; - options.Capabilities.Resources = resourcesCapability; - options.Capabilities.Tools = toolsCapability; - options.Capabilities.Logging = loggingCapability; - options.Capabilities.Completions = completionsCapability; } } diff --git a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsHandlerTests.cs b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsHandlerTests.cs index adae22f24..e61c442bf 100644 --- a/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsHandlerTests.cs +++ b/tests/ModelContextProtocol.Tests/Configuration/McpServerBuilderExtensionsHandlerTests.cs @@ -26,9 +26,9 @@ public void WithListToolsHandler_Sets_Handler() _builder.Object.WithListToolsHandler(handler); var serviceProvider = _services.BuildServiceProvider(); - var options = serviceProvider.GetRequiredService>().Value; + var options = serviceProvider.GetRequiredService>().Value; - Assert.Equal(handler, options.ListToolsHandler); + Assert.Equal(handler, options.Handlers.ListToolsHandler); } [Fact] @@ -39,9 +39,9 @@ public void WithCallToolHandler_Sets_Handler() _builder.Object.WithCallToolHandler(handler); var serviceProvider = _services.BuildServiceProvider(); - var options = serviceProvider.GetRequiredService>().Value; + var options = serviceProvider.GetRequiredService>().Value; - Assert.Equal(handler, options.CallToolHandler); + Assert.Equal(handler, options.Handlers.CallToolHandler); } [Fact] @@ -52,9 +52,9 @@ public void WithListPromptsHandler_Sets_Handler() _builder.Object.WithListPromptsHandler(handler); var serviceProvider = _services.BuildServiceProvider(); - var options = serviceProvider.GetRequiredService>().Value; + var options = serviceProvider.GetRequiredService>().Value; - Assert.Equal(handler, options.ListPromptsHandler); + Assert.Equal(handler, options.Handlers.ListPromptsHandler); } [Fact] @@ -65,9 +65,9 @@ public void WithGetPromptHandler_Sets_Handler() _builder.Object.WithGetPromptHandler(handler); var serviceProvider = _services.BuildServiceProvider(); - var options = serviceProvider.GetRequiredService>().Value; + var options = serviceProvider.GetRequiredService>().Value; - Assert.Equal(handler, options.GetPromptHandler); + Assert.Equal(handler, options.Handlers.GetPromptHandler); } [Fact] @@ -78,9 +78,9 @@ public void WithListResourceTemplatesHandler_Sets_Handler() _builder.Object.WithListResourceTemplatesHandler(handler); var serviceProvider = _services.BuildServiceProvider(); - var options = serviceProvider.GetRequiredService>().Value; + var options = serviceProvider.GetRequiredService>().Value; - Assert.Equal(handler, options.ListResourceTemplatesHandler); + Assert.Equal(handler, options.Handlers.ListResourceTemplatesHandler); } [Fact] @@ -91,9 +91,9 @@ public void WithListResourcesHandler_Sets_Handler() _builder.Object.WithListResourcesHandler(handler); var serviceProvider = _services.BuildServiceProvider(); - var options = serviceProvider.GetRequiredService>().Value; + var options = serviceProvider.GetRequiredService>().Value; - Assert.Equal(handler, options.ListResourcesHandler); + Assert.Equal(handler, options.Handlers.ListResourcesHandler); } [Fact] @@ -104,9 +104,9 @@ public void WithReadResourceHandler_Sets_Handler() _builder.Object.WithReadResourceHandler(handler); var serviceProvider = _services.BuildServiceProvider(); - var options = serviceProvider.GetRequiredService>().Value; + var options = serviceProvider.GetRequiredService>().Value; - Assert.Equal(handler, options.ReadResourceHandler); + Assert.Equal(handler, options.Handlers.ReadResourceHandler); } [Fact] @@ -117,9 +117,9 @@ public void WithCompleteHandler_Sets_Handler() _builder.Object.WithCompleteHandler(handler); var serviceProvider = _services.BuildServiceProvider(); - var options = serviceProvider.GetRequiredService>().Value; + var options = serviceProvider.GetRequiredService>().Value; - Assert.Equal(handler, options.CompleteHandler); + Assert.Equal(handler, options.Handlers.CompleteHandler); } [Fact] @@ -130,9 +130,9 @@ public void WithSubscribeToResourcesHandler_Sets_Handler() _builder.Object.WithSubscribeToResourcesHandler(handler); var serviceProvider = _services.BuildServiceProvider(); - var options = serviceProvider.GetRequiredService>().Value; + var options = serviceProvider.GetRequiredService>().Value; - Assert.Equal(handler, options.SubscribeToResourcesHandler); + Assert.Equal(handler, options.Handlers.SubscribeToResourcesHandler); } [Fact] @@ -143,8 +143,8 @@ public void WithUnsubscribeFromResourcesHandler_Sets_Handler() _builder.Object.WithUnsubscribeFromResourcesHandler(handler); var serviceProvider = _services.BuildServiceProvider(); - var options = serviceProvider.GetRequiredService>().Value; + var options = serviceProvider.GetRequiredService>().Value; - Assert.Equal(handler, options.UnsubscribeFromResourcesHandler); + Assert.Equal(handler, options.Handlers.UnsubscribeFromResourcesHandler); } }