Skip to content

Commit 8c9eb4a

Browse files
committed
fix(issues): accept native integer types for issue_number parameters
Extend RequiredInt/toInt coercion to handle int, int64, and json.Number in addition to float64 and numeric strings. Some MCP clients (including mcpcurl integer flags) pass native Go integer types that were previously rejected with 'expected number, got int'. Also add missing deprecated aliases for the issues consolidation rename: get_issue -> issue_read and update_issue -> issue_write. Fixes #2807
1 parent 9430064 commit 8c9eb4a

4 files changed

Lines changed: 76 additions & 24 deletions

File tree

pkg/github/deprecated_tool_aliases.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ package github
1010
// "get_issue": "issue_read",
1111
// "create_pr": "pull_request_create",
1212
var DeprecatedToolAliases = map[string]string{
13-
// Add entries as tools are renamed
13+
// Issues tools consolidated (#1211)
14+
"get_issue": "issue_read",
15+
"update_issue": "issue_write",
16+
1417
// Actions tools consolidated
1518
"list_workflows": "actions_list",
1619
"list_workflow_runs": "actions_list",

pkg/github/issues_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,20 @@ func Test_AddIssueComment(t *testing.T) {
606606
expectError: false,
607607
expectedComment: mockComment,
608608
},
609+
{
610+
name: "successful comment creation with int issue_number",
611+
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
612+
PostReposIssuesCommentsByOwnerByRepoByIssueNumber: mockResponse(t, http.StatusCreated, mockComment),
613+
}),
614+
requestArgs: map[string]any{
615+
"owner": "owner",
616+
"repo": "repo",
617+
"issue_number": int(42),
618+
"body": "This is a test comment",
619+
},
620+
expectError: false,
621+
expectedComment: mockComment,
622+
},
609623
{
610624
name: "comment creation fails",
611625
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{

pkg/github/params.go

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package github
22

33
import (
4+
"encoding/json"
45
"errors"
56
"fmt"
67
"math"
@@ -40,23 +41,52 @@ func isAcceptedError(err error) bool {
4041
return errors.As(err, &acceptedError)
4142
}
4243

43-
// toInt converts a value to int, handling both float64 and string representations.
44-
// Some MCP clients send numeric values as strings. It rejects NaN, ±Inf,
45-
// fractional values, and values outside the int range.
46-
func toInt(val any) (int, error) {
47-
var f float64
44+
// numericToFloat64 normalizes numeric tool arguments to float64.
45+
// MCP clients may send JSON numbers as float64 (default json.Unmarshal),
46+
// native integer types (e.g. mcpcurl integer flags), or strings.
47+
func numericToFloat64(val any) (float64, error) {
4848
switch v := val.(type) {
4949
case float64:
50-
f = v
50+
return v, nil
51+
case float32:
52+
return float64(v), nil
53+
case int:
54+
return float64(v), nil
55+
case int32:
56+
return float64(v), nil
57+
case int64:
58+
return float64(v), nil
59+
case uint:
60+
return float64(v), nil
61+
case uint32:
62+
return float64(v), nil
63+
case uint64:
64+
return float64(v), nil
5165
case string:
52-
var err error
53-
f, err = strconv.ParseFloat(v, 64)
66+
f, err := strconv.ParseFloat(v, 64)
67+
if err != nil {
68+
return 0, fmt.Errorf("invalid numeric value: %s", v)
69+
}
70+
return f, nil
71+
case json.Number:
72+
f, err := v.Float64()
5473
if err != nil {
5574
return 0, fmt.Errorf("invalid numeric value: %s", v)
5675
}
76+
return f, nil
5777
default:
5878
return 0, fmt.Errorf("expected number, got %T", val)
5979
}
80+
}
81+
82+
// toInt converts a value to int, handling float64, integer, and string representations.
83+
// Some MCP clients send numeric values as strings or native integer types. It rejects
84+
// NaN, ±Inf, fractional values, and values outside the int range.
85+
func toInt(val any) (int, error) {
86+
f, err := numericToFloat64(val)
87+
if err != nil {
88+
return 0, err
89+
}
6090
if math.IsNaN(f) || math.IsInf(f, 0) {
6191
return 0, fmt.Errorf("non-finite numeric value")
6292
}
@@ -69,22 +99,13 @@ func toInt(val any) (int, error) {
6999
return int(f), nil
70100
}
71101

72-
// toInt64 converts a value to int64, handling both float64 and string representations.
73-
// Some MCP clients send numeric values as strings. It rejects NaN, ±Inf,
74-
// fractional values, and values that lose precision in the float64→int64 conversion.
102+
// toInt64 converts a value to int64, handling float64, integer, and string representations.
103+
// Some MCP clients send numeric values as strings or native integer types. It rejects
104+
// NaN, ±Inf, fractional values, and values that lose precision in the float64→int64 conversion.
75105
func toInt64(val any) (int64, error) {
76-
var f float64
77-
switch v := val.(type) {
78-
case float64:
79-
f = v
80-
case string:
81-
var err error
82-
f, err = strconv.ParseFloat(v, 64)
83-
if err != nil {
84-
return 0, fmt.Errorf("invalid numeric value: %s", v)
85-
}
86-
default:
87-
return 0, fmt.Errorf("expected number, got %T", val)
106+
f, err := numericToFloat64(val)
107+
if err != nil {
108+
return 0, err
88109
}
89110
if math.IsNaN(f) || math.IsInf(f, 0) {
90111
return 0, fmt.Errorf("non-finite numeric value")

pkg/github/params_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,20 @@ func Test_RequiredInt(t *testing.T) {
171171
expected: 42,
172172
expectError: false,
173173
},
174+
{
175+
name: "valid int parameter",
176+
params: map[string]any{"count": int(42)},
177+
paramName: "count",
178+
expected: 42,
179+
expectError: false,
180+
},
181+
{
182+
name: "valid int64 parameter",
183+
params: map[string]any{"count": int64(42)},
184+
paramName: "count",
185+
expected: 42,
186+
expectError: false,
187+
},
174188
{
175189
name: "missing parameter",
176190
params: map[string]any{},

0 commit comments

Comments
 (0)