Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/ModelContextProtocol.Core/AIContentExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,29 @@ public static ChatMessage ToChatMessage(this PromptMessage promptMessage)
};
}

/// <summary>
/// Converts a <see cref="CallToolResult"/> to a <see cref="ChatMessage"/> object.
/// </summary>
/// <param name="result">The tool result to convert.</param>
/// <param name="callId">The identifier for the function call request that triggered the tool invocation.</param>
/// <returns>A <see cref="ChatMessage"/> object created from the tool result.</returns>
/// <remarks>
/// This method transforms a protocol-specific <see cref="CallToolResult"/> from the Model Context Protocol
/// into a standard <see cref="ChatMessage"/> object that can be used with AI client libraries. It produces a
/// <see cref="ChatRole.Tool"/> message containing a <see cref="FunctionResultContent"/> with result as a
/// serialized <see cref="JsonElement"/>.
/// </remarks>
public static ChatMessage ToChatMessage(this CallToolResult result, string callId)
{
Throw.IfNull(result);
Throw.IfNull(callId);

return new(ChatRole.Tool, [new FunctionResultContent(callId, JsonSerializer.SerializeToElement(result, McpJsonUtilities.JsonContext.Default.CallToolResult))
{
RawRepresentation = result,
}]);
}

/// <summary>
/// Converts a <see cref="GetPromptResult"/> to a list of <see cref="ChatMessage"/> objects.
/// </summary>
Expand Down
28 changes: 28 additions & 0 deletions tests/ModelContextProtocol.Tests/AIContentExtensionsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Microsoft.Extensions.AI;
using ModelContextProtocol.Protocol;
using System.Text.Json;

namespace ModelContextProtocol.Tests;

public class AIContentExtensionsTests
{
[Fact]
public void CallToolResult_ToChatMessage_ProducesExpectedAIContent()
{
CallToolResult toolResult = new() { Content = [new TextContentBlock { Text = "This is a test message." }] };

Assert.Throws<ArgumentNullException>(() => AIContentExtensions.ToChatMessage(null!, "call123"));
Assert.Throws<ArgumentNullException>(() => AIContentExtensions.ToChatMessage(toolResult, null!));

ChatMessage message = AIContentExtensions.ToChatMessage(toolResult, "call123");

Assert.NotNull(message);
Assert.Equal(ChatRole.Tool, message.Role);

FunctionResultContent frc = Assert.IsType<FunctionResultContent>(Assert.Single(message.Contents));
Assert.Same(toolResult, frc.RawRepresentation);
Assert.Equal("call123", frc.CallId);
JsonElement result = Assert.IsType<JsonElement>(frc.Result);
Assert.Contains("This is a test message.", result.ToString());
}
}