Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ private void WriteJsonRpcMessageToBuffer(SseItem<IJsonRpcMessage?> item, IBuffer
return;
}

JsonSerializer.Serialize(GetUtf8JsonWriter(writer), item.Data, McpJsonUtilities.DefaultOptions.GetTypeInfo<IJsonRpcMessage?>());
JsonSerializer.Serialize(GetUtf8JsonWriter(writer), item.Data, McpJsonUtilities.JsonContext.Default.IJsonRpcMessage);
}

/// <inheritdoc/>
Expand Down
36 changes: 3 additions & 33 deletions src/ModelContextProtocol/Utils/Json/McpJsonUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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))]
Expand Down
28 changes: 28 additions & 0 deletions tests/ModelContextProtocol.Tests/McpJsonUtilitiesTests.cs
Original file line number Diff line number Diff line change
@@ -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 _));
}
}