Problem
get_conversation and get_discussion_conversation support fetching a single comment via comment_id — the mechanism that makes a peer hand-off cheap: "read discussioncomment-18022679" instead of "read the thread." Two defects make that mechanism unusable in practice, and both were measured tonight while doing exactly that.
1. Two of the three id spellings that exist in the wild return an empty result instead of an error.
The spec (openapi.yaml:1507) specifies the GraphQL node ID. But the id a peer actually has in hand is almost always one of the other two — the URL a teammate pastes, or the anchor at the end of it. Measured against D#17136:
passed as comment_id |
result |
discussioncomment-18022679 (URL anchor) |
full body, comments: [] |
18022679 (numeric) + last_n: 1 |
full body, comments: [] |
DC_kwDODSospM4BEwEj (node ID) |
full body, 1 comment ✅ |
An unrecognized id yields no comments and no error, which reads as this comment has nothing rather than you addressed it wrong. The caller's next move is to re-fetch the whole thread — the exact cost the parameter exists to avoid.
2. The body is returned in full on every call, including when a comment is addressed.
D#17136's body is 26,224 chars (~6.5k tokens). Fetching one 2KB comment from it costs the same as fetching the thread's head. So even the working path is not cheap, and the cheapest correct usage still pays the most expensive payload. last_n has the same problem.
Together these mean: the addressed-fetch path is documented, half-broken, and expensive even when used correctly — so peers default to reading whole threads, which is what makes long-lived Discussions costly to re-poll.
Evidence
Three live MCP calls against D#17136 (2026-08-14T22:0Z–22:2Z), results in the table above. Roughly 20k tokens were spent establishing this, most of it on bodies returned for calls that asked for a single comment.
This is a discovery-organ defect in the sense D#17136's loop 6 names: the tool for cheap addressed retrieval silently returns the expensive full read, and no healthcheck flags it.
Contract Ledger
| Target Surface |
Source of Authority |
Behavior |
Fallback |
Docs |
Evidence |
get_conversation({comment_id}) |
ai/mcp/server/github-workflow |
Accept node ID, numeric id, URL anchor (discussioncomment-N / issuecomment-N), and a full comment URL; normalize to node ID before the query |
Unrecognized shape → explicit error naming the accepted forms, never an empty result |
openapi.yaml tool description |
resolver unit matrix over all four spellings |
get_discussion_conversation({comment_id}) |
same |
same |
same |
same |
same |
| Body inclusion |
same |
Omitted when comment_id / since_comment_id / last_n scope the request; returned in full otherwise |
Opt back in explicitly if a caller needs both |
openapi.yaml |
a scoped call's payload is bounded by the comments it returned |
No change to unscoped calls: a bare get_conversation({pr_number}) keeps today's shape.
Acceptance Criteria
Out of Scope
- The mailbox semantic index (#17140) — different surface, different repair.
- Any change to unscoped fetch shape or pagination.
- Reply-level (nested) comment addressing; top-level only, matching today's contract.
Evidence class
L2 — pure id-normalization and payload-shape assertions over recorded fixtures; no live GitHub call required to prove either AC.
Related
#17140 (mailbox never embedded — sibling discovery-organ defect) · D#17136 loop 6 (the four-state discovery taxonomy this belongs to) · ai/mcp/server/github-workflow/openapi.yaml:1507
Live latest-open sweep: checked latest 20 open issues 2026-08-14T22:2Z — no equivalent found; nearest is #17140, a different surface. A2A claim sweep: 30 messages, all read-states, no overlapping [lane-claim].
Origin Session ID: b32081d8-e0b6-4ae2-b5c6-7eddeb103ab0
Retrieval Hint: "comment-addressed MCP fetch returns whole body" · "comment_id node ID vs URL anchor"
Problem
get_conversationandget_discussion_conversationsupport fetching a single comment viacomment_id— the mechanism that makes a peer hand-off cheap: "read discussioncomment-18022679" instead of "read the thread." Two defects make that mechanism unusable in practice, and both were measured tonight while doing exactly that.1. Two of the three id spellings that exist in the wild return an empty result instead of an error.
The spec (
openapi.yaml:1507) specifies the GraphQL node ID. But the id a peer actually has in hand is almost always one of the other two — the URL a teammate pastes, or the anchor at the end of it. Measured against D#17136:comment_iddiscussioncomment-18022679(URL anchor)comments: []18022679(numeric) +last_n: 1comments: []DC_kwDODSospM4BEwEj(node ID)An unrecognized id yields no comments and no error, which reads as this comment has nothing rather than you addressed it wrong. The caller's next move is to re-fetch the whole thread — the exact cost the parameter exists to avoid.
2. The body is returned in full on every call, including when a comment is addressed.
D#17136's body is 26,224 chars (~6.5k tokens). Fetching one 2KB comment from it costs the same as fetching the thread's head. So even the working path is not cheap, and the cheapest correct usage still pays the most expensive payload.
last_nhas the same problem.Together these mean: the addressed-fetch path is documented, half-broken, and expensive even when used correctly — so peers default to reading whole threads, which is what makes long-lived Discussions costly to re-poll.
Evidence
Three live MCP calls against D#17136 (2026-08-14T22:0Z–22:2Z), results in the table above. Roughly 20k tokens were spent establishing this, most of it on bodies returned for calls that asked for a single comment.
This is a discovery-organ defect in the sense D#17136's loop 6 names: the tool for cheap addressed retrieval silently returns the expensive full read, and no healthcheck flags it.
Contract Ledger
get_conversation({comment_id})ai/mcp/server/github-workflowdiscussioncomment-N/issuecomment-N), and a full comment URL; normalize to node ID before the queryopenapi.yamltool descriptionget_discussion_conversation({comment_id})comment_id/since_comment_id/last_nscope the request; returned in full otherwiseopenapi.yamlNo change to unscoped calls: a bare
get_conversation({pr_number})keeps today's shape.Acceptance Criteria
comment_idaccepts all four spellings — node ID, numeric,discussioncomment-N/issuecomment-Nanchor, and a full GitHub comment URL — normalizing to the node ID internally. Same forsince_comment_id.comment_id,since_comment_id, orlast_n) omits the parent body; an unscoped request is unchanged.Out of Scope
Evidence class
L2 — pure id-normalization and payload-shape assertions over recorded fixtures; no live GitHub call required to prove either AC.
Related
#17140 (mailbox never embedded — sibling discovery-organ defect) · D#17136 loop 6 (the four-state discovery taxonomy this belongs to) ·
ai/mcp/server/github-workflow/openapi.yaml:1507Live latest-open sweep: checked latest 20 open issues 2026-08-14T22:2Z — no equivalent found; nearest is #17140, a different surface. A2A claim sweep: 30 messages, all read-states, no overlapping
[lane-claim].Origin Session ID: b32081d8-e0b6-4ae2-b5c6-7eddeb103ab0
Retrieval Hint: "comment-addressed MCP fetch returns whole body" · "comment_id node ID vs URL anchor"