diff --git a/src/ModelContextProtocol.Core/Protocol/CallToolResult.cs b/src/ModelContextProtocol.Core/Protocol/CallToolResult.cs index cd4c1abe3..35dba5b6e 100644 --- a/src/ModelContextProtocol.Core/Protocol/CallToolResult.cs +++ b/src/ModelContextProtocol.Core/Protocol/CallToolResult.cs @@ -1,5 +1,5 @@ using System.Diagnostics.CodeAnalysis; -using System.Text.Json.Nodes; +using System.Text.Json; using System.Text.Json.Serialization; namespace ModelContextProtocol.Protocol; @@ -41,7 +41,7 @@ public sealed class CallToolResult : Result /// Gets or sets an optional JSON object representing the structured result of the tool call. /// [JsonPropertyName("structuredContent")] - public JsonNode? StructuredContent { get; set; } + public JsonElement? StructuredContent { get; set; } /// /// Gets or sets a value that indicates whether the tool call was unsuccessful. diff --git a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs index f29d8fef1..e91bdd206 100644 --- a/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs +++ b/src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs @@ -266,7 +266,7 @@ public override async ValueTask InvokeAsync( object? result; result = await AIFunction.InvokeAsync(arguments, cancellationToken).ConfigureAwait(false); - JsonNode? structuredContent = CreateStructuredResponse(result); + JsonElement? structuredContent = CreateStructuredResponse(result); return result switch { AIContent aiContent => new() @@ -529,7 +529,7 @@ typeProperty.ValueKind is not JsonValueKind.String || return outputSchema; } - private JsonNode? CreateStructuredResponse(object? aiFunctionResult) + private JsonElement? CreateStructuredResponse(object? aiFunctionResult) { if (ProtocolTool.OutputSchema is null) { @@ -537,25 +537,29 @@ typeProperty.ValueKind is not JsonValueKind.String || return null; } - JsonNode? nodeResult = aiFunctionResult switch + JsonElement? elementResult = aiFunctionResult switch { - JsonNode node => node, - JsonElement jsonElement => JsonSerializer.SerializeToNode(jsonElement, McpJsonUtilities.JsonContext.Default.JsonElement), - _ => JsonSerializer.SerializeToNode(aiFunctionResult, AIFunction.JsonSerializerOptions.GetTypeInfo(typeof(object))), + JsonElement jsonElement => jsonElement, + JsonNode node => JsonSerializer.SerializeToElement(node, McpJsonUtilities.JsonContext.Default.JsonNode), + null => null, + _ => JsonSerializer.SerializeToElement(aiFunctionResult, AIFunction.JsonSerializerOptions.GetTypeInfo(typeof(object))), }; if (_structuredOutputRequiresWrapping) { - return new JsonObject + JsonNode? resultNode = elementResult is { } je + ? JsonSerializer.SerializeToNode(je, McpJsonUtilities.JsonContext.Default.JsonElement) + : null; + return JsonSerializer.SerializeToElement(new JsonObject { - ["result"] = nodeResult - }; + ["result"] = resultNode + }, McpJsonUtilities.JsonContext.Default.JsonObject); } - return nodeResult; + return elementResult; } - private static CallToolResult ConvertAIContentEnumerableToCallToolResult(IEnumerable contentItems, JsonNode? structuredContent) + private static CallToolResult ConvertAIContentEnumerableToCallToolResult(IEnumerable contentItems, JsonElement? structuredContent) { List contentList = []; bool allErrorContent = true; diff --git a/tests/ModelContextProtocol.Tests/Client/McpClientToolTests.cs b/tests/ModelContextProtocol.Tests/Client/McpClientToolTests.cs index f6818fd4f..e17fb6bc9 100644 --- a/tests/ModelContextProtocol.Tests/Client/McpClientToolTests.cs +++ b/tests/ModelContextProtocol.Tests/Client/McpClientToolTests.cs @@ -122,7 +122,7 @@ public static CallToolResult StructuredContentTool() => new() { Content = [new TextContentBlock { Text = "Regular content" }], - StructuredContent = JsonNode.Parse("{\"key\":\"value\"}") + StructuredContent = JsonElement.Parse("{\"key\":\"value\"}") }; // Tool that returns CallToolResult with Meta diff --git a/tests/ModelContextProtocol.Tests/Protocol/CallToolResultTests.cs b/tests/ModelContextProtocol.Tests/Protocol/CallToolResultTests.cs index 29ecbcb8e..d66e03b3f 100644 --- a/tests/ModelContextProtocol.Tests/Protocol/CallToolResultTests.cs +++ b/tests/ModelContextProtocol.Tests/Protocol/CallToolResultTests.cs @@ -12,7 +12,7 @@ public static void CallToolResult_SerializationRoundTrip_PreservesAllProperties( var original = new CallToolResult { Content = [new TextContentBlock { Text = "Result text" }], - StructuredContent = JsonNode.Parse("""{"temperature":72}"""), + StructuredContent = JsonElement.Parse("""{"temperature":72}"""), IsError = false, Task = new McpTask { @@ -32,7 +32,7 @@ public static void CallToolResult_SerializationRoundTrip_PreservesAllProperties( var textBlock = Assert.IsType(deserialized.Content[0]); Assert.Equal("Result text", textBlock.Text); Assert.NotNull(deserialized.StructuredContent); - Assert.Equal(72, deserialized.StructuredContent["temperature"]!.GetValue()); + Assert.Equal(72, deserialized.StructuredContent.Value.GetProperty("temperature").GetInt32()); Assert.False(deserialized.IsError); Assert.NotNull(deserialized.Task); Assert.Equal("task-1", deserialized.Task.TaskId); diff --git a/tests/ModelContextProtocol.Tests/Protocol/UnknownPropertiesTests.cs b/tests/ModelContextProtocol.Tests/Protocol/UnknownPropertiesTests.cs index 1501553d3..05c25b523 100644 --- a/tests/ModelContextProtocol.Tests/Protocol/UnknownPropertiesTests.cs +++ b/tests/ModelContextProtocol.Tests/Protocol/UnknownPropertiesTests.cs @@ -252,7 +252,7 @@ public void CallToolResult_WithStructuredContentAtCorrectLevel_PreservesProperty // Assert Assert.NotNull(deserialized); Assert.NotNull(deserialized.StructuredContent); - Assert.Equal("correctly placed here", deserialized.StructuredContent["result"]?.ToString()); - Assert.Equal(42, (int?)deserialized.StructuredContent["value"]); + Assert.Equal("correctly placed here", deserialized.StructuredContent.Value.GetProperty("result").GetString()); + Assert.Equal(42, deserialized.StructuredContent.Value.GetProperty("value").GetInt32()); } } diff --git a/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs b/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs index 552eaed72..fd62a05c7 100644 --- a/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs +++ b/tests/ModelContextProtocol.Tests/Server/McpServerToolTests.cs @@ -654,11 +654,11 @@ public object InstanceMethod() } } - private static void AssertMatchesJsonSchema(JsonElement schemaDoc, JsonNode? value) + private static void AssertMatchesJsonSchema(JsonElement schemaDoc, JsonElement? value) { JsonSchema schema = JsonSerializer.Deserialize(schemaDoc, JsonContext2.Default.JsonSchema)!; EvaluationOptions options = new() { OutputFormat = OutputFormat.List }; - EvaluationResults results = schema.Evaluate(JsonSerializer.SerializeToElement(value, JsonContext2.Default.JsonNode), options); + EvaluationResults results = schema.Evaluate(value!.Value, options); if (!results.IsValid) { IEnumerable errors = (results.Details ?? []) @@ -670,7 +670,7 @@ Instance JSON document does not match the specified schema. Schema: {JsonSerializer.Serialize(schema)} Instance: - {value?.ToJsonString() ?? "null"} + {value?.ToString() ?? "null"} Errors: {string.Join(Environment.NewLine, errors)} """);