From 495609f8f5a4f4fa17f13eb3e1af940f21cd2c51 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 20 May 2026 23:15:58 +0000
Subject: [PATCH 1/6] Initial plan
From 56b7101849c1c58b5f2e5fb360ee117ab940ba76 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 20 May 2026 23:21:47 +0000
Subject: [PATCH 2/6] Negotiate MCP initialize protocol version with client
request
Agent-Logs-Url: https://github.com/Azure/data-api-builder/sessions/7e83ced0-915a-414d-8d89-2533684eb764
Co-authored-by: Aniruddh25 <3513779+Aniruddh25@users.noreply.github.com>
---
.../Core/McpProtocolDefaults.cs | 35 +++++++++++-
.../Core/McpStdioServer.cs | 35 +++++++++---
.../UnitTests/McpProtocolDefaultsTests.cs | 53 +++++++++++++++++++
3 files changed, 114 insertions(+), 9 deletions(-)
create mode 100644 src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
diff --git a/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs b/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs
index 48b235f480..60e4a1bc3a 100644
--- a/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs
+++ b/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs
@@ -1,3 +1,4 @@
+using System.Globalization;
using Azure.DataApiBuilder.Product;
using Microsoft.Extensions.Configuration;
@@ -19,7 +20,7 @@ public static class McpProtocolDefaults
///
/// Default MCP protocol version advertised when no configuration override is provided.
///
- public const string DEFAULT_PROTOCOL_VERSION = "2025-06-18";
+ public const string DEFAULT_PROTOCOL_VERSION = "2025-11-25";
///
/// Configuration key used to override the MCP protocol version.
@@ -34,6 +35,36 @@ public static string ResolveProtocolVersion(IConfiguration? configuration)
{
return configuration?.GetValue(PROTOCOL_VERSION_CONFIG_KEY) ?? DEFAULT_PROTOCOL_VERSION;
}
+
+ ///
+ /// Resolves the protocol version to send in initialize response as the
+ /// greatest version that does not exceed the client requested version.
+ ///
+ /// The server's effective supported protocol version.
+ /// The protocol version requested by the client.
+ /// The protocol version to return to the client.
+ public static string ResolveInitializeResponseProtocolVersion(string supportedProtocolVersion, string? clientRequestedProtocolVersion)
+ {
+ if (string.IsNullOrWhiteSpace(clientRequestedProtocolVersion))
+ {
+ return supportedProtocolVersion;
+ }
+
+ return CompareProtocolVersions(supportedProtocolVersion, clientRequestedProtocolVersion) <= 0
+ ? supportedProtocolVersion
+ : clientRequestedProtocolVersion;
+ }
+
+ private static int CompareProtocolVersions(string leftVersion, string rightVersion)
+ {
+ const string FORMAT = "yyyy-MM-dd";
+ if (DateOnly.TryParseExact(leftVersion, FORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly leftDate) &&
+ DateOnly.TryParseExact(rightVersion, FORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly rightDate))
+ {
+ return leftDate.CompareTo(rightDate);
+ }
+
+ return string.Compare(leftVersion, rightVersion, StringComparison.Ordinal);
+ }
}
}
-
diff --git a/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs b/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs
index 6736c7d57d..d8d5c61dc0 100644
--- a/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs
+++ b/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs
@@ -115,7 +115,7 @@ public async Task RunAsync(CancellationToken cancellationToken)
switch (method)
{
case "initialize":
- HandleInitialize(id);
+ HandleInitialize(id, root);
break;
case "notifications/initialized":
@@ -160,13 +160,18 @@ public async Task RunAsync(CancellationToken cancellationToken)
///
/// The request identifier extracted from the incoming JSON-RPC request. Used to correlate the response with the request.
///
+ /// The incoming initialize request payload.
///
- /// This method constructs and writes the MCP "initialize" response to STDOUT. It uses the protocol version defined by PROTOCOL_VERSION
- /// and includes supported capabilities and server information. No notifications are sent here; the server waits for the client to send
- /// "notifications/initialized" before sending any notifications.
+ /// This method constructs and writes the MCP "initialize" response to STDOUT. It negotiates the response protocol version from the
+ /// server-supported version and client-requested version, and includes supported capabilities and server information. No notifications
+ /// are sent here; the server waits for the client to send "notifications/initialized" before sending any notifications.
///
- private void HandleInitialize(JsonElement? id)
+ private void HandleInitialize(JsonElement? id, JsonElement root)
{
+ string? clientRequestedProtocolVersion = TryGetClientProtocolVersion(root);
+ string negotiatedProtocolVersion =
+ McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(_protocolVersion, clientRequestedProtocolVersion);
+
// Get the description from runtime config if available
string? instructions = null;
RuntimeConfigProvider? runtimeConfigProvider = _serviceProvider.GetService();
@@ -190,7 +195,7 @@ private void HandleInitialize(JsonElement? id)
{
result = new
{
- protocolVersion = _protocolVersion,
+ protocolVersion = negotiatedProtocolVersion,
capabilities = new
{
tools = new { listChanged = true },
@@ -208,7 +213,7 @@ private void HandleInitialize(JsonElement? id)
{
result = new
{
- protocolVersion = _protocolVersion,
+ protocolVersion = negotiatedProtocolVersion,
capabilities = new
{
tools = new { listChanged = true },
@@ -225,6 +230,22 @@ private void HandleInitialize(JsonElement? id)
WriteResult(id, result);
}
+ private static string? TryGetClientProtocolVersion(JsonElement root)
+ {
+ if (!root.TryGetProperty("params", out JsonElement paramsElement) || paramsElement.ValueKind != JsonValueKind.Object)
+ {
+ return null;
+ }
+
+ if (!paramsElement.TryGetProperty("protocolVersion", out JsonElement protocolVersionElement) ||
+ protocolVersionElement.ValueKind != JsonValueKind.String)
+ {
+ return null;
+ }
+
+ return protocolVersionElement.GetString();
+ }
+
///
/// Handles the "tools/list" JSON-RPC method by sending the list of available tools to the client.
///
diff --git a/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs b/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
new file mode 100644
index 0000000000..1e01f2b2e0
--- /dev/null
+++ b/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Azure.DataApiBuilder.Mcp.Core;
+using Microsoft.Extensions.Configuration;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Azure.DataApiBuilder.Service.Tests.UnitTests
+{
+ [TestClass]
+ public class McpProtocolDefaultsTests
+ {
+ [TestMethod]
+ public void ResolveProtocolVersion_WithoutOverride_UsesLatestDefault()
+ {
+ IConfiguration config = new ConfigurationBuilder().Build();
+
+ string resolved = McpProtocolDefaults.ResolveProtocolVersion(config);
+
+ Assert.AreEqual("2025-11-25", resolved);
+ }
+
+ [TestMethod]
+ public void ResolveInitializeResponseProtocolVersion_ClientRequestsNewerVersion_ReturnsSupportedVersion()
+ {
+ string resolved = McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(
+ supportedProtocolVersion: "2025-11-25",
+ clientRequestedProtocolVersion: "2026-01-01");
+
+ Assert.AreEqual("2025-11-25", resolved);
+ }
+
+ [TestMethod]
+ public void ResolveInitializeResponseProtocolVersion_ClientRequestsOlderVersion_ReturnsClientVersion()
+ {
+ string resolved = McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(
+ supportedProtocolVersion: "2025-11-25",
+ clientRequestedProtocolVersion: "2025-06-18");
+
+ Assert.AreEqual("2025-06-18", resolved);
+ }
+
+ [TestMethod]
+ public void ResolveInitializeResponseProtocolVersion_WithoutClientVersion_ReturnsSupportedVersion()
+ {
+ string resolved = McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(
+ supportedProtocolVersion: "2025-11-25",
+ clientRequestedProtocolVersion: null);
+
+ Assert.AreEqual("2025-11-25", resolved);
+ }
+ }
+}
From 86564d1c5dda6178624508a0794078c948fbb93b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 20 May 2026 23:25:48 +0000
Subject: [PATCH 3/6] Address MCP protocol negotiation review feedback
Agent-Logs-Url: https://github.com/Azure/data-api-builder/sessions/7e83ced0-915a-414d-8d89-2533684eb764
Co-authored-by: Aniruddh25 <3513779+Aniruddh25@users.noreply.github.com>
---
.../Core/McpProtocolDefaults.cs | 6 +++---
src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs | 4 ++--
.../UnitTests/McpProtocolDefaultsTests.cs | 12 +++++++++++-
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs b/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs
index 60e4a1bc3a..0cfcb5b424 100644
--- a/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs
+++ b/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs
@@ -57,9 +57,9 @@ public static string ResolveInitializeResponseProtocolVersion(string supportedPr
private static int CompareProtocolVersions(string leftVersion, string rightVersion)
{
- const string FORMAT = "yyyy-MM-dd";
- if (DateOnly.TryParseExact(leftVersion, FORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly leftDate) &&
- DateOnly.TryParseExact(rightVersion, FORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly rightDate))
+ const string PROTOCOL_VERSION_DATE_FORMAT = "yyyy-MM-dd";
+ if (DateOnly.TryParseExact(leftVersion, PROTOCOL_VERSION_DATE_FORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly leftDate) &&
+ DateOnly.TryParseExact(rightVersion, PROTOCOL_VERSION_DATE_FORMAT, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateOnly rightDate))
{
return leftDate.CompareTo(rightDate);
}
diff --git a/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs b/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs
index d8d5c61dc0..7165bf511d 100644
--- a/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs
+++ b/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs
@@ -168,7 +168,7 @@ public async Task RunAsync(CancellationToken cancellationToken)
///
private void HandleInitialize(JsonElement? id, JsonElement root)
{
- string? clientRequestedProtocolVersion = TryGetClientProtocolVersion(root);
+ string? clientRequestedProtocolVersion = GetClientProtocolVersion(root);
string negotiatedProtocolVersion =
McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(_protocolVersion, clientRequestedProtocolVersion);
@@ -230,7 +230,7 @@ private void HandleInitialize(JsonElement? id, JsonElement root)
WriteResult(id, result);
}
- private static string? TryGetClientProtocolVersion(JsonElement root)
+ private static string? GetClientProtocolVersion(JsonElement root)
{
if (!root.TryGetProperty("params", out JsonElement paramsElement) || paramsElement.ValueKind != JsonValueKind.Object)
{
diff --git a/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs b/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
index 1e01f2b2e0..c0b4dbb118 100644
--- a/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
+++ b/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
@@ -21,7 +21,7 @@ public void ResolveProtocolVersion_WithoutOverride_UsesLatestDefault()
}
[TestMethod]
- public void ResolveInitializeResponseProtocolVersion_ClientRequestsNewerVersion_ReturnsSupportedVersion()
+ public void ResolveInitializeResponseProtocolVersion_ClientRequestsNewerVersion_ReturnsServerSupportedVersion()
{
string resolved = McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(
supportedProtocolVersion: "2025-11-25",
@@ -49,5 +49,15 @@ public void ResolveInitializeResponseProtocolVersion_WithoutClientVersion_Return
Assert.AreEqual("2025-11-25", resolved);
}
+
+ [TestMethod]
+ public void ResolveInitializeResponseProtocolVersion_NonDateVersionFormat_UsesOrdinalFallbackComparison()
+ {
+ string resolved = McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(
+ supportedProtocolVersion: "a-version",
+ clientRequestedProtocolVersion: "z-version");
+
+ Assert.AreEqual("a-version", resolved);
+ }
}
}
From 474557b51db93524a2cb288d3a8b98923444c63e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 21 May 2026 00:08:11 +0000
Subject: [PATCH 4/6] Use serverInfo.description for MCP 2025-11-25 initialize
metadata
Agent-Logs-Url: https://github.com/Azure/data-api-builder/sessions/86017944-515e-443c-9f16-545350791623
Co-authored-by: Aniruddh25 <3513779+Aniruddh25@users.noreply.github.com>
---
.../Core/McpProtocolDefaults.cs | 13 ++++++++
.../Core/McpStdioServer.cs | 30 +++++++++++++++----
.../UnitTests/McpProtocolDefaultsTests.cs | 13 ++++++++
3 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs b/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs
index 0cfcb5b424..289f6aa72d 100644
--- a/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs
+++ b/src/Azure.DataApiBuilder.Mcp/Core/McpProtocolDefaults.cs
@@ -27,6 +27,11 @@ public static class McpProtocolDefaults
///
public const string PROTOCOL_VERSION_CONFIG_KEY = "MCP:ProtocolVersion";
+ ///
+ /// Protocol version where MCP initialize server description is expected under serverInfo.description.
+ ///
+ public const string SERVER_INFO_DESCRIPTION_PROTOCOL_VERSION = "2025-11-25";
+
///
/// Helper to resolve the effective protocol version from configuration.
/// Falls back to when the key is not set.
@@ -55,6 +60,14 @@ public static string ResolveInitializeResponseProtocolVersion(string supportedPr
: clientRequestedProtocolVersion;
}
+ ///
+ /// Indicates whether initialize response metadata should use serverInfo.description instead of top-level instructions.
+ ///
+ public static bool ShouldUseServerInfoDescription(string protocolVersion)
+ {
+ return CompareProtocolVersions(protocolVersion, SERVER_INFO_DESCRIPTION_PROTOCOL_VERSION) >= 0;
+ }
+
private static int CompareProtocolVersions(string leftVersion, string rightVersion)
{
const string PROTOCOL_VERSION_DATE_FORMAT = "yyyy-MM-dd";
diff --git a/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs b/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs
index 7165bf511d..835b5db662 100644
--- a/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs
+++ b/src/Azure.DataApiBuilder.Mcp/Core/McpStdioServer.cs
@@ -173,14 +173,14 @@ private void HandleInitialize(JsonElement? id, JsonElement root)
McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(_protocolVersion, clientRequestedProtocolVersion);
// Get the description from runtime config if available
- string? instructions = null;
+ string? description = null;
RuntimeConfigProvider? runtimeConfigProvider = _serviceProvider.GetService();
if (runtimeConfigProvider != null)
{
try
{
RuntimeConfig runtimeConfig = runtimeConfigProvider.GetConfig();
- instructions = runtimeConfig.Runtime?.Mcp?.Description;
+ description = runtimeConfig.Runtime?.Mcp?.Description;
}
catch (Exception)
{
@@ -189,9 +189,29 @@ private void HandleInitialize(JsonElement? id, JsonElement root)
}
}
- // Create the initialize response - only include instructions if non-empty
+ bool shouldUseServerInfoDescription = McpProtocolDefaults.ShouldUseServerInfoDescription(negotiatedProtocolVersion);
+
+ // Create the initialize response - only include description/instructions if non-empty
object result;
- if (!string.IsNullOrWhiteSpace(instructions))
+ if (!string.IsNullOrWhiteSpace(description) && shouldUseServerInfoDescription)
+ {
+ result = new
+ {
+ protocolVersion = negotiatedProtocolVersion,
+ capabilities = new
+ {
+ tools = new { listChanged = true },
+ logging = new { }
+ },
+ serverInfo = new
+ {
+ name = McpProtocolDefaults.MCP_SERVER_NAME,
+ version = McpProtocolDefaults.MCP_SERVER_VERSION,
+ description = description
+ }
+ };
+ }
+ else if (!string.IsNullOrWhiteSpace(description))
{
result = new
{
@@ -206,7 +226,7 @@ private void HandleInitialize(JsonElement? id, JsonElement root)
name = McpProtocolDefaults.MCP_SERVER_NAME,
version = McpProtocolDefaults.MCP_SERVER_VERSION
},
- instructions = instructions
+ instructions = description
};
}
else
diff --git a/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs b/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
index c0b4dbb118..1846abb548 100644
--- a/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
+++ b/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
@@ -59,5 +59,18 @@ public void ResolveInitializeResponseProtocolVersion_NonDateVersionFormat_UsesOr
Assert.AreEqual("a-version", resolved);
}
+
+ [TestMethod]
+ public void ShouldUseServerInfoDescription_AtOrAboveThreshold_ReturnsTrue()
+ {
+ Assert.IsTrue(McpProtocolDefaults.ShouldUseServerInfoDescription("2025-11-25"));
+ Assert.IsTrue(McpProtocolDefaults.ShouldUseServerInfoDescription("2025-12-01"));
+ }
+
+ [TestMethod]
+ public void ShouldUseServerInfoDescription_BelowThreshold_ReturnsFalse()
+ {
+ Assert.IsFalse(McpProtocolDefaults.ShouldUseServerInfoDescription("2025-06-18"));
+ }
}
}
From 73540aafdc779eb650e29e345c58b5e55373b61f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 21 May 2026 20:02:28 +0000
Subject: [PATCH 5/6] Add HandleInitialize wire-shape tests for MCP initialize
responses
Agent-Logs-Url: https://github.com/Azure/data-api-builder/sessions/901e8c47-40c1-4349-82f3-727b5c85a884
Co-authored-by: aaronburtle <93220300+aaronburtle@users.noreply.github.com>
---
.../McpStdioServerInitializeTests.cs | 200 ++++++++++++++++++
1 file changed, 200 insertions(+)
create mode 100644 src/Service.Tests/UnitTests/McpStdioServerInitializeTests.cs
diff --git a/src/Service.Tests/UnitTests/McpStdioServerInitializeTests.cs b/src/Service.Tests/UnitTests/McpStdioServerInitializeTests.cs
new file mode 100644
index 0000000000..53cff20188
--- /dev/null
+++ b/src/Service.Tests/UnitTests/McpStdioServerInitializeTests.cs
@@ -0,0 +1,200 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#nullable enable
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Reflection;
+using System.Text.Json;
+using Azure.DataApiBuilder.Config;
+using Azure.DataApiBuilder.Config.ObjectModel;
+using Azure.DataApiBuilder.Core.Configurations;
+using Azure.DataApiBuilder.Mcp.Core;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace Azure.DataApiBuilder.Service.Tests.UnitTests
+{
+ [TestClass]
+ public class McpStdioServerInitializeTests
+ {
+ [TestMethod]
+ public void HandleInitialize_ClientRequests2025_11_25_WithDescription_UsesServerInfoDescription()
+ {
+ const string DESCRIPTION = "mcp description";
+ McpStdioServer server = CreateServer(description: DESCRIPTION, out StringWriter stdoutCapture);
+
+ JsonElement responseRoot = InvokeHandleInitialize(
+ server,
+ stdoutCapture,
+ """
+ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"client","version":"1.0.0"}}}
+ """);
+
+ AssertInitializeEnvelopeAndCapabilities(responseRoot, expectedId: 1, expectedProtocolVersion: "2025-11-25");
+ JsonElement result = responseRoot.GetProperty("result");
+
+ Assert.IsTrue(result.TryGetProperty("serverInfo", out JsonElement serverInfo), "Expected result.serverInfo.");
+ Assert.AreEqual(DESCRIPTION, serverInfo.GetProperty("description").GetString());
+ Assert.IsFalse(result.TryGetProperty("instructions", out _), "Did not expect top-level instructions for 2025-11-25.");
+ Assert.AreEqual(1, CountOutputLines(stdoutCapture));
+ }
+
+ [TestMethod]
+ public void HandleInitialize_ClientRequests2025_06_18_WithDescription_UsesTopLevelInstructions()
+ {
+ const string DESCRIPTION = "legacy instruction text";
+ McpStdioServer server = CreateServer(description: DESCRIPTION, out StringWriter stdoutCapture);
+
+ JsonElement responseRoot = InvokeHandleInitialize(
+ server,
+ stdoutCapture,
+ """
+ {"jsonrpc":"2.0","id":"abc","method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"client","version":"1.0.0"}}}
+ """);
+
+ AssertInitializeEnvelopeAndCapabilities(responseRoot, expectedId: "abc", expectedProtocolVersion: "2025-06-18");
+ JsonElement result = responseRoot.GetProperty("result");
+
+ Assert.AreEqual(DESCRIPTION, result.GetProperty("instructions").GetString());
+ Assert.IsFalse(result.GetProperty("serverInfo").TryGetProperty("description", out _), "Did not expect serverInfo.description for 2025-06-18.");
+ Assert.AreEqual(1, CountOutputLines(stdoutCapture));
+ }
+
+ [TestMethod]
+ public void HandleInitialize_ClientRequests2025_11_25_WithoutDescription_EmitsNeitherField()
+ {
+ McpStdioServer server = CreateServer(description: null, out StringWriter stdoutCapture);
+
+ JsonElement responseRoot = InvokeHandleInitialize(
+ server,
+ stdoutCapture,
+ """
+ {"jsonrpc":"2.0","id":2,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"client","version":"1.0.0"}}}
+ """);
+
+ AssertInitializeEnvelopeAndCapabilities(responseRoot, expectedId: 2, expectedProtocolVersion: "2025-11-25");
+ JsonElement result = responseRoot.GetProperty("result");
+
+ Assert.IsFalse(result.TryGetProperty("instructions", out _), "Did not expect top-level instructions when description is not configured.");
+ Assert.IsFalse(result.GetProperty("serverInfo").TryGetProperty("description", out _), "Did not expect serverInfo.description when description is not configured.");
+ Assert.AreEqual(1, CountOutputLines(stdoutCapture));
+ }
+
+ private static McpStdioServer CreateServer(string? description, out StringWriter stdoutCapture)
+ {
+ stdoutCapture = new StringWriter();
+ McpStdoutWriter stdoutWriter = new(stdoutCapture);
+
+ RuntimeConfig runtimeConfig = new(
+ Schema: RuntimeConfig.DEFAULT_CONFIG_SCHEMA_LINK,
+ DataSource: null,
+ Entities: new RuntimeEntities(new Dictionary()),
+ Runtime: new RuntimeOptions(
+ Rest: null,
+ GraphQL: null,
+ Mcp: new McpRuntimeOptions(Description: description),
+ Host: null));
+ RuntimeConfigProvider runtimeConfigProvider = new StubRuntimeConfigProvider(runtimeConfig);
+
+ IConfiguration configuration = new ConfigurationBuilder().Build();
+ ServiceProvider serviceProvider = new ServiceCollection()
+ .AddSingleton(configuration)
+ .AddSingleton(stdoutWriter)
+ .AddSingleton(runtimeConfigProvider)
+ .BuildServiceProvider();
+
+ return new McpStdioServer(new McpToolRegistry(), serviceProvider);
+ }
+
+ private static JsonElement InvokeHandleInitialize(McpStdioServer server, StringWriter stdoutCapture, string initializeRequestJson)
+ {
+ MethodInfo? handleInitialize = typeof(McpStdioServer).GetMethod("HandleInitialize", BindingFlags.NonPublic | BindingFlags.Instance);
+ Assert.IsNotNull(handleInitialize, "Expected private HandleInitialize method to exist.");
+
+ using JsonDocument request = JsonDocument.Parse(initializeRequestJson);
+ JsonElement requestRoot = request.RootElement;
+ JsonElement? id = requestRoot.TryGetProperty("id", out JsonElement idElement) ? idElement : null;
+
+ handleInitialize.Invoke(server, new object?[] { id, requestRoot });
+
+ string output = ExtractSingleOutputLine(stdoutCapture);
+ using JsonDocument response = JsonDocument.Parse(output);
+ return response.RootElement.Clone();
+ }
+
+ private static void AssertInitializeEnvelopeAndCapabilities(JsonElement responseRoot, object expectedId, string expectedProtocolVersion)
+ {
+ Assert.AreEqual("2.0", responseRoot.GetProperty("jsonrpc").GetString());
+ if (expectedId is int expectedNumericId)
+ {
+ Assert.AreEqual(expectedNumericId, responseRoot.GetProperty("id").GetInt32());
+ }
+ else
+ {
+ Assert.AreEqual(expectedId, responseRoot.GetProperty("id").GetString());
+ }
+
+ JsonElement result = responseRoot.GetProperty("result");
+ Assert.AreEqual(expectedProtocolVersion, result.GetProperty("protocolVersion").GetString());
+
+ JsonElement capabilities = result.GetProperty("capabilities");
+ Assert.IsTrue(capabilities.GetProperty("tools").GetProperty("listChanged").GetBoolean());
+ Assert.AreEqual(JsonValueKind.Object, capabilities.GetProperty("logging").ValueKind);
+
+ JsonElement serverInfo = result.GetProperty("serverInfo");
+ Assert.AreEqual(McpProtocolDefaults.MCP_SERVER_NAME, serverInfo.GetProperty("name").GetString());
+ Assert.AreEqual(McpProtocolDefaults.MCP_SERVER_VERSION, serverInfo.GetProperty("version").GetString());
+ }
+
+ private static int CountOutputLines(StringWriter stdoutCapture)
+ {
+ return stdoutCapture
+ .ToString()
+ .Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries)
+ .Length;
+ }
+
+ private static string ExtractSingleOutputLine(StringWriter stdoutCapture)
+ {
+ string[] lines = stdoutCapture
+ .ToString()
+ .Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
+ Assert.AreEqual(1, lines.Length, "Expected a single JSON-RPC response line.");
+ return lines[0];
+ }
+
+ private sealed class StubRuntimeConfigProvider : RuntimeConfigProvider
+ {
+ private readonly RuntimeConfig _runtimeConfig;
+
+ public StubRuntimeConfigProvider(RuntimeConfig runtimeConfig) : base(new StubRuntimeConfigLoader())
+ {
+ _runtimeConfig = runtimeConfig;
+ }
+
+ public override RuntimeConfig GetConfig()
+ {
+ return _runtimeConfig;
+ }
+ }
+
+ private sealed class StubRuntimeConfigLoader : RuntimeConfigLoader
+ {
+ public override bool TryLoadKnownConfig([NotNullWhen(true)] out RuntimeConfig? config, bool replaceEnvVar = false)
+ {
+ config = null;
+ return false;
+ }
+
+ public override string GetPublishedDraftSchemaLink()
+ {
+ return RuntimeConfig.DEFAULT_CONFIG_SCHEMA_LINK;
+ }
+ }
+ }
+}
From 59dca7adf66507cd50e5ecb4f4fecb999c565260 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 21 May 2026 21:21:48 +0000
Subject: [PATCH 6/6] Refactor MCP protocol negotiation tests to DataRow and
add same-version case
---
.../UnitTests/McpProtocolDefaultsTests.cs | 48 +++++--------------
1 file changed, 13 insertions(+), 35 deletions(-)
diff --git a/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs b/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
index 1846abb548..341f17986a 100644
--- a/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
+++ b/src/Service.Tests/UnitTests/McpProtocolDefaultsTests.cs
@@ -20,44 +20,22 @@ public void ResolveProtocolVersion_WithoutOverride_UsesLatestDefault()
Assert.AreEqual("2025-11-25", resolved);
}
- [TestMethod]
- public void ResolveInitializeResponseProtocolVersion_ClientRequestsNewerVersion_ReturnsServerSupportedVersion()
- {
- string resolved = McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(
- supportedProtocolVersion: "2025-11-25",
- clientRequestedProtocolVersion: "2026-01-01");
-
- Assert.AreEqual("2025-11-25", resolved);
- }
-
- [TestMethod]
- public void ResolveInitializeResponseProtocolVersion_ClientRequestsOlderVersion_ReturnsClientVersion()
- {
- string resolved = McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(
- supportedProtocolVersion: "2025-11-25",
- clientRequestedProtocolVersion: "2025-06-18");
-
- Assert.AreEqual("2025-06-18", resolved);
- }
-
- [TestMethod]
- public void ResolveInitializeResponseProtocolVersion_WithoutClientVersion_ReturnsSupportedVersion()
- {
- string resolved = McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(
- supportedProtocolVersion: "2025-11-25",
- clientRequestedProtocolVersion: null);
-
- Assert.AreEqual("2025-11-25", resolved);
- }
-
- [TestMethod]
- public void ResolveInitializeResponseProtocolVersion_NonDateVersionFormat_UsesOrdinalFallbackComparison()
+ [DataTestMethod]
+ [DataRow("2025-11-25", "2026-01-01", "2025-11-25")]
+ [DataRow("2025-11-25", "2025-06-18", "2025-06-18")]
+ [DataRow("2025-11-25", "2025-11-25", "2025-11-25")]
+ [DataRow("2025-11-25", null, "2025-11-25")]
+ [DataRow("a-version", "z-version", "a-version")]
+ public void ResolveInitializeResponseProtocolVersion_ReturnsExpectedNegotiatedVersion(
+ string supportedProtocolVersion,
+ string clientRequestedProtocolVersion,
+ string expectedVersion)
{
string resolved = McpProtocolDefaults.ResolveInitializeResponseProtocolVersion(
- supportedProtocolVersion: "a-version",
- clientRequestedProtocolVersion: "z-version");
+ supportedProtocolVersion,
+ clientRequestedProtocolVersion);
- Assert.AreEqual("a-version", resolved);
+ Assert.AreEqual(expectedVersion, resolved);
}
[TestMethod]