diff --git a/internal/mcp/bridge_tool.go b/internal/mcp/bridge_tool.go index d7ac8582..bb5e5472 100644 --- a/internal/mcp/bridge_tool.go +++ b/internal/mcp/bridge_tool.go @@ -125,6 +125,9 @@ func inputSchemaToMap(schema mcpgo.ToolInputSchema) map[string]any { } if len(schema.Properties) > 0 { m["properties"] = schema.Properties + } else if m["type"] == "object" { + // OpenAI requires "properties" even when empty for object schemas. + m["properties"] = map[string]any{} } if len(schema.Required) > 0 { m["required"] = schema.Required diff --git a/internal/mcp/bridge_tool_test.go b/internal/mcp/bridge_tool_test.go index 01e19d6d..783048e9 100644 --- a/internal/mcp/bridge_tool_test.go +++ b/internal/mcp/bridge_tool_test.go @@ -47,6 +47,19 @@ func TestInputSchemaToMap_EmptyType(t *testing.T) { } } +func TestInputSchemaToMap_ObjectNoProperties(t *testing.T) { + schema := mcpgo.ToolInputSchema{Type: "object"} + m := inputSchemaToMap(schema) + + props, ok := m["properties"].(map[string]any) + if !ok || props == nil { + t.Fatal("expected empty properties map for object schema, got nil — OpenAI rejects object schemas without properties") + } + if len(props) != 0 { + t.Errorf("expected empty properties, got %v", props) + } +} + func TestExtractTextContent(t *testing.T) { result := &mcpgo.CallToolResult{ Content: []mcpgo.Content{