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
7 changed files with 632 additions and 372 deletions

View file

@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol.Messages;
@ -23,5 +24,5 @@ public record JsonRpcNotification : IJsonRpcMessage
/// Optional parameters for the notification.
/// </summary>
[JsonPropertyName("params")]
public object? Params { get; init; }
public JsonNode? Params { get; init; }
}

View file

@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol.Messages;
@ -29,5 +30,5 @@ public record JsonRpcRequest : IJsonRpcMessageWithId
/// Optional parameters for the method.
/// </summary>
[JsonPropertyName("params")]
public object? Params { get; init; }
public JsonNode? Params { get; init; }
}

View file

@ -1,4 +1,4 @@

using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace ModelContextProtocol.Protocol.Messages;
@ -23,5 +23,5 @@ public record JsonRpcResponse : IJsonRpcMessageWithId
/// The result of the method invocation.
/// </summary>
[JsonPropertyName("result")]
public required object? Result { get; init; }
public required JsonNode? Result { get; init; }
}

View file

@ -24,7 +24,6 @@ internal sealed class SseClientSessionTransport : TransportBase
private Task? _receiveTask;
private readonly ILogger _logger;
private readonly McpServerConfig _serverConfig;
private readonly JsonSerializerOptions _jsonOptions;
private readonly TaskCompletionSource<bool> _connectionEstablished;
private string EndpointName => $"Client (SSE) for ({_serverConfig.Id}: {_serverConfig.Name})";
@ -50,7 +49,6 @@ internal sealed class SseClientSessionTransport : TransportBase
_httpClient = httpClient;
_connectionCts = new CancellationTokenSource();
_logger = (ILogger?)loggerFactory?.CreateLogger<SseClientTransport>() ?? NullLogger.Instance;
_jsonOptions = McpJsonUtilities.DefaultOptions;
_connectionEstablished = new TaskCompletionSource<bool>();
}
@ -94,7 +92,7 @@ internal sealed class SseClientSessionTransport : TransportBase
throw new InvalidOperationException("Transport not connected");
using var content = new StringContent(
JsonSerializer.Serialize(message, _jsonOptions.GetTypeInfo<IJsonRpcMessage>()),
JsonSerializer.Serialize(message, McpJsonUtilities.JsonContext.Default.IJsonRpcMessage),
Encoding.UTF8,
"application/json"
);
@ -127,7 +125,7 @@ internal sealed class SseClientSessionTransport : TransportBase
}
else
{
JsonRpcResponse initializeResponse = JsonSerializer.Deserialize(responseContent, _jsonOptions.GetTypeInfo<JsonRpcResponse>()) ??
JsonRpcResponse initializeResponse = JsonSerializer.Deserialize(responseContent, McpJsonUtilities.JsonContext.Default.JsonRpcResponse) ??
throw new McpTransportException("Failed to initialize client");
_logger.TransportReceivedMessageParsed(EndpointName, messageId);
@ -259,7 +257,7 @@ internal sealed class SseClientSessionTransport : TransportBase
try
{
var message = JsonSerializer.Deserialize(data, _jsonOptions.GetTypeInfo<IJsonRpcMessage>());
var message = JsonSerializer.Deserialize(data, McpJsonUtilities.JsonContext.Default.IJsonRpcMessage);
if (message == null)
{
_logger.TransportMessageParseUnexpectedType(EndpointName, data);

View file

@ -1,4 +1,6 @@
namespace ModelContextProtocol.Protocol.Types;
using System.Text.Json;
namespace ModelContextProtocol.Protocol.Types;
/// <summary>
/// Used by the client to invoke a tool provided by the server.
@ -16,5 +18,5 @@ public class CallToolRequestParams : RequestParams
/// Optional arguments to pass to the tool.
/// </summary>
[System.Text.Json.Serialization.JsonPropertyName("arguments")]
public Dictionary<string,object>? Arguments { get; init; }
public Dictionary<string, JsonElement>? Arguments { get; init; }
}

View file

@ -24,7 +24,7 @@ public class LoggingMessageNotificationParams
public string? Logger { get; init; }
/// <summary>
/// The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here.
/// The data to be logged, such as a string message or an object.
/// </summary>
[JsonPropertyName("data")]
public JsonElement? Data { get; init; }

View file

@ -61,6 +61,8 @@ public abstract class ResourceContents
}
string? propertyName = reader.GetString();
bool success = reader.Read();
Debug.Assert(success, "STJ must have buffered the entire object for us.");
switch (propertyName)
{