diff --git a/pkg/github/granular_tools_test.go b/pkg/github/granular_tools_test.go index 4d7996e96..883158bb2 100644 --- a/pkg/github/granular_tools_test.go +++ b/pkg/github/granular_tools_test.go @@ -907,4 +907,42 @@ func TestGranularSetIssueFields(t *testing.T) { textContent := getTextResult(t, result) assert.Contains(t, textContent.Text, "each field must have a value") }) + + t.Run("multiple value keys returns error", func(t *testing.T) { + deps := BaseDeps{} + serverTool := GranularSetIssueFields(translations.NullTranslationHelper) + handler := serverTool.Handler(deps) + + request := createMCPRequest(map[string]any{ + "owner": "owner", + "repo": "repo", + "issue_number": float64(5), + "fields": []any{ + map[string]any{"field_id": "FIELD_1", "text_value": "hello", "number_value": float64(42)}, + }, + }) + result, err := handler(ContextWithDeps(context.Background(), deps), &request) + require.NoError(t, err) + textContent := getTextResult(t, result) + assert.Contains(t, textContent.Text, "each field must have exactly one value") + }) + + t.Run("value key with delete returns error", func(t *testing.T) { + deps := BaseDeps{} + serverTool := GranularSetIssueFields(translations.NullTranslationHelper) + handler := serverTool.Handler(deps) + + request := createMCPRequest(map[string]any{ + "owner": "owner", + "repo": "repo", + "issue_number": float64(5), + "fields": []any{ + map[string]any{"field_id": "FIELD_1", "text_value": "hello", "delete": true}, + }, + }) + result, err := handler(ContextWithDeps(context.Background(), deps), &request) + require.NoError(t, err) + textContent := getTextResult(t, result) + assert.Contains(t, textContent.Text, "each field must have exactly one value") + }) } diff --git a/pkg/github/issues_granular.go b/pkg/github/issues_granular.go index 107f8a74f..5dbd7d8d1 100644 --- a/pkg/github/issues_granular.go +++ b/pkg/github/issues_granular.go @@ -731,41 +731,44 @@ func GranularSetIssueFields(t translations.TranslationHelperFunc) inventory.Serv FieldID: githubv4.ID(fieldID), } - // Check for exactly one value type (or delete) - hasValue := false + // Count how many value keys are present; exactly one is required. + valueCount := 0 if v, err := OptionalParam[string](fieldMap, "text_value"); err == nil && v != "" { input.TextValue = githubv4.NewString(githubv4.String(v)) - hasValue = true + valueCount++ } if v, err := OptionalParam[float64](fieldMap, "number_value"); err == nil { if _, exists := fieldMap["number_value"]; exists { gqlFloat := githubv4.Float(v) input.NumberValue = &gqlFloat - hasValue = true + valueCount++ } } if v, err := OptionalParam[string](fieldMap, "date_value"); err == nil && v != "" { input.DateValue = githubv4.NewString(githubv4.String(v)) - hasValue = true + valueCount++ } if v, err := OptionalParam[string](fieldMap, "single_select_option_id"); err == nil && v != "" { optionID := githubv4.ID(v) input.SingleSelectOptionID = &optionID - hasValue = true + valueCount++ } if _, exists := fieldMap["delete"]; exists { del, err := OptionalParam[bool](fieldMap, "delete") if err == nil && del { deleteVal := githubv4.Boolean(true) input.Delete = &deleteVal - hasValue = true + valueCount++ } } - if !hasValue { + if valueCount == 0 { return utils.NewToolResultError("each field must have a value (text_value, number_value, date_value, single_select_option_id) or delete: true"), nil, nil } + if valueCount > 1 { + return utils.NewToolResultError("each field must have exactly one value (text_value, number_value, date_value, single_select_option_id) or delete: true, but multiple were provided"), nil, nil + } issueFields = append(issueFields, input) }