From bbf96f63a6f7aa9837da18b8d54dfd7e5a6c26e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 21:36:12 +0000 Subject: [PATCH 1/6] Initial plan From 42bc783f3f0ed3cebb17ed5f73c132aa0bc879e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 21:45:34 +0000 Subject: [PATCH 2/6] Fix Extensions not being copied to ServerCapabilities and add tests In McpServerImpl.ConfigureExperimental, the Extensions property from the options was not being copied to the server's ServerCapabilities. This caused Extensions to be missing from the initialize response. Also added: - Test for Extensions in initialize response - Test for Experimental in initialize response - Reflection-based test to catch future missing capability copies Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../Server/McpServerImpl.cs | 1 + .../Server/McpServerTests.cs | 89 +++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs index 49fadb5e4..25fae3884 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs @@ -265,6 +265,7 @@ private void ConfigureCompletion(McpServerOptions options) private void ConfigureExperimental(McpServerOptions options) { ServerCapabilities.Experimental = options.Capabilities?.Experimental; + ServerCapabilities.ExtensionsCore = options.Capabilities?.ExtensionsCore; } private void ConfigureResources(McpServerOptions options) diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs index 53fd50685..d242e5424 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs @@ -290,6 +290,95 @@ await Can_Handle_Requests( }); } +#pragma warning disable MCPEXP001 + [Fact] + public async Task Initialize_IncludesExtensionsInResponse() + { + await Can_Handle_Requests( + serverCapabilities: new ServerCapabilities + { + Extensions = new Dictionary { ["io.myext"] = new JsonObject { ["required"] = true } }, + }, + method: RequestMethods.Initialize, + configureOptions: null, + assertResult: (_, response) => + { + var result = JsonSerializer.Deserialize(response, McpJsonUtilities.DefaultOptions); + Assert.NotNull(result); + Assert.NotNull(result.Capabilities.Extensions); + Assert.True(result.Capabilities.Extensions.ContainsKey("io.myext")); + }); + } + + [Fact] + public async Task Initialize_IncludesExperimentalInResponse() + { + await Can_Handle_Requests( + serverCapabilities: new ServerCapabilities + { + Experimental = new Dictionary { ["customFeature"] = new JsonObject { ["enabled"] = true } }, + }, + method: RequestMethods.Initialize, + configureOptions: null, + assertResult: (_, response) => + { + var result = JsonSerializer.Deserialize(response, McpJsonUtilities.DefaultOptions); + Assert.NotNull(result); + Assert.NotNull(result.Capabilities.Experimental); + Assert.True(result.Capabilities.Experimental.ContainsKey("customFeature")); + }); + } + + [Fact] + public async Task Initialize_CopiesAllCapabilityProperties() + { + // Set every public property on ServerCapabilities to a non-null value. + // If a new property is added to ServerCapabilities in the future but the + // server fails to copy it, this test will fail as a reminder. + var inputCapabilities = new ServerCapabilities + { + Experimental = new Dictionary { ["test"] = new JsonObject() }, + Logging = new LoggingCapability(), + Prompts = new PromptsCapability(), + Resources = new ResourcesCapability(), + Tools = new ToolsCapability(), + Completions = new CompletionsCapability(), + Tasks = new McpTasksCapability(), + Extensions = new Dictionary { ["io.test"] = new JsonObject() }, + }; + + await Can_Handle_Requests( + serverCapabilities: inputCapabilities, + method: RequestMethods.Initialize, + configureOptions: options => + { + // Tasks capability requires a TaskStore + options.TaskStore = new InMemoryMcpTaskStore(); + }, + assertResult: (_, response) => + { + var result = JsonSerializer.Deserialize(response, McpJsonUtilities.DefaultOptions); + Assert.NotNull(result); + + // Use reflection to verify every public property on ServerCapabilities is non-null. + // This catches cases where new capability properties are added but not copied + // from options in McpServerImpl. + foreach (var property in typeof(ServerCapabilities).GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + if (!property.CanRead) + { + continue; + } + + Assert.True( + property.GetValue(result.Capabilities) is not null, + $"ServerCapabilities.{property.Name} was set on options but is null in the initialize response. " + + $"Ensure the property is copied in McpServerImpl's Configure* methods."); + } + }); + } +#pragma warning restore MCPEXP001 + [Fact] public async Task Can_Handle_Completion_Requests() { From 61fe3301a6b6eb4f8d673d996997b20a08451a21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 21:49:18 +0000 Subject: [PATCH 3/6] Improve comment clarity in reflection-based test Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- tests/ModelContextProtocol.Tests/Server/McpServerTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs index d242e5424..6508f9fee 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs @@ -334,7 +334,8 @@ public async Task Initialize_CopiesAllCapabilityProperties() { // Set every public property on ServerCapabilities to a non-null value. // If a new property is added to ServerCapabilities in the future but the - // server fails to copy it, this test will fail as a reminder. + // server fails to copy it, this reflection-based test will automatically + // detect the missing property and fail. var inputCapabilities = new ServerCapabilities { Experimental = new Dictionary { ["test"] = new JsonObject() }, From ce962063f882f7ceda27af85c055a1be4f8ec919 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 22:15:18 +0000 Subject: [PATCH 4/6] Use public Extensions property instead of internal ExtensionsCore Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- src/ModelContextProtocol.Core/Server/McpServerImpl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs index 25fae3884..2bb8f6455 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs @@ -265,7 +265,7 @@ private void ConfigureCompletion(McpServerOptions options) private void ConfigureExperimental(McpServerOptions options) { ServerCapabilities.Experimental = options.Capabilities?.Experimental; - ServerCapabilities.ExtensionsCore = options.Capabilities?.ExtensionsCore; + ServerCapabilities.Extensions = options.Capabilities?.Extensions; } private void ConfigureResources(McpServerOptions options) From c108e2ea0c18aade2c8e6346403e35e6ea0e5d5a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 22:18:04 +0000 Subject: [PATCH 5/6] Remove redundant #pragma warning disable MCPEXP001 (already in Directory.Build.props) Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- tests/ModelContextProtocol.Tests/Server/McpServerTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs index 6508f9fee..ea680ecf0 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerTests.cs @@ -290,7 +290,6 @@ await Can_Handle_Requests( }); } -#pragma warning disable MCPEXP001 [Fact] public async Task Initialize_IncludesExtensionsInResponse() { From 2334e2d909f129a69cdc3fc0304ad84373776b21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Feb 2026 23:13:35 +0000 Subject: [PATCH 6/6] Rename ConfigureExperimental to ConfigureExperimentalAndExtensions and remove redundant = new() initializer Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- src/ModelContextProtocol.Core/Server/McpServerImpl.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs index 2bb8f6455..d9fd0e2e2 100644 --- a/src/ModelContextProtocol.Core/Server/McpServerImpl.cs +++ b/src/ModelContextProtocol.Core/Server/McpServerImpl.cs @@ -90,7 +90,7 @@ public McpServerImpl(ITransport transport, McpServerOptions options, ILoggerFact ConfigureTasks(options); ConfigureLogging(options); ConfigureCompletion(options); - ConfigureExperimental(options); + ConfigureExperimentalAndExtensions(options); // Register any notification handlers that were provided. if (options.Handlers.NotificationHandlers is { } notificationHandlers) @@ -138,7 +138,7 @@ void Register(McpServerPrimitiveCollection? collection, public override string? NegotiatedProtocolVersion => _negotiatedProtocolVersion; /// - public ServerCapabilities ServerCapabilities { get; } = new(); + public ServerCapabilities ServerCapabilities { get; } /// public override ClientCapabilities? ClientCapabilities => _clientCapabilities; @@ -262,7 +262,7 @@ private void ConfigureCompletion(McpServerOptions options) McpJsonUtilities.JsonContext.Default.CompleteResult); } - private void ConfigureExperimental(McpServerOptions options) + private void ConfigureExperimentalAndExtensions(McpServerOptions options) { ServerCapabilities.Experimental = options.Capabilities?.Experimental; ServerCapabilities.Extensions = options.Capabilities?.Extensions;