Skip to content

Commit 84dcb46

Browse files
Copilotstephentoub
andcommitted
Revert to ICallToolResultTyped with ToCallToolResult conversion method
Restore the previous interface design where CallToolResult<T> implements ICallToolResultTyped.ToCallToolResult(JsonSerializerOptions) with the serialization logic inside the generic type. Remove the data-only ICallToolResultTypedContent interface and ConvertCallToolResultOfT helper. Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
1 parent 6db5287 commit 84dcb46

2 files changed

Lines changed: 24 additions & 37 deletions

File tree

src/ModelContextProtocol.Core/Protocol/CallToolResultOfT.cs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Text.Json;
12
using System.Text.Json.Nodes;
23

34
namespace ModelContextProtocol.Protocol;
@@ -22,7 +23,7 @@ namespace ModelContextProtocol.Protocol;
2223
/// the SDK to handle serialization of a strongly-typed result.
2324
/// </para>
2425
/// </remarks>
25-
public sealed class CallToolResult<T> : ICallToolResultTypedContent
26+
public sealed class CallToolResult<T> : ICallToolResultTyped
2627
{
2728
/// <summary>
2829
/// Gets or sets the typed content returned by the tool.
@@ -57,15 +58,30 @@ public sealed class CallToolResult<T> : ICallToolResultTypedContent
5758
public JsonObject? Meta { get; set; }
5859

5960
/// <inheritdoc/>
60-
(object? Content, Type ContentType, bool? IsError, JsonObject? Meta) ICallToolResultTypedContent.GetContent() =>
61-
(Content, typeof(T), IsError, Meta);
61+
CallToolResult ICallToolResultTyped.ToCallToolResult(JsonSerializerOptions serializerOptions)
62+
{
63+
var typeInfo = serializerOptions.GetTypeInfo(typeof(T));
64+
65+
string json = JsonSerializer.Serialize(Content, typeInfo);
66+
JsonNode? structuredContent = JsonSerializer.SerializeToNode(Content, typeInfo);
67+
68+
return new()
69+
{
70+
Content = [new TextContentBlock { Text = json }],
71+
StructuredContent = structuredContent,
72+
IsError = IsError,
73+
Meta = Meta,
74+
};
75+
}
6276
}
6377

6478
/// <summary>
65-
/// Internal interface for accessing the content of a <see cref="CallToolResult{T}"/> without reflection.
79+
/// Internal interface for converting strongly-typed tool results to <see cref="CallToolResult"/>.
6680
/// </summary>
67-
internal interface ICallToolResultTypedContent
81+
internal interface ICallToolResultTyped
6882
{
69-
/// <summary>Gets the content, its type, the error flag, and metadata.</summary>
70-
(object? Content, Type ContentType, bool? IsError, JsonObject? Meta) GetContent();
83+
/// <summary>
84+
/// Converts the strongly-typed result to a <see cref="CallToolResult"/>.
85+
/// </summary>
86+
CallToolResult ToCallToolResult(JsonSerializerOptions serializerOptions);
7187
}

src/ModelContextProtocol.Core/Server/AIFunctionMcpServerTool.cs

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ public override async ValueTask<CallToolResult> InvokeAsync(
319319

320320
CallToolResult callToolResponse => callToolResponse,
321321

322-
_ when ConvertCallToolResultOfT(result, AIFunction.JsonSerializerOptions) is { } converted => converted,
322+
_ when result is ICallToolResultTyped typed => typed.ToCallToolResult(AIFunction.JsonSerializerOptions),
323323

324324
_ => new()
325325
{
@@ -626,33 +626,4 @@ private static CallToolResult ConvertAIContentEnumerableToCallToolResult(IEnumer
626626
IsError = allErrorContent && hasAny
627627
};
628628
}
629-
630-
/// <summary>
631-
/// If <paramref name="result"/> is a <see cref="CallToolResult{T}"/>, converts it to a <see cref="CallToolResult"/>.
632-
/// </summary>
633-
private static CallToolResult? ConvertCallToolResultOfT(object result, JsonSerializerOptions serializerOptions)
634-
{
635-
Type type = result.GetType();
636-
if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(CallToolResult<>))
637-
{
638-
return null;
639-
}
640-
641-
// Use the internal accessor to get the untyped content, IsError, and Meta
642-
// without reflection, avoiding trimming warnings.
643-
var (content, contentType, isError, meta) = ((ICallToolResultTypedContent)result).GetContent();
644-
645-
var typeInfo = serializerOptions.GetTypeInfo(contentType);
646-
647-
string json = JsonSerializer.Serialize(content, typeInfo);
648-
JsonNode? structuredContent = JsonSerializer.SerializeToNode(content, typeInfo);
649-
650-
return new()
651-
{
652-
Content = [new TextContentBlock { Text = json }],
653-
StructuredContent = structuredContent,
654-
IsError = isError,
655-
Meta = meta,
656-
};
657-
}
658629
}

0 commit comments

Comments
 (0)