enhance update_issue_labels tool with method options#2742
Conversation
There was a problem hiding this comment.
Pull request overview
This PR enhances the feature-flagged update_issue_labels MCP tool to support granular label operations via a new method parameter, enabling atomic add/remove behavior without requiring a read-modify-write cycle.
Changes:
- Added
methodtoupdate_issue_labelswithreplace(default),add, andremovebehaviors, including URL-escaped label removal for names containing spaces/slashes. - Refactored label handling into helpers (
issueLabelNames,replaceIssueLabels,addIssueLabels,removeIssueLabels) and attached repo-visibility IFC labeling for label results. - Added unit tests and updated the tool snapshot and feature-flag docs to reflect the new input schema/behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| pkg/github/issues_granular.go | Adds method support and implements add/remove/replace label operations with validation and URL-escaped deletes. |
| pkg/github/helper_test.go | Adds mock endpoint patterns for the new labels POST and label DELETE routes used by tests. |
| pkg/github/granular_tools_test.go | Adds coverage for add/remove behaviors, trimming/dedup validation, escaping, and method normalization. |
| pkg/github/toolsnaps/update_issue_labels.snap | Updates the toolsnap to include the new method parameter and updated labels description. |
| docs/feature-flags.md | Updates feature-flag tool documentation to include the new method parameter and revised labels description. |
| r, err := json.Marshal(issue.Labels) | ||
| if err != nil { | ||
| return utils.NewToolResultErrorFromErr("failed to marshal response", err), nil, nil | ||
| } | ||
|
|
||
| result := utils.NewToolResultText(string(r)) | ||
| // Labels are structural repo metadata defined by collaborators | ||
| // (trusted); confidentiality follows repo visibility. | ||
| result = attachRepoVisibilityIFCLabelLazy(ctx, deps, owner, repo, result, ifc.LabelRepoMetadata) | ||
| return result, nil, nil |
There was a problem hiding this comment.
The shape change is intentional and not a GA break, this tool is behind the issues_granular feature flag, so there's no stable response contract yet. All three methods (replace/add/remove) return the resulting label set on purpose: add/remove are backed by the labels endpoints, which return []Label and never expose the issue's ID/URL, so emitting MinimalResponse would force an extra GET per call to return less useful data, and reverting only replace would make the tool inconsistent with itself. Returning the labels gives one consistent, useful response across all methods (see
Summary
Adds a
methodparameter to the feature-flaggedupdate_issue_labelstool so one tool can replace (default), add, or remove issue labels.Why
Fixes #2724
The tool could previously only replace an issue's entire label set, forcing a full read-modify-write cycle just to add or remove a single label. A
methoddiscriminator makes targeted add/remove operations safe and atomic.What changed
methodparameter toupdate_issue_labels:replace(default),add,remove.add→ POST.../labels(keeps existing labels);remove→ one DELETE.../labels/{name}per label (atomic, avoids the read-modify-write race);replacekeeps the existing PATCH behavior with optional per-label rationale/confidence/is_suggestion intent.status/blocked) stay a single valid path segment.docs/feature-flags.md.MCP impact
methodenum and add/remove behaviors toupdate_issue_labels(behind theissues_granularfeature flag).Security / limits
reposcope; results are tagged with the repo-visibility IFC label (labels are trusted repo metadata), and label names are URL-escaped to avoid malformed or extra path segments.Tool renaming
add/removeare new methods on the existing tool, not new or renamed tools, so no aliases are needed.Lint & tests
./script/lint./script/testDocs
docs/feature-flags.md.