Skip to content

Return closing pull requests from issue_read - #3006

Draft
zwick wants to merge 2 commits into
mainfrom
zwick-issue-read-closed-by-prs
Draft

Return closing pull requests from issue_read#3006
zwick wants to merge 2 commits into
mainfrom
zwick-issue-read-closed-by-prs

Conversation

@zwick

@zwick zwick commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

issue_read with method=get now returns closed_by_pull_requests, a compact summary of the pull requests configured to close the issue, sourced from the GraphQL Issue.closedByPullRequestsReferences field.

Why

Answering "is there a PR that closes this issue?" previously meant listing up to 100 pull requests and grepping their bodies for closing keywords. That burns a large token budget and misses cross-repo and non-body links. GraphQL already models this relationship directly.

Tracking issue: github/plan-track-agentic-org#192

What changed

  • Added closedByPullRequestsReferences(first: 5, includeClosedPrs: true, orderByState: true) with totalCount to the existing issueReadEnrichmentQuery, so the answer arrives in the same round-trip as the hierarchy signals. No new tool, no extra API call.
  • Response shape is { "total_count": N, "references": [...] }. At most 5 references are embedded because this enrichment runs on every get; total_count is authoritative, so the rare issue with more linked PRs is never read as a complete list. Truncation is derivable from total_count > len(references), so no redundant flag is emitted.
  • MinimalIssue.ClosedByPullRequests is a pointer: an enriched issue with no closing PRs still serializes a definitive total_count: 0, while list/search paths that never enrich omit the key entirely.
  • Generalized isSafeParentContent into isSafeRefContent and reused it to filter closing PR references under lockdown.

includeClosedPrs is required because it defaults to false and hides merged and closed PRs, which are exactly what answers "which PR closed this?". orderByState keeps open PRs ahead of the cap.

MCP impact

  • Tool schema or behavior changed — issue_read get gains a closed_by_pull_requests key; the method description was updated and the toolsnap regenerated.

Prompts tested (tool changes only)

Drove the built server over stdio against the live API:

  • "Is there a PR that closes this issue?" — open closing PR returned as state: OPEN.
  • Same issue after the PR merged — returned as state: MERGED, so the retrospective "which PR closed this?" case works.
  • github/github-mcp-server#1 — returned PR fix: detect ungraceful stdin close and self-terminate #2325 with state: CLOSED (unmerged), which the default GraphQL args would have hidden.
  • An issue with no linked PR — returned total_count: 0, references: [].
  • An issue with 7 linked PRs — returned total_count: 7 with 5 open references, confirming truncation is visible.

Security / limits

  • Data exposure, filtering, or token/size limits considered — closing PR titles are sanitized because they can originate from another repository; under lockdown, references whose author cannot be verified as safe content are omitted, matching the existing parent reference behavior. Capped at 5 embedded references to keep the always-on enrichment cheap.

Tool renaming

  • I am not renaming tools as part of this PR

Lint & tests

  • Linted locally with ./script/lint
  • Tested locally with ./script/test

Table-driven coverage for populated results (including a cross-repo PR), empty results, truncation, title sanitization, lockdown filtering, and the enrichment-failure path.

Docs

  • Updated (README / docs / examples) — regenerated via script/generate-docs.

zwick and others added 2 commits August 3, 2026 15:24
Answering "is there a PR that closes this issue?" previously required
listing pull requests and grepping their bodies for closing keywords,
which is expensive and unreliable. GraphQL already exposes
Issue.closedByPullRequestsReferences.

Add it to the existing issue_read `get` enrichment query so the answer
comes back in the same round-trip as the hierarchy signals, as a compact
`closed_by_pull_requests` list. An enriched issue with no closing pull
requests serializes an explicit empty list so an agent can stop looking.

Lockdown mode filters references whose author cannot be verified as safe
content, mirroring the existing parent reference handling.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a0b58914-0d94-47a9-8229-c0ef7e32e69f
This enrichment runs on every issue_read get, so embedding up to 25
references costs more than the common case is worth. Embed at most 5,
keeping orderByState so open pull requests are the ones that survive.

Select totalCount alongside the nodes and return the summary as an
object of total_count plus references, so the rare issue with more than
five linked pull requests cannot be read as a complete list. The common
zero-to-two case stays compact and an empty result stays definitive.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a0b58914-0d94-47a9-8229-c0ef7e32e69f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant