Ensure MCP works when inputSchema.properties is missing (#454)
Resolves #449 - TLDR, [OpenAI's API](https://platform.openai.com/docs/api-reference/responses/create) expects the properties field to be present, whereas the MCP schema explicitly allows omitting the properties field. [MCP Spec](https://github.com/modelcontextprotocol/specification/blob/main/schema/2025-03-26/schema.json)
This commit is contained in:
parent
064e25b01b
commit
50bbfdd8be
2 changed files with 41 additions and 7 deletions
|
|
@ -59,6 +59,11 @@ class MCPUtil:
|
|||
"""Convert an MCP tool to an Agents SDK function tool."""
|
||||
invoke_func = functools.partial(cls.invoke_mcp_tool, server, tool)
|
||||
schema, is_strict = tool.inputSchema, False
|
||||
|
||||
# MCP spec doesn't require the inputSchema to have `properties`, but OpenAI spec does.
|
||||
if "properties" not in schema:
|
||||
schema["properties"] = {}
|
||||
|
||||
if convert_schemas_to_strict:
|
||||
try:
|
||||
schema = ensure_strict_json_schema(schema)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,10 @@ async def test_get_all_function_tools():
|
|||
|
||||
for idx, tool in enumerate(tools):
|
||||
assert isinstance(tool, FunctionTool)
|
||||
assert tool.params_json_schema == schemas[idx]
|
||||
if schemas[idx] == {}:
|
||||
assert tool.params_json_schema == snapshot({"properties": {}})
|
||||
else:
|
||||
assert tool.params_json_schema == schemas[idx]
|
||||
assert tool.name == names[idx]
|
||||
|
||||
# Also make sure it works with strict schemas
|
||||
|
|
@ -167,10 +170,7 @@ async def test_agent_convert_schemas_true():
|
|||
|
||||
# Checks that additionalProperties is set to False
|
||||
assert bar_tool.params_json_schema == snapshot(
|
||||
{
|
||||
"type": "object",
|
||||
"additionalProperties": {"type": "string"},
|
||||
}
|
||||
{"type": "object", "additionalProperties": {"type": "string"}, "properties": {}}
|
||||
)
|
||||
assert bar_tool.strict_json_schema is False, "bar_tool should not be strict"
|
||||
|
||||
|
|
@ -220,7 +220,9 @@ async def test_agent_convert_schemas_false():
|
|||
assert foo_tool.params_json_schema == strict_schema
|
||||
assert foo_tool.strict_json_schema is False, "Shouldn't be converted unless specified"
|
||||
|
||||
assert bar_tool.params_json_schema == non_strict_schema
|
||||
assert bar_tool.params_json_schema == snapshot(
|
||||
{"type": "object", "additionalProperties": {"type": "string"}, "properties": {}}
|
||||
)
|
||||
assert bar_tool.strict_json_schema is False
|
||||
|
||||
assert baz_tool.params_json_schema == possible_to_convert_schema
|
||||
|
|
@ -255,8 +257,35 @@ async def test_agent_convert_schemas_unset():
|
|||
assert foo_tool.params_json_schema == strict_schema
|
||||
assert foo_tool.strict_json_schema is False, "Shouldn't be converted unless specified"
|
||||
|
||||
assert bar_tool.params_json_schema == non_strict_schema
|
||||
assert bar_tool.params_json_schema == snapshot(
|
||||
{"type": "object", "additionalProperties": {"type": "string"}, "properties": {}}
|
||||
)
|
||||
assert bar_tool.strict_json_schema is False
|
||||
|
||||
assert baz_tool.params_json_schema == possible_to_convert_schema
|
||||
assert baz_tool.strict_json_schema is False, "Shouldn't be converted unless specified"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_util_adds_properties():
|
||||
"""The MCP spec doesn't require the inputSchema to have `properties`, so we need to add it
|
||||
if it's missing.
|
||||
"""
|
||||
schema = {
|
||||
"type": "object",
|
||||
"description": "Test tool",
|
||||
}
|
||||
|
||||
server = FakeMCPServer()
|
||||
server.add_tool("test_tool", schema)
|
||||
|
||||
tools = await MCPUtil.get_all_function_tools([server], convert_schemas_to_strict=False)
|
||||
tool = next(tool for tool in tools if tool.name == "test_tool")
|
||||
|
||||
assert isinstance(tool, FunctionTool)
|
||||
assert "properties" in tool.params_json_schema
|
||||
assert tool.params_json_schema["properties"] == {}
|
||||
|
||||
assert tool.params_json_schema == snapshot(
|
||||
{"type": "object", "description": "Test tool", "properties": {}}
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue