Skip to content

Commit 4e290f8

Browse files
authored
Add CallToolResult.ToChatMessage extension method (#575)
To simplify non-AIFunction usage getting a ChatMessage with the appropriate FunctionResultContent.
1 parent 92fd8b2 commit 4e290f8

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

src/ModelContextProtocol.Core/AIContentExtensions.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,29 @@ public static ChatMessage ToChatMessage(this PromptMessage promptMessage)
3939
};
4040
}
4141

42+
/// <summary>
43+
/// Converts a <see cref="CallToolResult"/> to a <see cref="ChatMessage"/> object.
44+
/// </summary>
45+
/// <param name="result">The tool result to convert.</param>
46+
/// <param name="callId">The identifier for the function call request that triggered the tool invocation.</param>
47+
/// <returns>A <see cref="ChatMessage"/> object created from the tool result.</returns>
48+
/// <remarks>
49+
/// This method transforms a protocol-specific <see cref="CallToolResult"/> from the Model Context Protocol
50+
/// into a standard <see cref="ChatMessage"/> object that can be used with AI client libraries. It produces a
51+
/// <see cref="ChatRole.Tool"/> message containing a <see cref="FunctionResultContent"/> with result as a
52+
/// serialized <see cref="JsonElement"/>.
53+
/// </remarks>
54+
public static ChatMessage ToChatMessage(this CallToolResult result, string callId)
55+
{
56+
Throw.IfNull(result);
57+
Throw.IfNull(callId);
58+
59+
return new(ChatRole.Tool, [new FunctionResultContent(callId, JsonSerializer.SerializeToElement(result, McpJsonUtilities.JsonContext.Default.CallToolResult))
60+
{
61+
RawRepresentation = result,
62+
}]);
63+
}
64+
4265
/// <summary>
4366
/// Converts a <see cref="GetPromptResult"/> to a list of <see cref="ChatMessage"/> objects.
4467
/// </summary>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Microsoft.Extensions.AI;
2+
using ModelContextProtocol.Protocol;
3+
using System.Text.Json;
4+
5+
namespace ModelContextProtocol.Tests;
6+
7+
public class AIContentExtensionsTests
8+
{
9+
[Fact]
10+
public void CallToolResult_ToChatMessage_ProducesExpectedAIContent()
11+
{
12+
CallToolResult toolResult = new() { Content = [new TextContentBlock { Text = "This is a test message." }] };
13+
14+
Assert.Throws<ArgumentNullException>(() => AIContentExtensions.ToChatMessage(null!, "call123"));
15+
Assert.Throws<ArgumentNullException>(() => AIContentExtensions.ToChatMessage(toolResult, null!));
16+
17+
ChatMessage message = AIContentExtensions.ToChatMessage(toolResult, "call123");
18+
19+
Assert.NotNull(message);
20+
Assert.Equal(ChatRole.Tool, message.Role);
21+
22+
FunctionResultContent frc = Assert.IsType<FunctionResultContent>(Assert.Single(message.Contents));
23+
Assert.Same(toolResult, frc.RawRepresentation);
24+
Assert.Equal("call123", frc.CallId);
25+
JsonElement result = Assert.IsType<JsonElement>(frc.Result);
26+
Assert.Contains("This is a test message.", result.ToString());
27+
}
28+
}

0 commit comments

Comments
 (0)