Repository navigation
github_issue_write silently drops labels when caller lacks AddLabelsToLabelable permission #3160
Description
Describe the bug
github_issue_write with method: "create" (and method: "update") silently drops the labels argument when the calling user lacks AddLabelsToLabelable permission on the target repository. The API returns success (issue created/updated, no error), but no label is applied. The failure is only detectable by reading back the issue's labels.
Observed against an upstream repo where the caller is not a maintainer, using a label that verifiably exists in the repository (enhancement, applied via the repo's issue template):
github_issue_writecreate withlabels: ["enhancement"]→ returns success + issue URL.github_issue_readwithget_labelson the created issue →[](empty).- Retried via
github_issue_writeupdate withlabels: ["enhancement"]→ again success, still empty. - The label exists in the repo:
GitHub_get_labelreturns the label (colora2eeef, description "New feature or request"). - The equivalent CLI operation fails loudly:
gh issue edit <n> --add-label enhancementexits 1 with a GraphQL permission error (see Logs).
So the MCP tool succeeds silently where the CLI surfaces the permission boundary — the labels field is dropped without any error or warning.
Affected version
Could not capture the server version: the docker daemon is not running in this environment (docker run -i --rm ghcr.io/github/github-mcp-server ./github-mcp-server --version failed with failed to connect to the docker API at unix:///var/run/docker.sock; check if the path is correct and if the daemon is running: dial unix /var/run/docker.sock: connect: no such file or directory).
Environment used: the hosted GitHub MCP endpoint at https://api.githubcopilot.com/mcp/ (as configured by the host client).
Steps to reproduce the behavior
- Authenticate to the MCP server as a user without
AddLabelsToLabelablepermission on an upstream repo (i.e. not a maintainer/collaborator). - Confirm a label exists in that repo (e.g. via
get_labelfor the label the repo's issue template applies, such asenhancement). - Call
github_issue_writewithmethod: "create",owner,repo,title,body, andlabels: ["enhancement"]. - View the output — the tool reports success and returns the new issue URL.
- Call
github_issue_readwithmethod: "get_labels"for that issue — the labels list is empty. - Repeat with
method: "update"adding the same label — same silent drop.
Expected vs actual behavior
- Expected: either the label is applied, or the tool returns an error indicating the label(s) could not be applied (matching the CLI's behavior).
- Actual: the tool returns success with no error, and the label is silently not applied. The caller has no way to know the label was dropped without a read-back.
Logs
gh issue edit confirmation of the permission boundary (CLI fails loudly where the MCP tool succeeds silently):
gh issue edit 44 --add-label enhancement
GraphQL: HaleTom does not have the correct permissions to execute `AddLabelsToLabelable` (addLabelsToLabelable)
get_labels read-back on the issue created by the MCP tool with labels: ["enhancement"]: [].
Activity
CAOShurong commentedon Aug 25, 2026
Verified against main (
822c8776) — the report is accurate, and the reason for the silence is structural:Root cause walk
CreateIssuebuildsgithub.CreateIssueRequest{Labels: ...}(pkg/github/issues.go ~L2672),UpdateIssuesetsissueRequest.LabelswhenLabelsProvided(~L2758). There is no separate add-labels call anywhere in the codebase (noAddLabelsToIssueusage).MinimalResponse{ID, URL}built from the returned issue and discard everything else (~L2702, ~L2931). The REST response actually echoes the post-write label set, but it is thrown away.AddLabelsToLabelable, the tool has no error to surface and discards the one signal that would reveal the drop.Reproduced at package level (go1.26.7, worktree at
822c8776): mocked endpoint answering201 Createdwith an empty"labels":[]array to a create carryinglabels:["enhancement"]returnserr == nil. Confirmed: an error-based fix alone cannot detect this class of failure; the information exists only in the returnedissue.Labels, which the tool currently drops.Design options
requested_labelsvsapplied_labelstaken from the returned issue. Callers (and agents driving them) immediately see the mismatch.UpdateIssuealready uses forfallbackDeleteFieldIDs(the "failed=..., cleared=..." pattern at ~L2849).get_labelsread-back.Note
assigneesalmost certainly behaves identically (same request-body mechanism, same permission model) and would benefit from option 1 for free.Happy to send a PR implementing option 1 plus tests if maintainers agree that is the desired shape.