Bug Description
McpToolSpec.create_model_from_json_schema does not handle inline nested objects (objects defined directly under a properties entry with their own properties/required, rather than via a $ref/$defs). Instead of recursively building a nested Pydantic model, the nested object is collapsed into a bare Dict, so its properties and required are lost.
Where
- Package:
llama-index-tools-mcp
- File:
llama-index-integrations/tools/llama-index-tools-mcp/llama_index/tools/mcp/tool_spec_mixins.py
Version
llama-index-tools-mcp==0.4.8
llama-index-core==0.14.23
Steps to Reproduce
from llama_index.tools.mcp import McpToolSpec, BasicMCPClient
schema = {
"properties": {
"nested": {
"properties": {"value": {"title": "Value", "type": "string"}},
"required": ["value"],
"type": "object",
},
},
"required": ["nested"],
"type": "object",
}
tool_spec = McpToolSpec(BasicMCPClient("python", args=["server.py"]), allowed_tools=[])
model = tool_spec.create_model_from_json_schema(schema)
out = model.model_json_schema()
del out["title"]
print(out)
Expected Behavior
Build a model from the JSON schema using McpToolSpec.create_model_from_json_schema , and then calling model_json_schema() should reproduce the input schema with the nested object structure:
{
"properties": {
"nested": {
"properties": {"value": {"title": "Value", "type": "string"}},
"required": ["value"],
"type": "object",
}
},
"required": ["nested"],
"type": "object",
}
Actual Behavior
The nested field is generated as a bare dict, losing its inner properties:
{
"properties": {
"nested": {"additionalProperties": True, "title": "Nested", "type": "object"}
},
"required": ["nested"],
"type": "object",
}
Test Case
I've created a test case that can be added to llama-index-integrations/tools/llama-index-tools-mcp/tests/test_tools_mcp.py.
Only the nested-object test case fails; referenced-nested-object passes and is included as a contrast.
base_test_cases = [
pytest.param(
{
"properties": {
"nested": {
"properties": {
"value": {"title": "Value", "type": "string"},
},
"required": ["value"],
"type": "object",
},
},
"required": ["nested"],
"type": "object",
},
id="nested-object",
),
pytest.param(
{
"$defs": {
"Inner": {
"properties": {
"value": {"title": "Value", "type": "string"},
},
"required": ["value"],
"title": "Inner",
"type": "object",
},
},
"properties": {
"nested": {"$ref": "#/$defs/Inner"},
},
"required": ["nested"],
"type": "object",
},
id="referenced-nested-object",
),
]
@pytest.mark.parametrize(
"json_schema",
[
*base_test_cases,
],
)
def test_create_model_from_json_schema(client: BasicMCPClient, json_schema: dict):
"""Converting a JSON schema into a Pydantic model and back to a JSON schema should yield the original schema."""
tool_spec = McpToolSpec(client, allowed_tools=[])
pydantic_model = tool_spec.create_model_from_json_schema(json_schema)
json_schema_from_pydantic_model = pydantic_model.model_json_schema()
del json_schema_from_pydantic_model["title"]
assert json_schema == json_schema_from_pydantic_model
Bug Description
McpToolSpec.create_model_from_json_schemadoes not handle inline nested objects (objects defined directly under apropertiesentry with their ownproperties/required, rather than via a$ref/$defs). Instead of recursively building a nested Pydantic model, the nested object is collapsed into a bareDict, so itspropertiesandrequiredare lost.Where
llama-index-tools-mcpllama-index-integrations/tools/llama-index-tools-mcp/llama_index/tools/mcp/tool_spec_mixins.pyVersion
llama-index-tools-mcp==0.4.8llama-index-core==0.14.23Steps to Reproduce
Expected Behavior
Build a model from the JSON schema using
McpToolSpec.create_model_from_json_schema, and then callingmodel_json_schema()should reproduce the input schema with the nested object structure:{ "properties": { "nested": { "properties": {"value": {"title": "Value", "type": "string"}}, "required": ["value"], "type": "object", } }, "required": ["nested"], "type": "object", }Actual Behavior
The
nestedfield is generated as a bare dict, losing its inner properties:{ "properties": { "nested": {"additionalProperties": True, "title": "Nested", "type": "object"} }, "required": ["nested"], "type": "object", }Test Case
I've created a test case that can be added to
llama-index-integrations/tools/llama-index-tools-mcp/tests/test_tools_mcp.py.Only the
nested-objecttest case fails;referenced-nested-objectpasses and is included as a contrast.