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:
parent
4b38d3e71b
commit
f1af251c32
1 changed files with 632 additions and 372 deletions
|
|
@ -5,6 +5,8 @@ using ModelContextProtocol.Protocol.Types;
|
|||
using ModelContextProtocol.Server;
|
||||
using ModelContextProtocol.Tests.Utils;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace ModelContextProtocol.Tests.Server;
|
||||
|
||||
|
|
@ -171,7 +173,8 @@ public class McpServerTests : LoggedTest
|
|||
configureOptions: null,
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<PingResult>(response);
|
||||
JsonObject jObj = Assert.IsType<JsonObject>(response);
|
||||
Assert.Empty(jObj);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -184,9 +187,8 @@ public class McpServerTests : LoggedTest
|
|||
configureOptions: null,
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<InitializeResult>(response);
|
||||
|
||||
var result = (InitializeResult)response;
|
||||
var result = JsonSerializer.Deserialize<InitializeResult>(response);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("TestServer", result.ServerInfo.Name);
|
||||
Assert.Equal("1.0", result.ServerInfo.Version);
|
||||
Assert.Equal("2024", result.ProtocolVersion);
|
||||
|
|
@ -202,10 +204,8 @@ public class McpServerTests : LoggedTest
|
|||
configureOptions: null,
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<CompleteResult>(response);
|
||||
|
||||
var result = (CompleteResult)response;
|
||||
Assert.NotNull(result.Completion);
|
||||
var result = JsonSerializer.Deserialize<CompleteResult>(response);
|
||||
Assert.NotNull(result?.Completion);
|
||||
Assert.Empty(result.Completion.Values);
|
||||
Assert.Equal(0, result.Completion.Total);
|
||||
Assert.False(result.Completion.HasMore);
|
||||
|
|
@ -233,10 +233,8 @@ public class McpServerTests : LoggedTest
|
|||
},
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<CompleteResult>(response);
|
||||
|
||||
var result = (CompleteResult)response;
|
||||
Assert.NotNull(result.Completion);
|
||||
CompleteResult? result = JsonSerializer.Deserialize<CompleteResult>(response);
|
||||
Assert.NotNull(result?.Completion);
|
||||
Assert.NotEmpty(result.Completion.Values);
|
||||
Assert.Equal("test", result.Completion.Values[0]);
|
||||
Assert.Equal(2, result.Completion.Total);
|
||||
|
|
@ -273,10 +271,8 @@ public class McpServerTests : LoggedTest
|
|||
configureOptions: null,
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<ListResourceTemplatesResult>(response);
|
||||
|
||||
var result = (ListResourceTemplatesResult)response;
|
||||
Assert.NotNull(result.ResourceTemplates);
|
||||
var result = JsonSerializer.Deserialize<ListResourceTemplatesResult>(response);
|
||||
Assert.NotNull(result?.ResourceTemplates);
|
||||
Assert.NotEmpty(result.ResourceTemplates);
|
||||
Assert.Equal("test", result.ResourceTemplates[0].UriTemplate);
|
||||
});
|
||||
|
|
@ -304,10 +300,8 @@ public class McpServerTests : LoggedTest
|
|||
configureOptions: null,
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<ListResourcesResult>(response);
|
||||
|
||||
var result = (ListResourcesResult)response;
|
||||
Assert.NotNull(result.Resources);
|
||||
var result = JsonSerializer.Deserialize<ListResourcesResult>(response);
|
||||
Assert.NotNull(result?.Resources);
|
||||
Assert.NotEmpty(result.Resources);
|
||||
Assert.Equal("test", result.Resources[0].Uri);
|
||||
});
|
||||
|
|
@ -331,7 +325,7 @@ public class McpServerTests : LoggedTest
|
|||
{
|
||||
return Task.FromResult(new ReadResourceResult
|
||||
{
|
||||
Contents = [new TextResourceContents() { Text = "test" }]
|
||||
Contents = [new TextResourceContents { Text = "test" }]
|
||||
});
|
||||
},
|
||||
ListResourcesHandler = (request, ct) => throw new NotImplementedException(),
|
||||
|
|
@ -341,10 +335,8 @@ public class McpServerTests : LoggedTest
|
|||
configureOptions: null,
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<ReadResourceResult>(response);
|
||||
|
||||
var result = (ReadResourceResult)response;
|
||||
Assert.NotNull(result.Contents);
|
||||
var result = JsonSerializer.Deserialize<ReadResourceResult>(response);
|
||||
Assert.NotNull(result?.Contents);
|
||||
Assert.NotEmpty(result.Contents);
|
||||
|
||||
TextResourceContents textResource = Assert.IsType<TextResourceContents>(result.Contents[0]);
|
||||
|
|
@ -380,10 +372,8 @@ public class McpServerTests : LoggedTest
|
|||
configureOptions: null,
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<ListPromptsResult>(response);
|
||||
|
||||
var result = (ListPromptsResult)response;
|
||||
Assert.NotNull(result.Prompts);
|
||||
var result = JsonSerializer.Deserialize<ListPromptsResult>(response);
|
||||
Assert.NotNull(result?.Prompts);
|
||||
Assert.NotEmpty(result.Prompts);
|
||||
Assert.Equal("test", result.Prompts[0].Name);
|
||||
});
|
||||
|
|
@ -411,9 +401,8 @@ public class McpServerTests : LoggedTest
|
|||
configureOptions: null,
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<GetPromptResult>(response);
|
||||
|
||||
var result = (GetPromptResult)response;
|
||||
var result = JsonSerializer.Deserialize<GetPromptResult>(response);
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal("test", result.Description);
|
||||
});
|
||||
}
|
||||
|
|
@ -446,9 +435,8 @@ public class McpServerTests : LoggedTest
|
|||
configureOptions: null,
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<ListToolsResult>(response);
|
||||
|
||||
var result = (ListToolsResult)response;
|
||||
var result = JsonSerializer.Deserialize<ListToolsResult>(response);
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result.Tools);
|
||||
Assert.Equal("test", result.Tools[0].Name);
|
||||
});
|
||||
|
|
@ -482,9 +470,8 @@ public class McpServerTests : LoggedTest
|
|||
configureOptions: null,
|
||||
assertResult: response =>
|
||||
{
|
||||
Assert.IsType<CallToolResponse>(response);
|
||||
|
||||
var result = (CallToolResponse)response;
|
||||
var result = JsonSerializer.Deserialize<CallToolResponse>(response);
|
||||
Assert.NotNull(result);
|
||||
Assert.NotEmpty(result.Content);
|
||||
Assert.Equal("test", result.Content[0].Text);
|
||||
});
|
||||
|
|
@ -496,7 +483,7 @@ public class McpServerTests : LoggedTest
|
|||
await Throws_Exception_If_No_Handler_Assigned(new ServerCapabilities { Tools = new() }, RequestMethods.ToolsCall, "CallTool handler not configured");
|
||||
}
|
||||
|
||||
private async Task Can_Handle_Requests(ServerCapabilities? serverCapabilities, string method, Action<McpServerOptions>? configureOptions, Action<object> assertResult)
|
||||
private async Task Can_Handle_Requests(ServerCapabilities? serverCapabilities, string method, Action<McpServerOptions>? configureOptions, Action<JsonNode?> assertResult)
|
||||
{
|
||||
await using var transport = new TestServerTransport();
|
||||
var options = CreateOptions(serverCapabilities);
|
||||
|
|
@ -524,7 +511,6 @@ public class McpServerTests : LoggedTest
|
|||
|
||||
var response = await receivedMessage.Task.WaitAsync(TimeSpan.FromSeconds(5));
|
||||
Assert.NotNull(response);
|
||||
Assert.NotNull(response.Result);
|
||||
|
||||
assertResult(response.Result);
|
||||
|
||||
|
|
@ -610,10 +596,11 @@ public class McpServerTests : LoggedTest
|
|||
supportsSampling ? new ClientCapabilities { Sampling = new SamplingCapability() } :
|
||||
null;
|
||||
|
||||
public Task<T> SendRequestAsync<T>(JsonRpcRequest request, CancellationToken cancellationToken) where T : class
|
||||
public Task<JsonRpcResponse> SendRequestAsync(JsonRpcRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
CreateMessageRequestParams rp = Assert.IsType<CreateMessageRequestParams>(request.Params);
|
||||
CreateMessageRequestParams? rp = JsonSerializer.Deserialize<CreateMessageRequestParams>(request.Params);
|
||||
|
||||
Assert.NotNull(rp);
|
||||
Assert.Equal(0.75f, rp.Temperature);
|
||||
Assert.Equal(42, rp.MaxTokens);
|
||||
Assert.Equal(["."], rp.StopSequences);
|
||||
|
|
@ -634,7 +621,12 @@ public class McpServerTests : LoggedTest
|
|||
Role = "assistant",
|
||||
StopReason = "endTurn",
|
||||
};
|
||||
return Task.FromResult((T)(object)result);
|
||||
|
||||
return Task.FromResult(new JsonRpcResponse
|
||||
{
|
||||
Id = new RequestId("0"),
|
||||
Result = JsonSerializer.SerializeToNode(result),
|
||||
});
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync() => default;
|
||||
|
|
@ -670,7 +662,7 @@ public class McpServerTests : LoggedTest
|
|||
await transport.SendMessageAsync(new JsonRpcNotification
|
||||
{
|
||||
Method = NotificationMethods.ProgressNotification,
|
||||
Params = new ProgressNotification()
|
||||
Params = JsonSerializer.SerializeToNode(new ProgressNotification
|
||||
{
|
||||
ProgressToken = new("abc"),
|
||||
Progress = new()
|
||||
|
|
@ -679,11 +671,12 @@ public class McpServerTests : LoggedTest
|
|||
Total = 100,
|
||||
Message = "Progress message",
|
||||
},
|
||||
},
|
||||
}),
|
||||
}, TestContext.Current.CancellationToken);
|
||||
|
||||
var notification = await notificationReceived.Task;
|
||||
var progress = (ProgressNotification)notification.Params!;
|
||||
var progress = JsonSerializer.Deserialize<ProgressNotification>(notification.Params);
|
||||
Assert.NotNull(progress);
|
||||
Assert.Equal("abc", progress.ProgressToken.ToString());
|
||||
Assert.Equal(50, progress.Progress.Progress);
|
||||
Assert.Equal(100, progress.Progress.Total);
|
||||
|
|
|
|||
Loading…
Reference in a new issue