diff --git a/src/ModelContextProtocol/Configuration/McpServerBuilderExtensions.cs b/src/ModelContextProtocol/Configuration/McpServerBuilderExtensions.cs index ebc776bc3..d685cc474 100644 --- a/src/ModelContextProtocol/Configuration/McpServerBuilderExtensions.cs +++ b/src/ModelContextProtocol/Configuration/McpServerBuilderExtensions.cs @@ -8,6 +8,7 @@ using ModelContextProtocol.Utils; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Text.Json; namespace Microsoft.Extensions.DependencyInjection; @@ -24,6 +25,7 @@ public static partial class McpServerBuilderExtensions /// Adds instances to the service collection backing . /// The tool type. /// The builder instance. + /// The serializer options governing tool parameter marshalling. /// The builder provided in . /// is . /// @@ -35,7 +37,8 @@ public static partial class McpServerBuilderExtensions DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods | DynamicallyAccessedMemberTypes.PublicConstructors)] TToolType>( - this IMcpServerBuilder builder) + this IMcpServerBuilder builder, + JsonSerializerOptions? serializerOptions = null) { Throw.IfNull(builder); @@ -44,8 +47,8 @@ public static partial class McpServerBuilderExtensions if (toolMethod.GetCustomAttribute() is not null) { builder.Services.AddSingleton((Func)(toolMethod.IsStatic ? - services => McpServerTool.Create(toolMethod, options: new() { Services = services }) : - services => McpServerTool.Create(toolMethod, typeof(TToolType), new() { Services = services }))); + services => McpServerTool.Create(toolMethod, options: new() { Services = services, SerializerOptions = serializerOptions }) : + services => McpServerTool.Create(toolMethod, typeof(TToolType), new() { Services = services, SerializerOptions = serializerOptions }))); } } @@ -55,6 +58,7 @@ public static partial class McpServerBuilderExtensions /// Adds instances to the service collection backing . /// The builder instance. /// Types with marked methods to add as tools to the server. + /// The serializer options governing tool parameter marshalling. /// The builder provided in . /// is . /// is . @@ -64,7 +68,7 @@ public static partial class McpServerBuilderExtensions /// instance for each. For instance methods, an instance will be constructed for each invocation of the tool. /// [RequiresUnreferencedCode(WithToolsRequiresUnreferencedCodeMessage)] - public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, params IEnumerable toolTypes) + public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, IEnumerable toolTypes, JsonSerializerOptions? serializerOptions = null) { Throw.IfNull(builder); Throw.IfNull(toolTypes); @@ -78,8 +82,8 @@ public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, params if (toolMethod.GetCustomAttribute() is not null) { builder.Services.AddSingleton((Func)(toolMethod.IsStatic ? - services => McpServerTool.Create(toolMethod, options: new() { Services = services }) : - services => McpServerTool.Create(toolMethod, toolType, new() { Services = services }))); + services => McpServerTool.Create(toolMethod, options: new() { Services = services , SerializerOptions = serializerOptions }) : + services => McpServerTool.Create(toolMethod, toolType, new() { Services = services , SerializerOptions = serializerOptions }))); } } } @@ -92,6 +96,7 @@ public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, params /// Adds types marked with the attribute from the given assembly as tools to the server. /// /// The builder instance. + /// The serializer options governing tool parameter marshalling. /// The assembly to load the types from. If , the calling assembly will be used. /// The builder provided in . /// is . @@ -116,7 +121,7 @@ public static IMcpServerBuilder WithTools(this IMcpServerBuilder builder, params /// /// [RequiresUnreferencedCode(WithToolsRequiresUnreferencedCodeMessage)] - public static IMcpServerBuilder WithToolsFromAssembly(this IMcpServerBuilder builder, Assembly? toolAssembly = null) + public static IMcpServerBuilder WithToolsFromAssembly(this IMcpServerBuilder builder, Assembly? toolAssembly = null, JsonSerializerOptions? serializerOptions = null) { Throw.IfNull(builder); @@ -125,7 +130,8 @@ public static IMcpServerBuilder WithToolsFromAssembly(this IMcpServerBuilder bui return builder.WithTools( from t in toolAssembly.GetTypes() where t.GetCustomAttribute() is not null - select t); + select t, + serializerOptions); } #endregion diff --git a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs index 5e4b1e16e..abb5a197b 100644 --- a/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs +++ b/src/ModelContextProtocol/Server/AIFunctionMcpServerTool.cs @@ -67,6 +67,7 @@ private static AIFunctionFactoryOptions CreateAIFunctionFactoryOptions( Name = options?.Name ?? method.GetCustomAttribute()?.Name, Description = options?.Description, MarshalResult = static (result, _, cancellationToken) => new ValueTask(result), + SerializerOptions = options?.SerializerOptions ?? McpJsonUtilities.DefaultOptions, ConfigureParameterBinding = pi => { if (pi.ParameterType == typeof(RequestContext)) @@ -314,7 +315,7 @@ public override async Task InvokeAsync( { Content = [new() { - Text = JsonSerializer.Serialize(result, McpJsonUtilities.DefaultOptions.GetTypeInfo(typeof(object))), + Text = JsonSerializer.Serialize(result, AIFunction.JsonSerializerOptions.GetTypeInfo(typeof(object))), Type = "text" }] }, diff --git a/src/ModelContextProtocol/Server/McpServerToolCreateOptions.cs b/src/ModelContextProtocol/Server/McpServerToolCreateOptions.cs index f6567d4e0..ed7a49f10 100644 --- a/src/ModelContextProtocol/Server/McpServerToolCreateOptions.cs +++ b/src/ModelContextProtocol/Server/McpServerToolCreateOptions.cs @@ -1,4 +1,6 @@ +using ModelContextProtocol.Utils.Json; using System.ComponentModel; +using System.Text.Json; namespace ModelContextProtocol.Server; @@ -122,11 +124,19 @@ public sealed class McpServerToolCreateOptions /// public bool? ReadOnly { get; set; } + /// + /// Gets or sets the JSON serializer options to use when marshalling data to/from JSON. + /// + /// + /// Defaults to if left unspecified. + /// + public JsonSerializerOptions? SerializerOptions { get; set; } + /// /// Creates a shallow clone of the current instance. /// internal McpServerToolCreateOptions Clone() => - new McpServerToolCreateOptions() + new McpServerToolCreateOptions { Services = Services, Name = Name, @@ -135,6 +145,7 @@ internal McpServerToolCreateOptions Clone() => Destructive = Destructive, Idempotent = Idempotent, OpenWorld = OpenWorld, - ReadOnly = ReadOnly + ReadOnly = ReadOnly, + SerializerOptions = SerializerOptions, }; } diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/ModelContextProtocol.AspNetCore.Tests.csproj b/tests/ModelContextProtocol.AspNetCore.Tests/ModelContextProtocol.AspNetCore.Tests.csproj index 5e0e028b3..9d7246bf5 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/ModelContextProtocol.AspNetCore.Tests.csproj +++ b/tests/ModelContextProtocol.AspNetCore.Tests/ModelContextProtocol.AspNetCore.Tests.csproj @@ -10,6 +10,11 @@ ModelContextProtocol.AspNetCore.Tests + + + false + + + false + +