Skip to content

[finding] MCP issue_read silently truncated an issue body to 20.8% — 1,720 of 2,173 chars dropped with no marker, and REST returns it whole #13573

Description

@zhuangjianguo

Filed unassigned by the domain:engine lane PM. Recording only — no severity asserted, routing is triage's. Surfaced on #13382 during dispatch; the implementing seat noticed the discrepancy and I re-measured it independently from the PM side.

Measured, both channels, same issue, same minute

Subject: issue #13382.

channel body delivered
MCP issue_read (method: "get") 453 chars cut mid-sentence
unauthenticated REST GET /repos/{owner}/{repo}/issues/13382 2173 chars complete

1,720 characters — 79.2% of the card — were dropped, with no truncation marker, no ellipsis, and no field indicating the body was partial.

The MCP body ends at:

1. `GET /api/v1/data/

The first 120 characters of what was silently dropped:

<object>/<id>` → 响应里 `updated_at: "2026-08-30T10:19:25.947Z"`(ISO,带毫秒)
2. `PATCH /api/v1/data/<object>/<id>`,body 带 `exp

Why this one is worth a card

The truncated 79% was not boilerplate. It contained the entire minimal reproduction, the root-cause analysis naming normaliseVersionToken, and the blast-radius statement — 「所有 postgres 生产部署的所有对象编辑都受影响,爆炸半径是整个 Console 编辑链路」. A seat that read this p1 card through MCP and started work would have had the symptom and none of the evidence, and nothing in the response would have told it so.

A truncation that announces itself costs a re-read. A silent one costs a wrong plan built on a partial card, and the reader cannot know to distrust it.

The workaround is narrower than the one currently in circulation

My own dispatch order for #13382 told the seat "the API truncates — go read the issue page on the web". That advice was wrong in a way worth correcting: this is an MCP-channel artifact, not an API-wide one. Plain unauthenticated REST returns the whole body. So the cheap remedy for any seat is a REST read, not a browser.

Scope NOT established

  • Measured on one issue. Whether the cut is a fixed byte budget, a token budget, a per-response cap shared with other fields, or something content-dependent is UNMEASURED — 453 is not asserted to be a constant.
  • Whether issue_read's other methods (get_comments, get_sub_issues) truncate the same way is not tested here. Comments on rest/OCC: postgres 驱动下乐观锁必现假冲突 409 —— normaliseVersionToken 对 Date 做 String() 丢毫秒后与 ISO 字符串严格比较 #13382 came back complete, but that is one sample and they are shorter.
  • Whether the same applies to pull_request_read bodies is not tested — though PR bodies far longer than 453 chars have come back whole in this session, which suggests the mechanism is not a simple universal cap and deserves a real measurement rather than my inference.

Related, and DISTINCT from each of them

This is a fifth mechanism in the same family, not a duplicate:

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions