Skip to content

Commit cb95813

Browse files
Copilotstephentoub
andcommitted
Add tests for anonymous types in CallToolAsync and ToChatMessage
- Added test for CallToolAsync with anonymous type arguments - Added test for ToChatMessage with anonymous types in ContentBlock.Meta - Added ArgumentEchoTool to McpClientToolTests to support testing - Tests verify that anonymous types work correctly when reflection is enabled - All tests pass, indicating AIJsonUtilities resolver chain handles anonymous types The tests demonstrate that user-defined types in dictionaries are properly serialized through the existing resolver chain that includes AIJsonUtilities.DefaultOptions. Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
1 parent 32f2549 commit cb95813

2 files changed

Lines changed: 63 additions & 0 deletions

File tree

tests/ModelContextProtocol.Tests/AIContentExtensionsTests.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,33 @@ public void ToContentBlock_WithNamedUserDefinedTypeInAdditionalProperties_Works(
375375
Assert.Contains("1", json);
376376
Assert.Contains("2", json);
377377
}
378+
379+
[Fact]
380+
public void ToChatMessage_CallToolResult_WithAnonymousTypeInContent_Works()
381+
{
382+
if (!JsonSerializer.IsReflectionEnabledByDefault)
383+
{
384+
return;
385+
}
386+
387+
// Create a CallToolResult with anonymous type data in the content
388+
var result = new CallToolResult
389+
{
390+
Content = new List<ContentBlock>
391+
{
392+
new TextContentBlock
393+
{
394+
Text = "Result with metadata",
395+
Meta = JsonSerializer.SerializeToNode(new { Status = "success", Code = 200 }) as System.Text.Json.Nodes.JsonObject
396+
}
397+
}
398+
};
399+
400+
// This should not throw NotSupportedException
401+
var exception = Record.Exception(() => result.ToChatMessage("call_123"));
402+
403+
Assert.Null(exception);
404+
}
378405
}
379406

380407
// Test type for named user-defined type test

tests/ModelContextProtocol.Tests/Client/McpClientToolTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,14 @@ public static TextContentBlock MetadataEchoTool(RequestContext<CallToolRequestPa
165165
var metaJson = meta?.ToJsonString() ?? "{}";
166166
return new TextContentBlock { Text = metaJson };
167167
}
168+
169+
// Tool that accepts arbitrary JsonElement parameter to test anonymous type serialization
170+
[McpServerTool]
171+
public static TextContentBlock ArgumentEchoTool(string text, JsonElement coordinates)
172+
{
173+
var result = new { text, coordinates };
174+
return new TextContentBlock { Text = JsonSerializer.Serialize(result) };
175+
}
168176
}
169177

170178
[Fact]
@@ -818,4 +826,32 @@ public async Task CallAsync_WithOnlyRequestOptionsMeta_NoWithMeta_WorksCorrectly
818826
Assert.NotNull(receivedMetadata);
819827
Assert.Equal("requestOnlyValue", receivedMetadata["requestOnlyKey"]?.GetValue<string>());
820828
}
829+
830+
[Fact]
831+
public async Task CallToolAsync_WithAnonymousTypeArguments_Works()
832+
{
833+
if (!JsonSerializer.IsReflectionEnabledByDefault)
834+
{
835+
return;
836+
}
837+
838+
await using McpClient client = await CreateMcpClientForServer();
839+
840+
// Call with dictionary containing anonymous type values
841+
var arguments = new Dictionary<string, object?>
842+
{
843+
["text"] = "test",
844+
["coordinates"] = new { X = 1.0, Y = 2.0 } // Anonymous type
845+
};
846+
847+
// This should not throw NotSupportedException
848+
var result = await client.CallToolAsync("argument_echo_tool", arguments, cancellationToken: TestContext.Current.CancellationToken);
849+
850+
Assert.NotNull(result);
851+
Assert.NotEmpty(result.Content);
852+
853+
// Verify the anonymous type was serialized correctly
854+
var textBlock = Assert.IsType<TextContentBlock>(result.Content[0]);
855+
Assert.Contains("coordinates", textBlock.Text);
856+
}
821857
}

0 commit comments

Comments
 (0)