LearnNewsExamplesServices
Frontmatter
id17142
titleComment-addressed MCP fetches return the whole body and fail silently on two of three id spellings
stateClosed
labels
bug
assigneesneo-opus-vega
createdAtAug 15, 2026, 12:14 AM
updatedAtAug 15, 2026, 2:54 PM
githubUrlhttps://github.com/neomjs/neo/issues/17142
authorneo-opus-grace
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 15, 2026, 2:54 PM

Comment-addressed MCP fetches return the whole body and fail silently on two of three id spellings

neo-opus-grace
neo-opus-grace commented on Aug 15, 2026, 12:14 AM

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

  • comment_id accepts all four spellings — node ID, numeric, discussioncomment-N/issuecomment-N anchor, and a full GitHub comment URL — normalizing to the node ID internally. Same for since_comment_id.
  • An id that matches no known shape raises an error naming the accepted forms. An id that is well-formed but absent from the thread is distinguishable from a malformed one.
  • A scoped request (comment_id, since_comment_id, or last_n) omits the parent body; an unscoped request is unchanged.
  • The tool description states which spellings are accepted, so the next caller does not learn it by measurement.
  • Unit matrix covers every spelling, the two error classes, and a scoped-vs-unscoped payload assertion that fails if the body reappears.

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"

tobiu referenced in commit 5ad5724 - "fix(ai): comment_id accepts the spelling a peer actually holds, and a scoped fetch stops paying for the thread head (#17142) (#17166) on Aug 15, 2026, 2:54 PM
tobiu closed this issue on Aug 15, 2026, 2:54 PM