From 49ae90035b374aa9f0575f37c2e34be5554aba59 Mon Sep 17 00:00:00 2001 From: Rohan Mehta Date: Mon, 7 Apr 2025 17:40:40 -0400 Subject: [PATCH] Ensure MCP works when inputSchema.properties is missing --- src/agents/mcp/util.py | 5 +++++ tests/mcp/test_mcp_util.py | 43 +++++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/agents/mcp/util.py b/src/agents/mcp/util.py index 770ae8dd..bbfe1885 100644 --- a/src/agents/mcp/util.py +++ b/src/agents/mcp/util.py @@ -59,6 +59,11 @@ def to_function_tool( """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) diff --git a/tests/mcp/test_mcp_util.py b/tests/mcp/test_mcp_util.py index 64378b59..74356a16 100644 --- a/tests/mcp/test_mcp_util.py +++ b/tests/mcp/test_mcp_util.py @@ -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": {}} + )