Skip to content

Commit ec67616

Browse files
authored
Add new RequiredIntArrayParam helper
1 parent 8e1e341 commit ec67616

File tree

3 files changed

+149
-6
lines changed

3 files changed

+149
-6
lines changed

pkg/github/issues.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1480,16 +1480,11 @@ func FindClosingPullRequests(getGQLClient GetGQLClientFn, t translations.Transla
14801480
if err != nil {
14811481
return mcp.NewToolResultError(fmt.Sprintf("repo parameter error: %s", err.Error())), nil
14821482
}
1483-
issueNumbers, err := OptionalIntArrayParam(request, "issue_numbers")
1483+
issueNumbers, err := RequiredIntArrayParam(request, "issue_numbers")
14841484
if err != nil {
14851485
return mcp.NewToolResultError(fmt.Sprintf("issue_numbers parameter error: %s", err.Error())), nil
14861486
}
14871487

1488-
// Validate that issue_numbers is not empty
1489-
if len(issueNumbers) == 0 {
1490-
return mcp.NewToolResultError("issue_numbers parameter is required and cannot be empty - provide at least one issue number"), nil
1491-
}
1492-
14931488
// Get GraphQL client
14941489
client, err := getGQLClient(ctx)
14951490
if err != nil {

pkg/github/server.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,50 @@ func RequiredInt(r mcp.CallToolRequest, p string) (int, error) {
9999
return int(v), nil
100100
}
101101

102+
// RequiredIntArrayParam is a helper function that can be used to fetch a required integer array parameter from the request.
103+
// It does the following checks:
104+
// 1. Checks if the parameter is present in the request
105+
// 2. Checks if the parameter is an array and each element can be converted to int
106+
// 3. Checks if the array is not empty
107+
func RequiredIntArrayParam(r mcp.CallToolRequest, p string) ([]int, error) {
108+
// Check if the parameter is present in the request
109+
if _, ok := r.GetArguments()[p]; !ok {
110+
return nil, fmt.Errorf("missing required parameter: %s", p)
111+
}
112+
113+
switch v := r.GetArguments()[p].(type) {
114+
case nil:
115+
return nil, fmt.Errorf("missing required parameter: %s", p)
116+
case []int:
117+
if len(v) == 0 {
118+
return nil, fmt.Errorf("parameter %s cannot be empty", p)
119+
}
120+
return v, nil
121+
case []any:
122+
if len(v) == 0 {
123+
return nil, fmt.Errorf("parameter %s cannot be empty", p)
124+
}
125+
intSlice := make([]int, len(v))
126+
for i, elem := range v {
127+
switch num := elem.(type) {
128+
case float64:
129+
intSlice[i] = int(num)
130+
case int:
131+
intSlice[i] = num
132+
case int32:
133+
intSlice[i] = int(num)
134+
case int64:
135+
intSlice[i] = int(num)
136+
default:
137+
return nil, fmt.Errorf("parameter %s contains non-numeric value, element %d is %T", p, i, elem)
138+
}
139+
}
140+
return intSlice, nil
141+
default:
142+
return nil, fmt.Errorf("parameter %s is not an array, is %T", p, r.GetArguments()[p])
143+
}
144+
}
145+
102146
// OptionalParam is a helper function that can be used to fetch a requested parameter from the request.
103147
// It does the following checks:
104148
// 1. Checks if the parameter is present in the request, if not, it returns its zero-value

pkg/github/server_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,110 @@ func TestOptionalIntArrayParam(t *testing.T) {
564564
}
565565
}
566566

567+
func TestRequiredIntArrayParam(t *testing.T) {
568+
tests := []struct {
569+
name string
570+
params map[string]interface{}
571+
paramName string
572+
expected []int
573+
expectError bool
574+
}{
575+
{
576+
name: "parameter not in request",
577+
params: map[string]any{},
578+
paramName: "numbers",
579+
expected: nil,
580+
expectError: true,
581+
},
582+
{
583+
name: "valid any array parameter with float64",
584+
params: map[string]any{
585+
"numbers": []any{float64(1), float64(2), float64(3)},
586+
},
587+
paramName: "numbers",
588+
expected: []int{1, 2, 3},
589+
expectError: false,
590+
},
591+
{
592+
name: "valid int array parameter",
593+
params: map[string]any{
594+
"numbers": []int{1, 2, 3},
595+
},
596+
paramName: "numbers",
597+
expected: []int{1, 2, 3},
598+
expectError: false,
599+
},
600+
{
601+
name: "mixed numeric types",
602+
params: map[string]any{
603+
"numbers": []any{float64(1), int(2), int32(3), int64(4)},
604+
},
605+
paramName: "numbers",
606+
expected: []int{1, 2, 3, 4},
607+
expectError: false,
608+
},
609+
{
610+
name: "invalid type in array",
611+
params: map[string]any{
612+
"numbers": []any{float64(1), "not a number"},
613+
},
614+
paramName: "numbers",
615+
expected: nil,
616+
expectError: true,
617+
},
618+
{
619+
name: "nil value",
620+
params: map[string]any{
621+
"numbers": nil,
622+
},
623+
paramName: "numbers",
624+
expected: nil,
625+
expectError: true,
626+
},
627+
{
628+
name: "empty array",
629+
params: map[string]any{
630+
"numbers": []any{},
631+
},
632+
paramName: "numbers",
633+
expected: nil,
634+
expectError: true,
635+
},
636+
{
637+
name: "empty int array",
638+
params: map[string]any{
639+
"numbers": []int{},
640+
},
641+
paramName: "numbers",
642+
expected: nil,
643+
expectError: true,
644+
},
645+
{
646+
name: "wrong parameter type",
647+
params: map[string]any{
648+
"numbers": "not an array",
649+
},
650+
paramName: "numbers",
651+
expected: nil,
652+
expectError: true,
653+
},
654+
}
655+
656+
for _, tc := range tests {
657+
t.Run(tc.name, func(t *testing.T) {
658+
request := createMCPRequest(tc.params)
659+
result, err := RequiredIntArrayParam(request, tc.paramName)
660+
661+
if tc.expectError {
662+
assert.Error(t, err)
663+
} else {
664+
assert.NoError(t, err)
665+
assert.Equal(t, tc.expected, result)
666+
}
667+
})
668+
}
669+
}
670+
567671
func TestOptionalPaginationParams(t *testing.T) {
568672
tests := []struct {
569673
name string

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy