Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion pkg/github/deprecated_tool_aliases.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ package github
// "get_issue": "issue_read",
// "create_pr": "pull_request_create",
var DeprecatedToolAliases = map[string]string{
// Add entries as tools are renamed
// Issues tools consolidated (#1211)
"get_issue": "issue_read",
"update_issue": "issue_write",

// Actions tools consolidated
"list_workflows": "actions_list",
"list_workflow_runs": "actions_list",
Expand Down
14 changes: 14 additions & 0 deletions pkg/github/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,20 @@ func Test_AddIssueComment(t *testing.T) {
expectError: false,
expectedComment: mockComment,
},
{
name: "successful comment creation with int issue_number",
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
PostReposIssuesCommentsByOwnerByRepoByIssueNumber: mockResponse(t, http.StatusCreated, mockComment),
}),
requestArgs: map[string]any{
"owner": "owner",
"repo": "repo",
"issue_number": int(42),
"body": "This is a test comment",
},
expectError: false,
expectedComment: mockComment,
},
{
name: "comment creation fails",
mockedClient: MockHTTPClientWithHandlers(map[string]http.HandlerFunc{
Expand Down
67 changes: 44 additions & 23 deletions pkg/github/params.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package github

import (
"encoding/json"
"errors"
"fmt"
"math"
Expand Down Expand Up @@ -40,23 +41,52 @@ func isAcceptedError(err error) bool {
return errors.As(err, &acceptedError)
}

// toInt converts a value to int, handling both float64 and string representations.
// Some MCP clients send numeric values as strings. It rejects NaN, ±Inf,
// fractional values, and values outside the int range.
func toInt(val any) (int, error) {
var f float64
// numericToFloat64 normalizes numeric tool arguments to float64.
// MCP clients may send JSON numbers as float64 (default json.Unmarshal),
// native integer types (e.g. mcpcurl integer flags), or strings.
func numericToFloat64(val any) (float64, error) {
switch v := val.(type) {
case float64:
f = v
return v, nil
case float32:
return float64(v), nil
case int:
return float64(v), nil
case int32:
return float64(v), nil
case int64:
return float64(v), nil
case uint:
return float64(v), nil
case uint32:
return float64(v), nil
case uint64:
return float64(v), nil
case string:
var err error
f, err = strconv.ParseFloat(v, 64)
f, err := strconv.ParseFloat(v, 64)
if err != nil {
return 0, fmt.Errorf("invalid numeric value: %s", v)
}
return f, nil
case json.Number:
f, err := v.Float64()
if err != nil {
return 0, fmt.Errorf("invalid numeric value: %s", v)
}
return f, nil
default:
return 0, fmt.Errorf("expected number, got %T", val)
}
}

// toInt converts a value to int, handling float64, integer, and string representations.
// Some MCP clients send numeric values as strings or native integer types. It rejects
// NaN, ±Inf, fractional values, and values outside the int range.
func toInt(val any) (int, error) {
f, err := numericToFloat64(val)
if err != nil {
return 0, err
}
if math.IsNaN(f) || math.IsInf(f, 0) {
return 0, fmt.Errorf("non-finite numeric value")
}
Expand All @@ -69,22 +99,13 @@ func toInt(val any) (int, error) {
return int(f), nil
}

// toInt64 converts a value to int64, handling both float64 and string representations.
// Some MCP clients send numeric values as strings. It rejects NaN, ±Inf,
// fractional values, and values that lose precision in the float64→int64 conversion.
// toInt64 converts a value to int64, handling float64, integer, and string representations.
// Some MCP clients send numeric values as strings or native integer types. It rejects
// NaN, ±Inf, fractional values, and values that lose precision in the float64→int64 conversion.
func toInt64(val any) (int64, error) {
var f float64
switch v := val.(type) {
case float64:
f = v
case string:
var err error
f, err = strconv.ParseFloat(v, 64)
if err != nil {
return 0, fmt.Errorf("invalid numeric value: %s", v)
}
default:
return 0, fmt.Errorf("expected number, got %T", val)
f, err := numericToFloat64(val)
if err != nil {
return 0, err
}
if math.IsNaN(f) || math.IsInf(f, 0) {
return 0, fmt.Errorf("non-finite numeric value")
Expand Down
14 changes: 14 additions & 0 deletions pkg/github/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,20 @@ func Test_RequiredInt(t *testing.T) {
expected: 42,
expectError: false,
},
{
name: "valid int parameter",
params: map[string]any{"count": int(42)},
paramName: "count",
expected: 42,
expectError: false,
},
{
name: "valid int64 parameter",
params: map[string]any{"count": int64(42)},
paramName: "count",
expected: 42,
expectError: false,
},
{
name: "missing parameter",
params: map[string]any{},
Expand Down