Skip to content

Commit bcbf1b3

Browse files
authored
Python: Preserve MCP array items schema in Pydantic field generation (#2382)
* mcp tool parameter fix * small fixes
1 parent 9f43108 commit bcbf1b3

File tree

2 files changed

+50
-8
lines changed

2 files changed

+50
-8
lines changed

python/packages/core/agent_framework/_mcp.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -278,18 +278,30 @@ def resolve_type(prop_details: dict[str, Any]) -> type:
278278
python_type = resolve_type(prop_details)
279279
description = prop_details.get("description", "")
280280

281+
# Build field kwargs (description, array items schema, etc.)
282+
field_kwargs: dict[str, Any] = {}
283+
if description:
284+
field_kwargs["description"] = description
285+
286+
# Preserve array items schema if present
287+
if prop_details.get("type") == "array" and "items" in prop_details:
288+
items_schema = prop_details["items"]
289+
if items_schema and items_schema != {}:
290+
field_kwargs["json_schema_extra"] = {"items": items_schema}
291+
281292
# Create field definition for create_model
282293
if prop_name in required:
283-
field_definitions[prop_name] = (
284-
(python_type, Field(description=description)) if description else (python_type, ...)
285-
)
294+
if field_kwargs:
295+
field_definitions[prop_name] = (python_type, Field(**field_kwargs))
296+
else:
297+
field_definitions[prop_name] = (python_type, ...)
286298
else:
287299
default_value = prop_details.get("default", None)
288-
field_definitions[prop_name] = (
289-
(python_type, Field(default=default_value, description=description))
290-
if description
291-
else (python_type, default_value)
292-
)
300+
field_kwargs["default"] = default_value
301+
if field_kwargs and any(k != "default" for k in field_kwargs):
302+
field_definitions[prop_name] = (python_type, Field(**field_kwargs))
303+
else:
304+
field_definitions[prop_name] = (python_type, default_value)
293305

294306
return create_model(f"{tool.name}_input", **field_definitions)
295307

python/packages/core/tests/core/test_mcp.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,36 @@ def test_get_input_model_from_mcp_tool_with_ref_schema():
483483
assert dumped == {"params": {"customer_id": 251}}
484484

485485

486+
def test_get_input_model_from_mcp_tool_with_simple_array():
487+
"""Test array with simple items schema (items schema should be preserved in json_schema_extra)."""
488+
tool = types.Tool(
489+
name="simple_array_tool",
490+
description="Tool with simple array",
491+
inputSchema={
492+
"type": "object",
493+
"properties": {
494+
"tags": {
495+
"type": "array",
496+
"description": "List of tags",
497+
"items": {"type": "string"}, # Simple string array
498+
}
499+
},
500+
"required": ["tags"],
501+
},
502+
)
503+
model = _get_input_model_from_mcp_tool(tool)
504+
505+
# Create an instance
506+
instance = model(tags=["tag1", "tag2", "tag3"])
507+
assert instance.tags == ["tag1", "tag2", "tag3"]
508+
509+
# Verify JSON schema still preserves items for simple types
510+
json_schema = model.model_json_schema()
511+
tags_property = json_schema["properties"]["tags"]
512+
assert "items" in tags_property
513+
assert tags_property["items"]["type"] == "string"
514+
515+
486516
def test_get_input_model_from_mcp_prompt():
487517
"""Test creation of input model from MCP prompt."""
488518
prompt = types.Prompt(

0 commit comments

Comments
 (0)