Hardcode the source generator in one remaining location and simplify McpJsonUtilities. (#204)

This commit is contained in:
Eirik Tsarpalis 2025-04-03 18:42:42 +01:00 • committed by GitHub
commit 1c145a5d52
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 32 additions and 34 deletions

View file

@ -53,7 +53,7 @@ public sealed class SseResponseStreamTransport(Stream sseResponseStream, string
return;
}
JsonSerializer.Serialize(GetUtf8JsonWriter(writer), item.Data, McpJsonUtilities.DefaultOptions.GetTypeInfo<IJsonRpcMessage?>());
JsonSerializer.Serialize(GetUtf8JsonWriter(writer), item.Data, McpJsonUtilities.JsonContext.Default.IJsonRpcMessage);
}
/// <inheritdoc/>

View file

@ -3,7 +3,6 @@ using ModelContextProtocol.Protocol.Messages;
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.
/// </summary>
/// <returns>The configured options.</returns>
[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 @@ public static partial class McpJsonUtilities
UseStringEnumConverter = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
NumberHandling = JsonNumberHandling.AllowReadingFromString)]
// JSON
[JsonSerializable(typeof(JsonDocument))]
[JsonSerializable(typeof(JsonElement))]
[JsonSerializable(typeof(JsonNode))]
// JSON-RPC
[JsonSerializable(typeof(IJsonRpcMessage))]

View file

@ -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 _));
}
}