feat(pull_requests): add MCP tools for GitHub Stacked PRs (#2905) - #2908
feat(pull_requests): add MCP tools for GitHub Stacked PRs (#2905)#2908ruhaanpathan wants to merge 3 commits into
Conversation
|
Thanks for working on this — native stacked-PR support would be genuinely useful for us. We use agents to maintain dependent, reviewable PRs in a monorepo and currently have to mark and resynchronise GitHub stacks manually. I tested this branch against current
I’d be happy to help rebase and update this. Would the author and maintainers prefer contributions to this branch, or a replacement PR preserving attribution? |
982b6e8 to
f8b2332
Compare
Use the 2026-03-10 native stack endpoints, consolidate the tool surface, and cover pagination, validation, scopes, and unstack outcomes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
f8b2332 to
0957ac6
Compare
|
There was a problem hiding this comment.
pkg/github/toolset_instructions.go
There was a problem hiding this comment.
🟡 Changes recommended
The documented tool contract does not match the implementation, and unsupported GHES hosts expose unusable tools.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (3)
pkg/github/pullrequests_stacks.go:198
- The documented exception is inaccurate: the native API leaves pull requests that are merged, currently merging, or queued for merge; a locked conversation is not the condition. This wording can make agents misinterpret a successful partial unstack, so please update it here and regenerate the matching toolsnap/README artifacts.
"`unstack` removes every removable unmerged pull request and may leave locked or queued pull requests in the stack. "+
pkg/github/pullrequests_stacks_test.go:154
- The fixture represents a merged pull request (
state: closedwithmerged_atset), not a locked pull request. Rename this subtest toremaining merged pull requestsso it documents the actual unstack behavior being tested.
t.Run("remaining locked pull requests", func(t *testing.T) {
pkg/github/toolset_instructions.go:23
- This instruction gives agents the wrong postcondition: merged, merging, or merge-queued pull requests can remain after
unstack, not locked pull requests. Please use the API's actual categories so agents correctly interpret and report the returned stack.
Stacked PRs workflow: Use 'pull_request_stack_read' to inspect native stack metadata. Use 'pull_request_stack_write' with method 'create' for 2-100 repository pull requests ordered bottom-to-top, 'add' only to append new pull requests above the current top, and 'unstack' to remove every removable unmerged pull request. Native stack operations require same-repository branches in an existing linear base/head chain; they do not create pull requests, retarget bases, rebase commits, push branches, or merge. After 'unstack', inspect the result because locked or queued pull requests can remain.`
- Files reviewed: 7/7 changed files
- Comments generated: 3
- Review effort level: Balanced
| "method": { | ||
| Type: "string", | ||
| Description: "The write operation: `create`, `add`, or `unstack`.", | ||
| Enum: []any{"create", "add", "unstack"}, |
| PullRequestStackRead(t), | ||
| PullRequestStackWrite(t), |
| PullRequestStackRead(t), | ||
| PullRequestStackWrite(t), |
Hide native stack tools and instructions on GHES, and conservatively label stack responses as repository user content. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: f37b1980-3ec0-4b4e-9795-c9d8b448555e
There was a problem hiding this comment.
🟡 Changes recommended
Resolve the API contract mismatch and prevent read-only instructions from naming an unavailable write tool.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
pkg/github/tools.go:292
- The registered MCP surface does not match this PR's stated contract: the description and tested prompts promise five tools named
get_stack,list_stacks,link_stack,update_stack, anddissolve_stack, but these lines expose only two grouped tools whose write methods arecreate,add, andunstack; there is no update/reorder/drop operation. Clients following the documented names and prompts cannot invoke this implementation. Either expose the promised names and semantics or revise the PR contract and prompts to the consolidated API before merge.
PullRequestStackRead(t, opts...),
PullRequestStackWrite(t, opts...),
- Files reviewed: 7/7 changed files
- Comments generated: 2
- Review effort level: Balanced
| - `repo`: Repository name (string, required) | ||
| - `threadId`: The node ID of the review thread (e.g., PRRT_kwDOxxx). Required for resolve_thread and unresolve_thread methods. Get thread IDs from pull_request_read with method get_review_comments. (string, optional) | ||
|
|
||
| - **pull_request_stack_read** - Read pull request stacks |
| if inventoryHasAvailableTool(inv, "pull_request_stack_read") { | ||
| instructions += ` | ||
|
|
||
| Stacked PRs workflow: Use 'pull_request_stack_read' to inspect native stack metadata. Use 'pull_request_stack_write' with method 'create' for 2-100 repository pull requests ordered bottom-to-top, 'add' only to append new pull requests above the current top, and 'unstack' to remove every removable unmerged pull request. Native stack operations require same-repository branches in an existing linear base/head chain; they do not create pull requests, retarget bases, rebase commits, push branches, or merge. After 'unstack', inspect the result because locked or queued pull requests can remain.` | ||
| } |
Summary
Adds 5 new MCP tools (
get_stack,list_stacks,link_stack,update_stack,dissolve_stack) to thepull_requeststoolset to support native GitHub Stacked PRs.Why
Agents managing stacked/dependent PRs currently lack a first-class way to discover, create, update, and dissolve native GitHub Stacked PR objects via MCP without needing host
ghCLI access.Fixes #2905
What changed
pkg/github/pullrequests_stacks.goimplementingget_stack,list_stacks,link_stack,update_stack, anddissolve_stack.pkg/github/tools.gounderToolsetMetadataPullRequests.generatePullRequestsToolsetInstructionsinpkg/github/toolset_instructions.gowith stacked PR guidance.pkg/github/pullrequests_stacks_test.go.MCP impact
Added
get_stack,list_stacks,link_stack,update_stack, anddissolve_stacktools under thepull_requeststoolset.Prompts tested (tool changes only)
get_stack(owner, repo, stackNumber: 10)list_stacks(owner, repo)link_stack(owner, repo, pullNumbers: [101, 102], base: "main")update_stack(owner, repo, stackNumber: 10, pullNumbers: [101, 102, 103])dissolve_stack(owner, repo, stackNumber: 10)Security / limits
Requires standard
repoOAuth scope matching other pull request management tools.Tool renaming
deprecated_tool_aliases.goLint & tests
./script/testAdded unit tests covering tool definitions, input schemas, and HTTP API execution handlers.
Docs
Updated toolset instructions for
pull_requests.