Comparing v1.4.0...v1.5.0 · github/github-mcp-server · GitHub
Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: github/github-mcp-server
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.4.0
Choose a base ref
...
head repository: github/github-mcp-server
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.5.0
Choose a head ref
  • 15 commits
  • 95 files changed
  • 11 contributors

Commits on Jun 19, 2026

  1. Promote issue fields and deprecate legacy issue write tool (#2696)

    * Promote issue fields FF and remove legacy issue write methods
    
    * Remove legacy issue_write methods
    
    * Remove feature flag
    
    * Update tests
    
    * Update tool snaps
    
    * Update docs
    
    * Remove legacy issue write from issues test
    
    * Update tool snap
    
    * Fix docs
    
    * Include issue_fields in doc
    
    * Remove issue fields FF check in ui tools
    
    * Update UI tools test
    
    * update docs
    
    * Regenerate doc
    reneexeener authored Jun 19, 2026
    Configuration menu
    Copy the full SHA
    a378370 View commit details
    Browse the repository at this point in the history

Commits on Jun 23, 2026

  1. build(deps): bump actions/checkout from 6 to 7 (#2754)

    Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
    - [Release notes](https://github.com/actions/checkout/releases)
    - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
    - [Commits](actions/checkout@v6...v7)
    
    ---
    updated-dependencies:
    - dependency-name: actions/checkout
      dependency-version: '7'
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jun 23, 2026
    Configuration menu
    Copy the full SHA
    0b8bddb View commit details
    Browse the repository at this point in the history
  2. build(deps): bump golang from 8d95af5 to 523c3ef (#2753)

    Bumps golang from `8d95af5` to `523c3ef`.
    
    ---
    updated-dependencies:
    - dependency-name: golang
      dependency-version: 1.25.11-alpine
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jun 23, 2026
    Configuration menu
    Copy the full SHA
    6f33870 View commit details
    Browse the repository at this point in the history
  3. build(deps): bump node from 3ad34ca to a2dc166 (#2752)

    Bumps node from `3ad34ca` to `a2dc166`.
    
    ---
    updated-dependencies:
    - dependency-name: node
      dependency-version: 26-alpine
      dependency-type: direct:production
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jun 23, 2026
    Configuration menu
    Copy the full SHA
    27d8463 View commit details
    Browse the repository at this point in the history
  4. build(deps): bump hono (#2735)

    Bumps the npm_and_yarn group with 1 update in the /ui directory: [hono](https://github.com/honojs/hono).
    
    
    Updates `hono` from 4.12.23 to 4.12.26
    - [Release notes](https://github.com/honojs/hono/releases)
    - [Commits](honojs/hono@v4.12.23...v4.12.26)
    
    ---
    updated-dependencies:
    - dependency-name: hono
      dependency-version: 4.12.26
      dependency-type: indirect
      dependency-group: npm_and_yarn
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    dependabot[bot] authored Jun 23, 2026
    Configuration menu
    Copy the full SHA
    7613599 View commit details
    Browse the repository at this point in the history
  5. Add get_parent method to issue_read (#2726)

    Add an upward parent read to issue_read, the counterpart to the existing
    downward get_sub_issues. Uses the GraphQL Issue.parent field and returns a
    null parent when the issue is not a sub-issue. Kept always-on (not feature
    gated) to mirror get_sub_issues; the dependency tools remain flag-gated.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Sam Morrow <info@sam-morrow.com>
    3 people authored Jun 23, 2026
    Configuration menu
    Copy the full SHA
    9430064 View commit details
    Browse the repository at this point in the history

Commits on Jun 25, 2026

  1. Show issue_write MCP App form for labels/assignees/milestone/type (#2767

    )
    
    The issue_write form-gating logic uses issueWriteFormParams to decide whether
    to render the MCP App form or execute directly: a call carrying any parameter
    outside that allowlist bypasses the form. The form prefills and re-submits
    labels, assignees, milestone and type, but those four were absent from the
    allowlist, so passing any of them skipped the confirmation form even though the
    form fully supports them.
    
    Add labels, assignees, milestone and type to issueWriteFormParams so the form
    is shown when they are present. The allowlist now covers every input-schema
    property, leaving issueWriteHasNonFormParams as a forward-compatibility safety
    net for properties added without form support.
    
    Also correct the now-inaccurate show_ui guidance on issue_write and
    create_pull_request: both descriptions claimed the form "does not collect"
    fields it actually collects (labels/assignees/milestone/type/issue_fields, and
    reviewers respectively).
    
    Update unit tests and regenerate toolsnaps and docs.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    mattdholloway and Copilot authored Jun 25, 2026
    Configuration menu
    Copy the full SHA
    3c4749d View commit details
    Browse the repository at this point in the history
  2. fix(ui_get): bound pagination to cap latency (#2766)

    ui_get backs a synchronous UI picker (label/assignee/etc. dropdowns in the
    MCP App issue/PR write surfaces). Each handler paginated GitHub API results
    in an unbounded loop (PerPage 100, looping until NextPage==0 /
    HasNextPage==false). On very large repos/orgs this fans out into dozens of
    sequential round-trips, and a single slow page inflates the whole call —
    production telemetry showed a tail spiking to ~20 minutes.
    
    Bound every ui_get pagination loop to uiGetMaxPages (10 pages, ~1000 items)
    and add an additive "has_more" flag indicating results were truncated.
    Truncation is acceptable here because the picker pairs it with typeahead, so
    responsiveness matters more than completeness.
    
    Affected methods: labels, assignees, milestones, branches, reviewers
    (both the collaborators and teams loops). uiGetIssueTypes and issue_fields
    are single-request and left unchanged.
    
    has_more is response-only and backward-compatible: no existing keys are
    removed or renamed, and the tool input schema is unchanged. HTTP-client
    timeouts are intentionally a separate follow-up.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Sam Morrow <info@sam-morrow.com>
    3 people authored Jun 25, 2026
    Configuration menu
    Copy the full SHA
    63d313a View commit details
    Browse the repository at this point in the history

Commits on Jun 26, 2026

  1. feat(oauth): add stdio OAuth 2.1 login core library (1/4) (#2704)

    * feat(oauth): add stdio OAuth 2.1 stdio login
    Introduce internal/oauth, a self-contained library that performs the
    user-facing GitHub OAuth login the stdio server uses to obtain a token
    without a pre-provisioned PAT. It is independent of MCP: client concerns
    (elicitation) sit behind the Prompter interface so the flows are testable
    without a live session.
    
    What it provides:
    - Authorization-code + PKCE flow with a local loopback callback server,
      state/CSRF validation, and XSS-safe result pages.
    - Device-authorization flow as a fallback (headless, containers).
    - A Manager that selects the most secure available channel
      (browser auto-open -> URL elicitation -> last-resort user action),
      runs a single flow at a time, and exposes a refreshing token source.
    
    Both GitHub OAuth Apps and GitHub Apps are supported without special
    casing: the token is modeled as an x/oauth2 refreshing TokenSource, so
    expiring GitHub App user tokens are renewed transparently (the gap that
    made a stored-token approach silently die after ~8h).
    
    When a client lacks secure URL elicitation and the flow falls back to a
    tool-response message, the message advises the user that their agent/CLI/
    IDE does not appear to support URL elicitation and suggests requesting it
    for improved security.
    
    Tests exercise real protocol behavior against an httptest GitHub stand-in:
    PKCE challenge/verifier, GitHub App refresh-on-expiry, device polling,
    URL elicitation, declined prompts, the last-resort action with advisory,
    and single-flight concurrency.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(oauth): reap browser launcher and keep native callback on loopback
    
    Address code review:
    - openBrowser: reap the launcher process asynchronously so it does not
      linger as a zombie for the lifetime of the server.
    - listenCallback: take an explicit bindAll flag and bind to all interfaces
      only inside a container (where the published port arrives via eth0).
      A native run, even with a fixed callback port, now stays on 127.0.0.1
      instead of 0.0.0.0.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(oauth): fail fast when a fixed callback port is unavailable
    
    A fixed --oauth-callback-port is registered with the OAuth app and chosen
    deliberately, so a bind failure means another process holds the port and
    could intercept the authorization redirect. Treat that as fatal instead of
    silently downgrading to the device flow, which would mask the conflict.
    
    Also warn, when binding the callback inside a container, that the listener
    is on all interfaces and should be published to loopback only so the
    authorization code is not exposed on the container network.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(oauth): surface refresh failures, bound refresh, prefer device flow when headless
    
    Addresses pre-merge review of the OAuth stdio core:
    
    - Log a one-time warning when token refresh fails instead of silently
      returning an empty access token, so a forced re-login isn't a surprise.
    - Bound each background token refresh with a 30s HTTP client timeout so a
      stalled GitHub token endpoint can't block tool calls indefinitely.
    - On a headless host (no display server) with a random callback port, fall
      back to the device-code flow — the only channel reachable from a browser
      on another machine — instead of dead-ending on an unreachable localhost
      redirect. A generic browser-open failure still offers the manual URL.
    - Mark the callback bind failure with a sentinel so the fixed-port-busy
      fatal path can't misreport an unrelated error as a port conflict.
    - Export NormalizeHost so callers can recognize the default github.com host
      (consumed by the build-time baked-in credential guard).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * feat(oauth): wire stdio OAuth 2.1 login into the server (2/4) (#2710)
    
    * feat(oauth): wire stdio OAuth 2.1 login into the server
    
    Connect the internal/oauth core library to the stdio MCP server so users
    can authenticate with an OAuth App or GitHub App client ID instead of a
    static personal access token.
    
    - BearerAuthTransport gains a TokenProvider that is consulted per request,
      letting the lazily-acquired, auto-refreshing OAuth token take effect
      without rebuilding the client.
    - createGitHubClients uses BearerAuthTransport (and skips go-github's
      WithAuthToken, which would pin a static token) when a TokenProvider is set.
    - RunStdioServer starts without a token and installs receiving middleware
      that runs the authorization flow on the first tool call, surfacing the
      auth URL or device code via elicitation (or a tool result as a fallback).
    - Tool filtering uses the requested OAuth scopes; the default supported set
      hides nothing, while a narrower --oauth-scopes both narrows the grant and
      filters tools accordingly.
    - A sessionPrompter adapts the MCP server session to oauth.Prompter, keeping
      the authorization URL off the model's context.
    - New stdio flags: --oauth-client-id/-client-secret/-scopes/-callback-port.
    
    This is stdio-only and deliberately does not touch MCP-HTTP auth.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(oauth): address review — omit empty bearer header, guard token/oauth
    
    - BearerAuthTransport omits the Authorization header entirely when the token
      is empty (pre-authorization) rather than sending an empty "Bearer " value.
    - RunStdioServer rejects the ambiguous combination of a static Token and an
      OAuthManager up front, enforcing the documented mutual exclusivity.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(oauth): clarify SupportedScopes is the stdio default and tool filter
    
    Document that stdio OAuth login requests these scopes by default and then
    filters the exposed tools to the scopes actually granted, so a tool whose
    required scope is absent from this list is hidden under default OAuth even
    though a PAT carrying that scope would expose it. Keep the list in sync with
    tool scope requirements when scopes change.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Distinguish undeliverable auth prompts from user declines
    
    An elicitation prompt that the client cannot deliver (a transport or
    protocol failure) was treated the same as a user actively declining: any
    display error cancelled the flow. That conflated a system failure with a
    deliberate "no", so a client that advertised URL elicitation but failed
    to deliver it would hard-fail the login instead of degrading.
    
    Add an ErrPromptUnavailable sentinel alongside ErrPromptDeclined and have
    the MCP adapter return it when Elicit fails at the transport level. The
    manager now falls back to the manual user-action channel on an
    undeliverable prompt (keeping the background flow alive so the user can
    still authorize out of band), while a genuine decline still aborts. A
    context-cancelled prompt is checked first so an ending flow is never
    misread as a transport failure.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * build(oauth): bake in default OAuth credentials for official releases (3/4) (#2711)
    
    * build(oauth): bake in default OAuth credentials via build-time ldflags
    
    Inject the public OAuth client credentials (stored as the OAUTH_CLIENT_ID
    and OAUTH_CLIENT_SECRET repo secrets) at build time via -ldflags so
    official binaries and images ship a working default app for zero-config
    login. Security relies on PKCE, not on the secret. Local/dev builds leave
    the values empty and continue to require an explicit token or
    --oauth-client-id.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(oauth): recognize github.com host aliases for the baked-in client
    
    Match the default host via oauth.NormalizeHost instead of only an empty
    host string, so an explicit GITHUB_HOST=github.com (or api.github.com)
    still counts as the default and keeps zero-config baked-in login working.
    GHES and ghe.com users continue to bring their own --oauth-client-id.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(oauth): document stdio OAuth login; make PAT optional in install config (#2717)
    
    Add a dedicated Local Server OAuth Login guide (docs/oauth-login.md) covering
    the PKCE/device flows, display channels and the URL-elicitation security
    advisory, scope-based tool filtering, the fixed-port Docker recipe and its
    loopback/port-safety behavior, bringing your own OAuth or GitHub App, and the
    GitHub Enterprise Server / ghe.com requirement to register an app on that host
    (custom --gh-host directs login at that instance's authorization server).
    
    Reflect that the local server now logs in with OAuth by default on github.com:
    - README: make the stdio Docker install badges OAuth-first (fixed callback port
      8085 published to loopback), drop the PAT prompt, and reframe the PAT as an
      optional alternative with a pointer to the new guide.
    - server.json: make GITHUB_PERSONAL_ACCESS_TOKEN optional and publish the OAuth
      callback port so the registry default works without a token.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    SamMorrowDrums and Copilot authored Jun 26, 2026
    Configuration menu
    Copy the full SHA
    8ce77e3 View commit details
    Browse the repository at this point in the history
  2. docs: lead local/stdio install with OAuth login (#2776)

    * docs: lead local/stdio install with OAuth login
    
    Surface OAuth 2.1 login as a first-class option above the Personal Access
    Token in the README install section and in every local-capable installation
    guide, each in that client's own config syntax, linking to the dedicated
    docs/oauth-login.md guide.
    
    The github.com OAuth example needs no token; in Docker it publishes a fixed
    callback port to loopback (-p 127.0.0.1:8085:8085). The PAT block is retained
    below it and noted as taking precedence over OAuth.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs(oauth): correct PKCE/client-secret explanation
    
    The previous "How it works" text claimed PKCE removes the need for a client
    secret. In practice GitHub requires the client secret at the token endpoint for
    both OAuth Apps and GitHub Apps, and the implementation sends it alongside the
    PKCE verifier (Manager.oauth2Config populates ClientSecret; flow.go exchanges
    with VerifierOption). The secret is baked into the distributed binary and is not
    truly confidential; PKCE is what actually secures the flow. Reword to reflect
    this accurately.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * docs: don't frame OAuth login as github.com-only
    
    The intro line said "On github.com you can skip the token entirely", which
    implied OAuth login only works on github.com. OAuth works on GitHub Enterprise
    too — you just supply your own app credentials there. Reword to lead with OAuth
    as the mechanism and scope the zero-config claim correctly: on github.com the
    official image already includes the app credentials, so the user provides none.
    Enterprise / bring-your-own-app is covered by the linked OAuth guide.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    SamMorrowDrums and Copilot authored Jun 26, 2026
    Configuration menu
    Copy the full SHA
    fab5fc5 View commit details
    Browse the repository at this point in the history
  3. fix(pull_requests): validate required params in add_comment_to_pendin…

    …g_review (#2770)
    
    Replace mapstructure.WeakDecode with RequiredParam/RequiredInt checks so
    missing arguments like owner return a clear validation error instead of
    running the GraphQL query with zero values.
    
    Fixes #2718
    
    Co-authored-by: Cursor Agent <cursoragent@cursor.com>
    syf2211 and cursoragent authored Jun 26, 2026
    Configuration menu
    Copy the full SHA
    5aa8ed3 View commit details
    Browse the repository at this point in the history
  4. fix(mcp-apps): reconcile the show/defer contract — render results, re…

    …move show_ui (#2774)
    
    * fix(ui): render success view when an MCP App tool executed up-front
    
    The create_pull_request / issue_write / update_pull_request Views decided
    form-vs-success from in-app submit state only, ignoring the tool-result the
    host delivers on render. Per the MCP Apps 2026-01-26 spec the host renders a
    View whenever the tool carries _meta.ui.resourceUri — independent of whether
    the server deferred or executed. So when the server executed up-front (e.g.
    show_ui=false, or parameters the form can't represent) the View still showed
    its "Create pull request" input form over an already-created PR, which reads
    as a bug (it even shows a PR number).
    
    Drive the Views off the result instead: a new shared completedToolResult()
    helper returns parsed data only for a genuine completed success, and returns
    null for the awaiting_user_submission deferral sentinel, errors, or no result.
    Each write View now shows its success card when that completed result is
    present, so the form is only ever shown while the action is genuinely deferred.
    
    Reconciles the show/defer state machine at the View (decision layer that the
    host result feeds). See github/copilot-mcp-core#1864.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * fix(ui): scope tool-result to the current invocation
    
    Address review feedback: the write Views derive their success card from
    `toolResult`, but it wasn't cleared when a new invocation arrived (only the
    in-app `successPR`/`successIssue` was reset on `toolInput` change). A completed
    result from a previous invocation could briefly render a stale success card
    over the next, still-deferred form.
    
    Clear `toolResult` whenever a new `tool-input` notification arrives. The spec
    guarantees `tool-input` precedes that invocation's `tool-result`, so this scopes
    the result to the current invocation centrally in the hook — fixing all three
    Views without per-app invocation keys.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(mcp-apps): remove show_ui — it can't suppress app rendering
    
    show_ui promised "skip the form and execute directly", but it can't deliver:
    the host renders an MCP App for any tool that carries _meta.ui.resourceUri, and
    the 2026-01-26 MCP Apps spec has no per-call/per-result way to opt out of
    rendering. show_ui only flipped the server's defer decision, so show_ui=false
    created the PR/issue up-front yet the host still rendered the app — exactly the
    contradiction this work set out to fix. And show_ui is only ever exposed to
    clients that support UI, i.e. precisely the clients that always render the app.
    
    Remove it entirely:
    - Drop the show_ui schema property, the form-param allowlist entry, and the
      showUI term from the defer predicate in create_pull_request and issue_write.
      The gate is now FF && clientSupportsUI && !_ui_submitted && !hasNonFormParams.
    - Delete the now-unused UI-only schema-property strip machinery in
      pkg/inventory (uiOnlySchemaProperties, stripUIOnlySchemaProperties,
      stripSchemaProperties) and the exported ConditionalSchemaPropertyDescriptions,
      which existed solely to surface show_ui to UI-capable clients. _meta.ui
      stripping is untouched.
    - Drop the conditional-property annotation from the docs generator.
    - Update toolsnaps, generated docs, and tests.
    
    With the up-front-execution Views now rendering the result (success card), the
    remaining contract is simple: when MCP Apps are enabled the form is the path,
    and the form is only shown while the action is genuinely deferred.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * refactor(mcp-apps): centralize the show/defer decision (single source of truth)
    
    The defer-to-form predicate was triplicated across create_pull_request,
    update_pull_request, and issue_write, each with its own near-identical
    *HasNonFormParams function. As more MCP App tools are added this duplication
    would grow and the copies could silently drift.
    
    Extract one shared gate in ui_capability.go:
    - shouldDeferToForm(ctx, deps, req, args, formParams) — the single show/defer
      decision (MCP Apps enabled, client supports UI, not a form submission, and no
      non-form params).
    - hasNonFormParams(args, formParams) — one generic helper replacing the three
      per-tool functions.
    - uiSubmitted(args) — small shared predicate.
    
    Each handler is now a one-line `if shouldDeferToForm(...) { return awaiting }`.
    The per-tool form-parameter allowlists and the user-facing messages stay
    per-tool (that is the genuine per-tool config). Pure refactor — behavior
    unchanged; existing tests now exercise the generic helper.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    SamMorrowDrums and Copilot authored Jun 26, 2026
    Configuration menu
    Copy the full SHA
    0503f2f View commit details
    Browse the repository at this point in the history
  5. Add issue dependency read/write MCP tools (#2751)

    * Add issue dependency read/write MCP tools
    
    Add two feature-flagged tools for issue blocked-by / blocking
    relationships, gated behind the issue_dependencies flag so they stay off
    the default tool surface (auto-enabled for insiders only):
    
    - issue_dependency_read: get_blocked_by / get_blocking via the
      Issue.blockedBy / Issue.blocking GraphQL connections, cursor-paginated.
    - issue_dependency_write: add / remove x blocked_by / blocking via the
      addBlockedBy / removeBlockedBy mutations. Accepts issue numbers and
      resolves them to node IDs in a single aliased query; "blocking" is the
      inverse of "blocked_by" with the subject/related roles swapped.
    
    Closes the MCP gap behind the gh CLI dependency verbs (cli/cli#13057).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Fail fast on self-dependency in issue_dependency_write
    
    Reject a write where the subject and related issue are identical before
    resolving node IDs or issuing a mutation, avoiding two API round-trips.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Revert addition of `any of` for required ui_get scopes
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    zwick and Copilot authored Jun 26, 2026
    Configuration menu
    Copy the full SHA
    067756a View commit details
    Browse the repository at this point in the history
  6. Fix delete:true on issue fields by calling deleteIssueFieldValue muta…

    …tion (#2755)
    
    * Fall back to REST DELETE when the PATCH can't carry an issue field clear
    
    The dotcom REST update endpoint uses set semantics for issue_field_values:
    sending {"issue_field_values": [...]} overwrites the whole list, and
    anything not in the new list is treated as a deletion. UpdateIssue
    already exploits this via merge-and-filter — delete:true on a field
    removes it from the kept list and the server clears it as a side effect.
    
    That breaks for one specific case: when the kept list ends up empty
    (e.g. you're deleting the only remaining field value, or every field in
    one call), go-github's omitempty tag on
    `IssueRequest.IssueFieldValues` strips the empty slice from the JSON
    body. The dotcom REST handler's top-level
    `if data.include?(ISSUE_FIELD_VALUES)` guard then short-circuits — the
    key isn't in the payload, so the whole block is skipped and the field
    keeps its old value. The MCP tool returns success regardless, so a
    coding agent would happily report the field as cleared.
    
    Detect this case in UpdateIssue and fall back to the dedicated REST
    DELETE endpoint per field: DELETE /repos/{owner}/{repo}/issues/{number}/
    issue-field-values/{field_id}. The endpoint is idempotent, takes the
    integer field ID (no GraphQL node ID needed), and is the same one the
    public OpenAPI documents.
    
    Empirical confirmation on #2756:
    
    - Set Priority=P1 via REST
    - Before the fix: MCP issue_write delete:true returns success, PATCH body
      on the wire is literally {}, Priority remains P1 (silent no-op).
    - After the fix: MCP issue_write delete:true returns success, PATCH body
      is still {}, but the follow-up DELETE clears the field. Priority is
      cleared as expected.
    
    Three new tests in issues_delete_test.go cover:
    
    - The omitempty contract (so we know if go-github ever drops the tag)
    - The 1-of-1 fallback path (PATCH body has no issue_field_values, DELETE
      fires)
    - The N-1 set-semantics path (kept list is non-empty, PATCH alone
      handles it, no DELETE call)
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address review: handle delete-absent-field and DELETE partial failures
    
    Two issues surfaced in code review of the original delete fix:
    
    1. Asking to delete a field that isn't set on the issue used to be a
       silent no-op (PATCH body is {} after omitempty stripping, server
       skips the issue_field_values block, tool returns success). The fix
       turned it into a hard error because the fallback DELETE loop fires
       unconditionally for every field ID in fieldIDsToDelete, and the
       dotcom DELETE endpoint returns 404 when the field has no value to
       delete. This breaks idempotent 'ensure field X is cleared' callers
       that may re-run the same delete on a field that's already been
       cleared.
    
       Fix: before queueing the fallback DELETEs, filter
       fallbackDeleteFieldIDs down to IDs that actually appeared in the
       existing field values. This preserves the pre-fix silent-no-op
       behaviour and avoids a guaranteed 404.
    
    2. The DELETE loop returned on the first error. If a caller asks to
       clear three fields and the second fails (transient 5xx, rate limit,
       etc.), the first is gone, the third is never attempted, and the
       user gets a generic error with no indication of which field failed
       or which had already succeeded. This is unrecoverable from the
       caller side.
    
       Fix: continue on per-field errors, accumulate the failed and
       succeeded IDs, and return a single aggregated error naming both
       sets so callers can retry the right fields.
    
    Tests:
    
    - Test_UpdateIssue_DeleteAbsentFieldIsNoOp: existing field values is
      empty, fieldIDsToDelete=[101]. Asserts no DELETE call fires (the
      mock returns 404 if it does, which would fail the test) and the
      tool returns success.
    
    - Test_UpdateIssue_DeleteFallbackContinuesOnPartialFailure: three
      fields exist, all three are deleted. Mock returns 500 for the
      middle DELETE, 204 for the others. Asserts all three DELETEs
      fired (the middle failure didn't short-circuit the third) and the
      error result names failed=[202] and cleared=[101 303].
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Slim down code comments in delete-fix region
    
    Trim the doc comments on UpdateIssue's omitempty-trap region + test
    file to the bare minimum needed to understand the non-obvious behaviour
    (why the DELETE fallback exists, why we filter to existing IDs, why
    errors are aggregated). Drop restated context and step-by-step
    explanations.
    
    No behaviour change.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    owenniblock and Copilot authored Jun 26, 2026
    Configuration menu
    Copy the full SHA
    29634da View commit details
    Browse the repository at this point in the history

Commits on Jun 27, 2026

  1. Add reaction tools for issues and pull requests (#2732)

    * Add reaction tools for issues and pull requests
    
    Implement three granular-only tools for adding emoji reactions:
    - add_issue_reaction: Add reaction to an issue
    - add_issue_comment_reaction: Add reaction to an issue comment
    - add_pull_request_review_comment_reaction: Add reaction to a PR review comment
    
    All tools are feature-flagged with FeatureFlagEnable set to enable them
    only when clients request granular toolsets. Tools use go-github's
    Reactions service and return minimal ID response on success (HTTP 201).
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Make reaction tools available in both granular and non-granular modes
    
    Remove feature flag gates from reaction tools so they're available to all
    clients regardless of granular toolset preference. Reaction tools are
    naturally atomic operations and work equally well in both modes.
    
    Updates test expectations to exclude reaction tools from granular-only
    test assertions, since they're now always available.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Update toolsnaps with aligned reaction tool descriptions
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Align reaction tool descriptions with codebase style
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Improve reaction tool responses and wording
    
    Return reaction URLs in minimal responses and clarify issue tools apply to pull requests where applicable.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Expose reactions through default comment tools
    
    Keep the standalone reaction tools behind granular feature flags to avoid expanding the default tool count. Add optional reaction support to the existing issue comment and pull request comment reply tools, requiring at least one of body or reaction.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Clarify PR review comment IDs for reactions
    
    Document that PR review comment reaction inputs require the numeric review comment ID, not the GraphQL review thread node ID returned by review thread APIs.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Support issue comment reactions in add_issue_comment
    
    Add optional comment_id support so the default add_issue_comment tool can react to a specific issue or pull request comment without exposing a separate default reaction tool. Keep body creation tied to issue_number and require reaction targets to provide either issue_number or comment_id.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Harden combined comment reaction tools
    
    Apply reactions before creating comments or replies so retrying a failed combined call cannot duplicate the non-idempotent comment operation.
    
    Also reject issue comment IDs without a reaction target to avoid silently ignoring the field.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Group reaction tools with granular registrations
    
    Keep standalone reaction tool registrations next to the granular issue and pull request tools they belong with, so the default compound tool sections stay focused.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Align granular reaction tool constructors
    
    Rename the standalone reaction tool constructors to match the granular tool naming convention and clarify issue comment reaction IDs for pull request comments.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Require issue number for comment reactions
    
    Make issue_number required on the consolidated add_issue_comment tool even when reacting to a specific issue comment, keeping the default tool input shape explicit.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Address issue comment feedback
    
    Return structured GitHub API errors for issue comment creation failures and assert MCP error results in tests.
    
    Also reject comment_id with body on the consolidated comment tool to avoid ambiguous comment-plus-comment-reaction requests.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Validate issue comment reaction target
    
    Use the required issue_number to verify issue comment reaction targets before creating the reaction, and remove overlapping add_issue_comment test coverage.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    * Validate positive comment IDs
    
    Reject non-positive issue and pull request comment IDs in handlers and add the missing schema minimum for pull request review comment IDs.
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
    Co-authored-by: Sam Morrow <sammorrowdrums@github.com>
    Co-authored-by: Sam Morrow <info@sam-morrow.com>
    4 people authored Jun 27, 2026
    Configuration menu
    Copy the full SHA
    8cd03c0 View commit details
    Browse the repository at this point in the history
Loading