|
11 | 11 | import pytest |
12 | 12 | from dirty_equals import IsPartialDict |
13 | 13 | from mcp_types import CallToolResult, ContentBlock, EmbeddedResource, InputRequiredResult, TextContent |
14 | | -from pydantic import BaseModel, Field, ValidationError |
| 14 | +from pydantic import BaseModel, ConfigDict, Field, ValidationError |
15 | 15 | from typing_extensions import NotRequired, ReadOnly, Required |
16 | 16 |
|
17 | 17 | from mcp import MCPDeprecationWarning |
@@ -1322,6 +1322,34 @@ def func_with_aliases() -> ModelWithAliases: # pragma: no cover |
1322 | 1322 | assert structured_content_defaults["second"] is None |
1323 | 1323 |
|
1324 | 1324 |
|
| 1325 | +def test_call_tool_result_structured_content_alias_normalized(): |
| 1326 | + """CallToolResult.structured_content must be alias-normalized like plain returns.""" |
| 1327 | + |
| 1328 | + class ModelWithAliases(BaseModel): |
| 1329 | + model_config = ConfigDict(populate_by_name=True) |
| 1330 | + field_first: str | None = Field(default=None, alias="first") |
| 1331 | + field_second: str | None = Field(default=None, alias="second") |
| 1332 | + |
| 1333 | + def via_call_tool_result() -> Annotated[CallToolResult, ModelWithAliases]: |
| 1334 | + return CallToolResult( |
| 1335 | + content=[], |
| 1336 | + structured_content={"field_first": "hello", "field_second": "world"}, |
| 1337 | + ) |
| 1338 | + |
| 1339 | + meta = func_metadata(via_call_tool_result) |
| 1340 | + assert meta.output_schema is not None |
| 1341 | + assert "first" in meta.output_schema["properties"] |
| 1342 | + assert "field_first" not in meta.output_schema["properties"] |
| 1343 | + |
| 1344 | + converted = meta.convert_result(via_call_tool_result()) |
| 1345 | + assert isinstance(converted, CallToolResult) |
| 1346 | + structured_content = converted.structured_content |
| 1347 | + assert structured_content is not None |
| 1348 | + assert structured_content == {"first": "hello", "second": "world"} |
| 1349 | + assert "field_first" not in structured_content |
| 1350 | + assert "field_second" not in structured_content |
| 1351 | + |
| 1352 | + |
1325 | 1353 | def test_basemodel_reserved_names(): |
1326 | 1354 | """Test that functions with parameters named after BaseModel methods work correctly""" |
1327 | 1355 |
|
|
0 commit comments