Skip to content

Commit 1b6785d

Browse files
committed
fix: added missing schema/validation
1 parent 8e5dc79 commit 1b6785d

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

pkg/github/projects.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,24 @@ func UpdateProjectItem(getClient GetClientFn, t translations.TranslationHelperFu
629629
mcp.WithString("owner", mcp.Required(), mcp.Description("If owner_type == user it is the handle for the GitHub user account. If owner_type == org it is the name of the organization. The name is not case sensitive.")),
630630
mcp.WithNumber("project_number", mcp.Required(), mcp.Description("The project's number.")),
631631
mcp.WithNumber("item_id", mcp.Required(), mcp.Description("The numeric ID of the project item to update (not the issue or pull request ID).")),
632-
mcp.WithArray("fields", mcp.Required(), mcp.Description("A list of field updates to apply.")),
632+
mcp.WithArray("fields", mcp.Required(), mcp.Description("A list of field updates to apply."),
633+
mcp.Items(
634+
map[string]interface{}{
635+
"type": "object",
636+
"additionalProperties": false,
637+
"required": []string{"field_id", "value"},
638+
"properties": map[string]interface{}{
639+
"field_id": map[string]interface{}{
640+
"type": "string",
641+
"description": "The ID of the field to update",
642+
},
643+
"value": map[string]interface{}{
644+
"description": "The value to set for the field",
645+
},
646+
},
647+
},
648+
),
649+
),
633650
), func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
634651
owner, err := RequiredParam[string](req, "owner")
635652
if err != nil {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package github
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/github/github-mcp-server/pkg/translations"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
// TestAllArrayParametersHaveItems verifies that all array-type tool parameters
12+
// have an "items" schema defined, which is required by OpenAI's API
13+
func TestAllArrayParametersHaveItems(t *testing.T) {
14+
translator, _ := translations.TranslationHelper()
15+
16+
// Get all tools from toolsets
17+
toolsetGroup := DefaultToolsetGroup(false, nil, nil, nil, translator, 500)
18+
19+
// Enable all toolsets to get all tools
20+
_ = toolsetGroup.EnableToolsets([]string{"all"})
21+
22+
for _, toolset := range toolsetGroup.Toolsets {
23+
for _, serverTool := range toolset.GetAvailableTools() {
24+
toolName := serverTool.Tool.Name
25+
inputSchema := serverTool.Tool.InputSchema
26+
27+
// Marshal to JSON to inspect the schema
28+
schemaJSON, err := json.Marshal(inputSchema)
29+
require.NoError(t, err, "failed to marshal schema for tool %s", toolName)
30+
31+
var schema map[string]interface{}
32+
err = json.Unmarshal(schemaJSON, &schema)
33+
require.NoError(t, err, "failed to unmarshal schema for tool %s", toolName)
34+
35+
// Check properties
36+
properties, ok := schema["properties"].(map[string]interface{})
37+
if !ok {
38+
continue // No properties, skip
39+
}
40+
41+
for propName, propValue := range properties {
42+
propDef, ok := propValue.(map[string]interface{})
43+
if !ok {
44+
continue
45+
}
46+
47+
// If this is an array type, it MUST have an "items" property
48+
if propType, hasType := propDef["type"].(string); hasType && propType == "array" {
49+
_, hasItems := propDef["items"]
50+
require.True(t, hasItems,
51+
"tool %s has array parameter %s without 'items' schema definition. "+
52+
"OpenAI requires all array parameters to have an 'items' schema.",
53+
toolName, propName)
54+
}
55+
}
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)