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 <eirik.tsarpalis@gmail.com>
This commit is contained in:
Zae Chao 2025-03-24 20:51:24 +08:00 • committed by GitHub
commit 96ba2fa076
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 58 additions and 28 deletions

View file

@ -485,7 +485,7 @@ public static class McpClientExtensions
Throw.IfNull(client);
return client.SendRequestAsync<EmptyResult>(
CreateRequest("logging/setLevel", new() { ["level"] = level.ToJsonValue() }),
CreateRequest("logging/setLevel", new() { ["level"] = level }),
cancellationToken);
}
@ -514,22 +514,6 @@ public static class McpClientExtensions
return parameters;
}
private static string ToJsonValue(this LoggingLevel level)
{
return level switch
{
LoggingLevel.Debug => "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))
};
}
/// <summary>Provides an AI function that calls a tool through <see cref="IMcpClient"/>.</summary>
private sealed class McpAIFunction(IMcpClient client, Tool tool) : AIFunction
{

View file

@ -1,23 +1,29 @@
namespace ModelContextProtocol.Protocol.Types;
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol.Types;
/// <summary>
/// A request to include context from one or more MCP servers (including the caller), to be attached to the prompt.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter<ContextInclusion>))]
public enum ContextInclusion
{
/// <summary>
/// No context should be included.
/// </summary>
[JsonStringEnumMemberName("none")]
None,
/// <summary>
/// Include context from the server that sent the request.
/// </summary>
[JsonStringEnumMemberName("thisServer")]
ThisServer,
/// <summary>
/// Include context from all servers that the client is connected to.
/// </summary>
[JsonStringEnumMemberName("allServers")]
AllServers
}

View file

@ -7,37 +7,38 @@ 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
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter<LoggingLevel>))]
public enum LoggingLevel
{
/// <summary>Detailed debug information, typically only valuable to developers.</summary>
[JsonPropertyName("debug")]
[JsonStringEnumMemberName("debug")]
Debug,
/// <summary>Normal operational messages that require no action.</summary>
[JsonPropertyName("info")]
[JsonStringEnumMemberName("info")]
Info,
/// <summary>Normal but significant events that might deserve attention.</summary>
[JsonPropertyName("notice")]
[JsonStringEnumMemberName("notice")]
Notice,
/// <summary>Warning conditions that don't represent an error but indicate potential issues.</summary>
[JsonPropertyName("warning")]
[JsonStringEnumMemberName("warning")]
Warning,
/// <summary>Error conditions that should be addressed but don't require immediate action.</summary>
[JsonPropertyName("error")]
[JsonStringEnumMemberName("error")]
Error,
/// <summary>Critical conditions that require immediate attention.</summary>
[JsonPropertyName("critical")]
[JsonStringEnumMemberName("critical")]
Critical,
/// <summary>Action must be taken immediately to address the condition.</summary>
[JsonPropertyName("alert")]
[JsonStringEnumMemberName("alert")]
Alert,
/// <summary>System is unusable and requires immediate attention.</summary>
[JsonPropertyName("emergency")]
[JsonStringEnumMemberName("emergency")]
Emergency
}

View file

@ -6,17 +6,18 @@ namespace ModelContextProtocol.Protocol.Types;
/// Represents the type of role in the conversation.
/// <see href="https://github.com/modelcontextprotocol/specification/blob/main/schema/2024-11-05/schema.json">See the schema for details</see>
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter<Role>))]
public enum Role
{
/// <summary>
/// Corresponds to the user in the conversation.
/// </summary>
[JsonPropertyName("user")]
[JsonStringEnumMemberName("user")]
User,
/// <summary>
/// Corresponds to the AI in the conversation.
/// </summary>
[JsonPropertyName("assistant")]
[JsonStringEnumMemberName("assistant")]
Assistant
}

View file

@ -1,4 +1,5 @@
using ModelContextProtocol.Protocol.Types;
using ModelContextProtocol.Utils.Json;
using System.Text.Json;
namespace ModelContextProtocol.Tests.Protocol;
@ -51,4 +52,41 @@ public static class ProtocolTypeTests
Assert.True(JsonElement.DeepEquals(document.RootElement, tool.InputSchema));
}
[Theory]
[InlineData(Role.User, "\"user\"")]
[InlineData(Role.Assistant, "\"assistant\"")]
public static void SerializeRole_ShouldBeCamelCased(Role role, string expectedValue)
{
var actualValue = JsonSerializer.Serialize(role);
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_ShouldBeCamelCased(LoggingLevel level, string expectedValue)
{
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);
}
}