Allow JsonSerializerOptions parameters for user-defined and inputs and hardcode everything else to the source generator. (#182)

* Allow user-defined JsonSerializerOptions for user-defined and inputs and hardcode everything else to the source generator.

* Add validation for user-defined JsonSerializerOptions.

* Remove out of date comment.

* Address feedback and add tests
This commit is contained in:
Eirik Tsarpalis 2025-04-02 18:43:54 +01:00 • committed by GitHub
commit f1af251c32
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,11 +1,12 @@
using ModelContextProtocol.Protocol.Messages;
using ModelContextProtocol.Utils;
using ModelContextProtocol.Utils.Json;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization.Metadata;
namespace ModelContextProtocol.Shared;
internal sealed class RequestHandlers : Dictionary<string, Func<JsonRpcRequest, CancellationToken, Task<object?>>>
internal sealed class RequestHandlers : Dictionary<string, Func<JsonRpcRequest, CancellationToken, Task<JsonNode?>>>
{
/// <summary>
/// Registers a handler for incoming requests of a specific method.
@ -14,18 +15,24 @@ internal sealed class RequestHandlers : Dictionary<string, Func<JsonRpcRequest,
/// <typeparam name="TResponse">Type of response payload (not full RPC response</typeparam>
/// <param name="method">Method identifier to register for</param>
/// <param name="handler">Handler to be called when a request with specified method identifier is received</param>
public void Set<TRequest, TResponse>(string method, Func<TRequest?, CancellationToken, Task<TResponse>> handler)
/// <param name="requestTypeInfo">The JSON contract governing request serialization.</param>
/// <param name="responseTypeInfo">The JSON contract governing response serialization.</param>
public void Set<TRequest, TResponse>(
string method,
Func<TRequest?, CancellationToken, Task<TResponse>> handler,
JsonTypeInfo<TRequest> requestTypeInfo,
JsonTypeInfo<TResponse> responseTypeInfo)
{
Throw.IfNull(method);
Throw.IfNull(handler);
Throw.IfNull(requestTypeInfo);
Throw.IfNull(responseTypeInfo);
this[method] = async (request, cancellationToken) =>
{
// Convert the params JsonElement to our type using the same options
var jsonString = JsonSerializer.Serialize(request.Params, McpJsonUtilities.DefaultOptions.GetTypeInfo<object?>());
var typedRequest = JsonSerializer.Deserialize(jsonString, McpJsonUtilities.DefaultOptions.GetTypeInfo<TRequest>());
return await handler(typedRequest, cancellationToken).ConfigureAwait(false);
TRequest? typedRequest = JsonSerializer.Deserialize(request.Params, requestTypeInfo);
object? result = await handler(typedRequest, cancellationToken).ConfigureAwait(false);
return JsonSerializer.SerializeToNode(result, responseTypeInfo);
};
}
}