From 98ad9486174bb8b2ad31a8c1d3e8961c2c1e28f4 Mon Sep 17 00:00:00 2001 From: Zae Date: Sat, 22 Mar 2025 23:29:44 +0800 Subject: [PATCH 1/4] Fix enum serialization --- .../Client/McpClientExtensions.cs | 18 +----------------- .../Protocol/Types/LoggingLevel.cs | 16 ++++++++-------- .../Protocol/Types/Role.cs | 4 ++-- 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/src/ModelContextProtocol/Client/McpClientExtensions.cs b/src/ModelContextProtocol/Client/McpClientExtensions.cs index f11f02956..1a5c57cc3 100644 --- a/src/ModelContextProtocol/Client/McpClientExtensions.cs +++ b/src/ModelContextProtocol/Client/McpClientExtensions.cs @@ -485,7 +485,7 @@ public static Task SetLoggingLevel(this IMcpClient client, LoggingLevel level, C Throw.IfNull(client); return client.SendRequestAsync( - CreateRequest("logging/setLevel", new() { ["level"] = level.ToJsonValue() }), + CreateRequest("logging/setLevel", new() { ["level"] = level }), cancellationToken); } @@ -514,22 +514,6 @@ private static JsonRpcRequest CreateRequest(string method, Dictionary "debug", - LoggingLevel.Info => "info", - LoggingLevel.Notice => "notice", - LoggingLevel.Warning => "warning", - LoggingLevel.Error => "error", - LoggingLevel.Critical => "critical", - LoggingLevel.Alert => "alert", - LoggingLevel.Emergency => "emergency", - _ => throw new ArgumentOutOfRangeException(nameof(level)) - }; - } - /// Provides an AI function that calls a tool through . private sealed class McpAIFunction(IMcpClient client, Tool tool) : AIFunction { diff --git a/src/ModelContextProtocol/Protocol/Types/LoggingLevel.cs b/src/ModelContextProtocol/Protocol/Types/LoggingLevel.cs index 4e603e69e..1aac7d5d4 100644 --- a/src/ModelContextProtocol/Protocol/Types/LoggingLevel.cs +++ b/src/ModelContextProtocol/Protocol/Types/LoggingLevel.cs @@ -10,34 +10,34 @@ namespace ModelContextProtocol.Protocol.Types; public enum LoggingLevel { /// Detailed debug information, typically only valuable to developers. - [JsonPropertyName("debug")] + [JsonStringEnumMemberName("debug")] Debug, /// Normal operational messages that require no action. - [JsonPropertyName("info")] + [JsonStringEnumMemberName("info")] Info, /// Normal but significant events that might deserve attention. - [JsonPropertyName("notice")] + [JsonStringEnumMemberName("notice")] Notice, /// Warning conditions that don't represent an error but indicate potential issues. - [JsonPropertyName("warning")] + [JsonStringEnumMemberName("warning")] Warning, /// Error conditions that should be addressed but don't require immediate action. - [JsonPropertyName("error")] + [JsonStringEnumMemberName("error")] Error, /// Critical conditions that require immediate attention. - [JsonPropertyName("critical")] + [JsonStringEnumMemberName("critical")] Critical, /// Action must be taken immediately to address the condition. - [JsonPropertyName("alert")] + [JsonStringEnumMemberName("alert")] Alert, /// System is unusable and requires immediate attention. - [JsonPropertyName("emergency")] + [JsonStringEnumMemberName("emergency")] Emergency } \ No newline at end of file diff --git a/src/ModelContextProtocol/Protocol/Types/Role.cs b/src/ModelContextProtocol/Protocol/Types/Role.cs index a8266a057..57a39ff62 100644 --- a/src/ModelContextProtocol/Protocol/Types/Role.cs +++ b/src/ModelContextProtocol/Protocol/Types/Role.cs @@ -11,12 +11,12 @@ public enum Role /// /// Corresponds to the user in the conversation. /// - [JsonPropertyName("user")] + [JsonStringEnumMemberName("user")] User, /// /// Corresponds to the AI in the conversation. /// - [JsonPropertyName("assistant")] + [JsonStringEnumMemberName("assistant")] Assistant } \ No newline at end of file From 5bb20179e09fb6e4d6b70031280a3ebf666daf31 Mon Sep 17 00:00:00 2001 From: Zae Date: Sun, 23 Mar 2025 01:54:51 +0800 Subject: [PATCH 2/4] Add tests for enum serialization --- .../Protocol/ProtocolTypeTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs b/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs index a5c4c6a35..872915620 100644 --- a/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs +++ b/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs @@ -1,4 +1,5 @@ using ModelContextProtocol.Protocol.Types; +using ModelContextProtocol.Utils.Json; using System.Text.Json; namespace ModelContextProtocol.Tests.Protocol; @@ -51,4 +52,30 @@ public static void ToolInputSchema_AcceptsValidSchemaDocuments(string validSchem Assert.True(JsonElement.DeepEquals(document.RootElement, tool.InputSchema)); } + + [Theory] + [InlineData(Role.User, "\"user\"")] + [InlineData(Role.Assistant, "\"assistant\"")] + public static void SerializeRole_Should_Be_Lower_Case(Role role, string expectedValue) + { + var actualValue = JsonSerializer.Serialize(role, McpJsonUtilities.DefaultOptions); + + Assert.Equal(expectedValue, actualValue); + } + + [Theory] + [InlineData(LoggingLevel.Debug, "\"debug\"")] + [InlineData(LoggingLevel.Info, "\"info\"")] + [InlineData(LoggingLevel.Notice, "\"notice\"")] + [InlineData(LoggingLevel.Warning, "\"warning\"")] + [InlineData(LoggingLevel.Error, "\"error\"")] + [InlineData(LoggingLevel.Critical, "\"critical\"")] + [InlineData(LoggingLevel.Alert, "\"alert\"")] + [InlineData(LoggingLevel.Emergency, "\"emergency\"")] + public static void SerializeLoggingLevel_Should_Be_Lower_Case(LoggingLevel level, string expectedValue) + { + var actualValue = JsonSerializer.Serialize(level, McpJsonUtilities.DefaultOptions); + + Assert.Equal(expectedValue, actualValue); + } } From e729a1cfee746944e08c2536204536fa8d895ba1 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Mon, 24 Mar 2025 12:33:21 +0000 Subject: [PATCH 3/4] Add missing enum serialization configuration. --- .../Protocol/Types/ContextInclusion.cs | 8 +++++++- src/ModelContextProtocol/Protocol/Types/LoggingLevel.cs | 1 + src/ModelContextProtocol/Protocol/Types/Role.cs | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ModelContextProtocol/Protocol/Types/ContextInclusion.cs b/src/ModelContextProtocol/Protocol/Types/ContextInclusion.cs index 50fbc3de9..a513e4d7c 100644 --- a/src/ModelContextProtocol/Protocol/Types/ContextInclusion.cs +++ b/src/ModelContextProtocol/Protocol/Types/ContextInclusion.cs @@ -1,23 +1,29 @@ -namespace ModelContextProtocol.Protocol.Types; +using System.Text.Json.Serialization; + +namespace ModelContextProtocol.Protocol.Types; /// /// A request to include context from one or more MCP servers (including the caller), to be attached to the prompt. /// See the schema for details /// +[JsonConverter(typeof(JsonStringEnumConverter))] public enum ContextInclusion { /// /// No context should be included. /// + [JsonStringEnumMemberName("none")] None, /// /// Include context from the server that sent the request. /// + [JsonStringEnumMemberName("thisServer")] ThisServer, /// /// Include context from all servers that the client is connected to. /// + [JsonStringEnumMemberName("allServers")] AllServers } diff --git a/src/ModelContextProtocol/Protocol/Types/LoggingLevel.cs b/src/ModelContextProtocol/Protocol/Types/LoggingLevel.cs index 1aac7d5d4..df8c4c75a 100644 --- a/src/ModelContextProtocol/Protocol/Types/LoggingLevel.cs +++ b/src/ModelContextProtocol/Protocol/Types/LoggingLevel.cs @@ -7,6 +7,7 @@ namespace ModelContextProtocol.Protocol.Types; /// These map to syslog message severities, as specified in RFC-5424: /// https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1 /// +[JsonConverter(typeof(JsonStringEnumConverter))] public enum LoggingLevel { /// Detailed debug information, typically only valuable to developers. diff --git a/src/ModelContextProtocol/Protocol/Types/Role.cs b/src/ModelContextProtocol/Protocol/Types/Role.cs index 57a39ff62..91c9899ae 100644 --- a/src/ModelContextProtocol/Protocol/Types/Role.cs +++ b/src/ModelContextProtocol/Protocol/Types/Role.cs @@ -6,6 +6,7 @@ namespace ModelContextProtocol.Protocol.Types; /// Represents the type of role in the conversation. /// See the schema for details /// +[JsonConverter(typeof(JsonStringEnumConverter))] public enum Role { /// From b24fb1567536a83661f93a6bbccf4aa02a5e7cf8 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Mon, 24 Mar 2025 12:42:17 +0000 Subject: [PATCH 4/4] Ensure enums serialize as expected using defaults --- .../Protocol/ProtocolTypeTests.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs b/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs index 872915620..812643367 100644 --- a/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs +++ b/tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs @@ -56,9 +56,9 @@ public static void ToolInputSchema_AcceptsValidSchemaDocuments(string validSchem [Theory] [InlineData(Role.User, "\"user\"")] [InlineData(Role.Assistant, "\"assistant\"")] - public static void SerializeRole_Should_Be_Lower_Case(Role role, string expectedValue) + public static void SerializeRole_ShouldBeCamelCased(Role role, string expectedValue) { - var actualValue = JsonSerializer.Serialize(role, McpJsonUtilities.DefaultOptions); + var actualValue = JsonSerializer.Serialize(role); Assert.Equal(expectedValue, actualValue); } @@ -72,9 +72,20 @@ public static void SerializeRole_Should_Be_Lower_Case(Role role, string expected [InlineData(LoggingLevel.Critical, "\"critical\"")] [InlineData(LoggingLevel.Alert, "\"alert\"")] [InlineData(LoggingLevel.Emergency, "\"emergency\"")] - public static void SerializeLoggingLevel_Should_Be_Lower_Case(LoggingLevel level, string expectedValue) + public static void SerializeLoggingLevel_ShouldBeCamelCased(LoggingLevel level, string expectedValue) { - var actualValue = JsonSerializer.Serialize(level, McpJsonUtilities.DefaultOptions); + var actualValue = JsonSerializer.Serialize(level); + + Assert.Equal(expectedValue, actualValue); + } + + [Theory] + [InlineData(ContextInclusion.None, "\"none\"")] + [InlineData(ContextInclusion.ThisServer, "\"thisServer\"")] + [InlineData(ContextInclusion.AllServers, "\"allServers\"")] + public static void ContextInclusion_ShouldBeCamelCased(ContextInclusion level, string expectedValue) + { + var actualValue = JsonSerializer.Serialize(level); Assert.Equal(expectedValue, actualValue); }