Skip to content

update_issue_labels is annotated destructiveHint: false but replaces (removes) existing labels #3760

Open

Description

@rafe-walker

Describe the bug

The granular update_issue_labels tool sets destructiveHint: false. Its own description says "This replaces the current labels with the provided list", and that is what it does: labels not in the list are removed. A host that keys confirmation on destructiveHint may not prompt for a call that removes labels.

This is the opposite of #3281 / PR #3293, which are about additive tools that omit the hint. Here the hint is explicitly false on a tool that removes data. Open PR #2742 adds method: replace|add|remove but keeps replace as the default and does not change the annotation. update_issue_assignees uses the same annotation and the same replace pattern (issues_granular.go:238). That one was not tested live.

A previous PR, #2471, which marked the granular update_issue_* tools destructive for client egress policy, was closed unmerged. This issue is narrower: it concerns only the two replace-semantics tools, where the description and the annotation disagree.

The tool is behind the issues_granular feature flag, and this is an annotation-accuracy item only. To enable it, start the server with --features=issues_granular, which swaps the consolidated issue_write for the granular issue tools.

Code (main 99d6d65, unchanged since v2.1.0): pkg/github/issues_granular.go:368-375 (update_issue_labels, DestructiveHint: new(false) at :373).

Affected version

v2.1.0 (image sha256:f6056fc1…0f8a, commit 4bcdcdf) and main nightly (image sha256:48bc16d0…338f, revision 99d6d65), both with --features=issues_granular.

Steps to reproduce the behavior

  1. tools/list shows update_issue_labels annotations {"destructiveHint":false,"idempotentHint":false,"openWorldHint":true,"readOnlyHint":false}.
  2. Issue N has labels [c, d].
    (123 stands for the issue/PR number.)
  3. Call:
    {"name":"update_issue_labels","arguments":{"owner":"OWNER","repo":"REPO","issue_number":123,"labels":["a"]}}
  4. Result: success. Labels are now [a]: c and d were removed.

Expected vs actual behavior

Expected: a tool that can remove labels is annotated destructiveHint: true, or omits the hint, which defaults to true.

Actual: destructiveHint: false.

Suggested fix: set DestructiveHint: new(true) on update_issue_labels (and update_issue_assignees) while replace is possible. Annotations are static, so this holds even if PR #2742 adds non-destructive methods.

Logs

annotations: {"destructiveHint":false,"idempotentHint":false,"openWorldHint":true,"readOnlyHint":false,"title":"Update Issue Labels"}
labels before [c, d] -> update_issue_labels labels=["a"] -> OK -> labels after [a]     (v2.1.0 and main)

Found during an independent audit of v2.1.0 on a throwaway org and private test repo. Prepared with AI assistance (Claude Code); reproduced by two independent test runs before filing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions