Skip to content

Commit 96ba2fa

Browse files
Fix enum serialization (#61)
* Fix enum serialization * Add tests for enum serialization * Add missing enum serialization configuration. * Ensure enums serialize as expected using defaults --------- Co-authored-by: Eirik Tsarpalis <[email protected]>
1 parent 1a5732b commit 96ba2fa

File tree

5 files changed

+58
-28
lines changed

5 files changed

+58
-28
lines changed

src/ModelContextProtocol/Client/McpClientExtensions.cs

+1-17
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ public static Task SetLoggingLevel(this IMcpClient client, LoggingLevel level, C
485485
Throw.IfNull(client);
486486

487487
return client.SendRequestAsync<EmptyResult>(
488-
CreateRequest("logging/setLevel", new() { ["level"] = level.ToJsonValue() }),
488+
CreateRequest("logging/setLevel", new() { ["level"] = level }),
489489
cancellationToken);
490490
}
491491

@@ -514,22 +514,6 @@ private static JsonRpcRequest CreateRequest(string method, Dictionary<string, ob
514514
return parameters;
515515
}
516516

517-
private static string ToJsonValue(this LoggingLevel level)
518-
{
519-
return level switch
520-
{
521-
LoggingLevel.Debug => "debug",
522-
LoggingLevel.Info => "info",
523-
LoggingLevel.Notice => "notice",
524-
LoggingLevel.Warning => "warning",
525-
LoggingLevel.Error => "error",
526-
LoggingLevel.Critical => "critical",
527-
LoggingLevel.Alert => "alert",
528-
LoggingLevel.Emergency => "emergency",
529-
_ => throw new ArgumentOutOfRangeException(nameof(level))
530-
};
531-
}
532-
533517
/// <summary>Provides an AI function that calls a tool through <see cref="IMcpClient"/>.</summary>
534518
private sealed class McpAIFunction(IMcpClient client, Tool tool) : AIFunction
535519
{
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
1-
namespace ModelContextProtocol.Protocol.Types;
1+
using System.Text.Json.Serialization;
2+
3+
namespace ModelContextProtocol.Protocol.Types;
24

35
/// <summary>
46
/// A request to include context from one or more MCP servers (including the caller), to be attached to the prompt.
57
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
68
/// </summary>
9+
[JsonConverter(typeof(JsonStringEnumConverter<ContextInclusion>))]
710
public enum ContextInclusion
811
{
912
/// <summary>
1013
/// No context should be included.
1114
/// </summary>
15+
[JsonStringEnumMemberName("none")]
1216
None,
1317

1418
/// <summary>
1519
/// Include context from the server that sent the request.
1620
/// </summary>
21+
[JsonStringEnumMemberName("thisServer")]
1722
ThisServer,
1823

1924
/// <summary>
2025
/// Include context from all servers that the client is connected to.
2126
/// </summary>
27+
[JsonStringEnumMemberName("allServers")]
2228
AllServers
2329
}

src/ModelContextProtocol/Protocol/Types/LoggingLevel.cs

+9-8
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,38 @@ namespace ModelContextProtocol.Protocol.Types;
77
/// These map to syslog message severities, as specified in RFC-5424:
88
/// https://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1
99
/// </summary>
10+
[JsonConverter(typeof(JsonStringEnumConverter<LoggingLevel>))]
1011
public enum LoggingLevel
1112
{
1213
/// <summary>Detailed debug information, typically only valuable to developers.</summary>
13-
[JsonPropertyName("debug")]
14+
[JsonStringEnumMemberName("debug")]
1415
Debug,
1516

1617
/// <summary>Normal operational messages that require no action.</summary>
17-
[JsonPropertyName("info")]
18+
[JsonStringEnumMemberName("info")]
1819
Info,
1920

2021
/// <summary>Normal but significant events that might deserve attention.</summary>
21-
[JsonPropertyName("notice")]
22+
[JsonStringEnumMemberName("notice")]
2223
Notice,
2324

2425
/// <summary>Warning conditions that don't represent an error but indicate potential issues.</summary>
25-
[JsonPropertyName("warning")]
26+
[JsonStringEnumMemberName("warning")]
2627
Warning,
2728

2829
/// <summary>Error conditions that should be addressed but don't require immediate action.</summary>
29-
[JsonPropertyName("error")]
30+
[JsonStringEnumMemberName("error")]
3031
Error,
3132

3233
/// <summary>Critical conditions that require immediate attention.</summary>
33-
[JsonPropertyName("critical")]
34+
[JsonStringEnumMemberName("critical")]
3435
Critical,
3536

3637
/// <summary>Action must be taken immediately to address the condition.</summary>
37-
[JsonPropertyName("alert")]
38+
[JsonStringEnumMemberName("alert")]
3839
Alert,
3940

4041
/// <summary>System is unusable and requires immediate attention.</summary>
41-
[JsonPropertyName("emergency")]
42+
[JsonStringEnumMemberName("emergency")]
4243
Emergency
4344
}

src/ModelContextProtocol/Protocol/Types/Role.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,18 @@ namespace ModelContextProtocol.Protocol.Types;
66
/// Represents the type of role in the conversation.
77
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
88
/// </summary>
9+
[JsonConverter(typeof(JsonStringEnumConverter<Role>))]
910
public enum Role
1011
{
1112
/// <summary>
1213
/// Corresponds to the user in the conversation.
1314
/// </summary>
14-
[JsonPropertyName("user")]
15+
[JsonStringEnumMemberName("user")]
1516
User,
1617

1718
/// <summary>
1819
/// Corresponds to the AI in the conversation.
1920
/// </summary>
20-
[JsonPropertyName("assistant")]
21+
[JsonStringEnumMemberName("assistant")]
2122
Assistant
2223
}

tests/ModelContextProtocol.Tests/Protocol/ProtocolTypeTests.cs

+38
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using ModelContextProtocol.Protocol.Types;
2+
using ModelContextProtocol.Utils.Json;
23
using System.Text.Json;
34

45
namespace ModelContextProtocol.Tests.Protocol;
@@ -51,4 +52,41 @@ public static void ToolInputSchema_AcceptsValidSchemaDocuments(string validSchem
5152

5253
Assert.True(JsonElement.DeepEquals(document.RootElement, tool.InputSchema));
5354
}
55+
56+
[Theory]
57+
[InlineData(Role.User, "\"user\"")]
58+
[InlineData(Role.Assistant, "\"assistant\"")]
59+
public static void SerializeRole_ShouldBeCamelCased(Role role, string expectedValue)
60+
{
61+
var actualValue = JsonSerializer.Serialize(role);
62+
63+
Assert.Equal(expectedValue, actualValue);
64+
}
65+
66+
[Theory]
67+
[InlineData(LoggingLevel.Debug, "\"debug\"")]
68+
[InlineData(LoggingLevel.Info, "\"info\"")]
69+
[InlineData(LoggingLevel.Notice, "\"notice\"")]
70+
[InlineData(LoggingLevel.Warning, "\"warning\"")]
71+
[InlineData(LoggingLevel.Error, "\"error\"")]
72+
[InlineData(LoggingLevel.Critical, "\"critical\"")]
73+
[InlineData(LoggingLevel.Alert, "\"alert\"")]
74+
[InlineData(LoggingLevel.Emergency, "\"emergency\"")]
75+
public static void SerializeLoggingLevel_ShouldBeCamelCased(LoggingLevel level, string expectedValue)
76+
{
77+
var actualValue = JsonSerializer.Serialize(level);
78+
79+
Assert.Equal(expectedValue, actualValue);
80+
}
81+
82+
[Theory]
83+
[InlineData(ContextInclusion.None, "\"none\"")]
84+
[InlineData(ContextInclusion.ThisServer, "\"thisServer\"")]
85+
[InlineData(ContextInclusion.AllServers, "\"allServers\"")]
86+
public static void ContextInclusion_ShouldBeCamelCased(ContextInclusion level, string expectedValue)
87+
{
88+
var actualValue = JsonSerializer.Serialize(level);
89+
90+
Assert.Equal(expectedValue, actualValue);
91+
}
5492
}

0 commit comments

Comments
 (0)