From 6ef4cce4401665778dc363b89b9b43d7ad2e209d Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Thu, 3 Apr 2025 17:54:09 +0100 Subject: [PATCH] Hardcode the source generator in one remaining location and simplify McpJsonUtilities. --- .../Transport/SseResponseStreamTransport.cs | 2 +- .../Utils/Json/McpJsonUtilities.cs | 36 ++----------------- .../McpJsonUtilitiesTests.cs | 28 +++++++++++++++ 3 files changed, 32 insertions(+), 34 deletions(-) create mode 100644 tests/ModelContextProtocol.Tests/McpJsonUtilitiesTests.cs diff --git a/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs b/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs index 359de5ea..aed3b6df 100644 --- a/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs +++ b/src/ModelContextProtocol/Protocol/Transport/SseResponseStreamTransport.cs @@ -53,7 +53,7 @@ private void WriteJsonRpcMessageToBuffer(SseItem item, IBuffer return; } - JsonSerializer.Serialize(GetUtf8JsonWriter(writer), item.Data, McpJsonUtilities.DefaultOptions.GetTypeInfo()); + JsonSerializer.Serialize(GetUtf8JsonWriter(writer), item.Data, McpJsonUtilities.JsonContext.Default.IJsonRpcMessage); } /// diff --git a/src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs b/src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs index 2ef17f28..5af25a45 100644 --- a/src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs +++ b/src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs @@ -3,7 +3,6 @@ using ModelContextProtocol.Protocol.Types; using System.Diagnostics.CodeAnalysis; using System.Text.Json; -using System.Text.Json.Nodes; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; @@ -35,36 +34,12 @@ public static partial class McpJsonUtilities /// Creates default options to use for MCP-related serialization. /// /// The configured options. - [UnconditionalSuppressMessage("AotAnalysis", "IL3050", Justification = "DefaultJsonTypeInfoResolver is only used when reflection-based serialization is enabled")] - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026", Justification = "DefaultJsonTypeInfoResolver is only used when reflection-based serialization is enabled")] private static JsonSerializerOptions CreateDefaultOptions() { - // If reflection-based serialization is enabled by default, use it, as it's the most permissive in terms of what it can serialize, - // and we want to be flexible in terms of what can be put into the various collections in the object model. - // Otherwise, use the source-generated options to enable trimming and Native AOT. - JsonSerializerOptions options; + // Copy the configuration from the source generated context. + JsonSerializerOptions options = new(JsonContext.Default.Options); - if (JsonSerializer.IsReflectionEnabledByDefault) - { - // Keep in sync with the JsonSourceGenerationOptions attribute on JsonContext below. - options = new(JsonSerializerDefaults.Web) - { - TypeInfoResolver = new DefaultJsonTypeInfoResolver(), - Converters = { new JsonStringEnumConverter() }, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - NumberHandling = JsonNumberHandling.AllowReadingFromString, - }; - } - else - { - // Keep in sync with any additional settings above beyond what's in JsonContext below. - options = new(JsonContext.Default.Options) - { - }; - } - - // Include all types from AIJsonUtilities, so that anything default usable as part of an AIFunction - // is also usable as part of an McpServerTool. + // Chain with all supported types from MEAI options.TypeInfoResolverChain.Add(AIJsonUtilities.DefaultOptions.TypeInfoResolver!); options.MakeReadOnly(); @@ -106,11 +81,6 @@ internal static bool IsValidMcpToolSchema(JsonElement element) UseStringEnumConverter = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, NumberHandling = JsonNumberHandling.AllowReadingFromString)] - - // JSON - [JsonSerializable(typeof(JsonDocument))] - [JsonSerializable(typeof(JsonElement))] - [JsonSerializable(typeof(JsonNode))] // JSON-RPC [JsonSerializable(typeof(IJsonRpcMessage))] diff --git a/tests/ModelContextProtocol.Tests/McpJsonUtilitiesTests.cs b/tests/ModelContextProtocol.Tests/McpJsonUtilitiesTests.cs new file mode 100644 index 00000000..29385fb8 --- /dev/null +++ b/tests/ModelContextProtocol.Tests/McpJsonUtilitiesTests.cs @@ -0,0 +1,28 @@ +using ModelContextProtocol.Utils.Json; +using System.Text.Json; + +namespace ModelContextProtocol.Tests; + +public static class McpJsonUtilitiesTests +{ + [Fact] + public static void DefaultOptions_IsSingleton() + { + var options = McpJsonUtilities.DefaultOptions; + + Assert.NotNull(options); + Assert.True(options.IsReadOnly); + Assert.Same(options, McpJsonUtilities.DefaultOptions); + } + + [Fact] + public static void DefaultOptions_UseReflectionWhenEnabled() + { + var options = McpJsonUtilities.DefaultOptions; + bool isReflectionEnabled = JsonSerializer.IsReflectionEnabledByDefault; + Type anonType = new { Id = 42 }.GetType(); + + Assert.True(isReflectionEnabled); // To be disabled once https://github.com/dotnet/extensions/pull/6241 is incorporated + Assert.Equal(isReflectionEnabled, options.TryGetTypeInfo(anonType, out _)); + } +}