Skip to content

Commit 8b8c1ef

Browse files
committed
Work around for MCP Gateway schema issue
Signed-off-by: David Gageot <[email protected]>
1 parent abf25e1 commit 8b8c1ef

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

pkg/model/provider/openai/client.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,9 @@ func (c *Client) CreateChatCompletionStream(
338338
return nil, err
339339
}
340340

341+
// Fix missing item types in arrays
342+
parameters = fixSchemaArrayItems(parameters)
343+
341344
toolsParam[i] = openai.ChatCompletionFunctionTool(shared.FunctionDefinitionParam{
342345
Name: tool.Name,
343346
Description: openai.String(tool.Description),
@@ -447,6 +450,9 @@ func (c *Client) CreateResponseStream(
447450
// The Response API requires every parameter to be required
448451
parameters = makeAllRequired(parameters)
449452

453+
// Fix missing item types in arrays
454+
parameters = fixSchemaArrayItems(parameters)
455+
450456
toolsParam[i] = responses.ToolUnionParam{
451457
OfFunction: &responses.FunctionToolParam{
452458
Name: tool.Name,

pkg/model/provider/openai/schema.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package openai
22

33
import (
4+
"slices"
45
"sort"
56

67
"github.com/docker/cagent/pkg/tools"
@@ -58,3 +59,40 @@ func makeAllRequired(schema map[string]any) map[string]any {
5859
schema["additionalProperties"] = false
5960
return schema
6061
}
62+
63+
// In Docker Desktop 4.52, the MCP Gateway produces an invalid tools shema for `mcp-config-set`.
64+
func fixSchemaArrayItems(schema map[string]any) map[string]any {
65+
propertiesValue, ok := schema["properties"]
66+
if !ok {
67+
return schema
68+
}
69+
70+
properties, ok := propertiesValue.(map[string]any)
71+
if !ok {
72+
return schema
73+
}
74+
75+
for _, propValue := range properties {
76+
prop, ok := propValue.(map[string]any)
77+
if !ok {
78+
continue
79+
}
80+
81+
checkForMissingItems := false
82+
switch t := prop["type"].(type) {
83+
case string:
84+
checkForMissingItems = t == "array"
85+
case []string:
86+
checkForMissingItems = slices.Contains(t, "array")
87+
}
88+
if !checkForMissingItems {
89+
continue
90+
}
91+
92+
if _, ok := prop["items"]; !ok {
93+
prop["items"] = map[string]any{"type": "object"}
94+
}
95+
}
96+
97+
return schema
98+
}

pkg/model/provider/openai/schema_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,61 @@ func TestMakeAllRequired_NilSchema(t *testing.T) {
5353
require.NoError(t, err)
5454
assert.JSONEq(t, `{"additionalProperties":false,"properties":{},"type":"object","required":[]}`, string(buf))
5555
}
56+
57+
func TestFixSchemaArrayItems(t *testing.T) {
58+
schema := `{
59+
"properties": {
60+
"arguments": {
61+
"description": "Arguments to pass to the tool (can be any valid JSON value)",
62+
"type": [
63+
"string",
64+
"number",
65+
"boolean",
66+
"object",
67+
"array",
68+
"null"
69+
]
70+
},
71+
"name": {
72+
"description": "Name of the tool to execute",
73+
"type": "string"
74+
}
75+
},
76+
"required": [
77+
"name"
78+
],
79+
"type": "object"
80+
}`
81+
82+
schemaMap := map[string]any{}
83+
err := json.Unmarshal([]byte(schema), &schemaMap)
84+
require.NoError(t, err)
85+
86+
updatedSchema := fixSchemaArrayItems(schemaMap)
87+
buf, err := json.Marshal(updatedSchema)
88+
require.NoError(t, err)
89+
90+
assert.JSONEq(t, `{
91+
"properties": {
92+
"arguments": {
93+
"description": "Arguments to pass to the tool (can be any valid JSON value)",
94+
"type": [
95+
"string",
96+
"number",
97+
"boolean",
98+
"object",
99+
"array",
100+
"null"
101+
]
102+
},
103+
"name": {
104+
"description": "Name of the tool to execute",
105+
"type": "string"
106+
}
107+
},
108+
"required": [
109+
"name"
110+
],
111+
"type": "object"
112+
}`, string(buf))
113+
}

0 commit comments

Comments
 (0)