[BUG] MCP tool ImageContent is duplicated into structuredContent and injected as text (~25K-token truncation), despite the image also rendering natively
Related to #31208 (closed as stale + locked; the auto-bot said to file a new issue and reference it). Same root cause, now with protocol-level proof and a controlled A/B repro.
What's wrong
When an MCP tool returns an ImageContent block, Claude Code renders the image natively (good) but also serializes the tool result's structuredContent into the model context as text — and for such tools structuredContent contains the image's base64. So the model receives the full base64 as text on top of the rendered image, blowing past the ~25,000-token tool-output cap and triggering [OUTPUT TRUNCATED - exceeded 25000 token limit], plus large context waste.
Why structuredContent contains the base64
FastMCP auto-enables structured output from a tool's return type annotation (e.g. -> list[ImageContent | TextContent]) and copies the return value (including the base64) into structuredContent; the MCP spec also mandates a backward-compat text mirror. Claude Code feeds that text (with base64) to the model instead of de-duplicating against the already-rendered image block.
Evidence
- Cross-client: claude.ai web handles the identical server correctly (renders image + a small text block, no base64 text, no truncation). Claude Code (VSCode extension and CLI) dumps the base64 as text and truncates.
- Protocol-level: the raw
CallToolResultshowscontentcarries the image block's base64 andstructuredContentseparately carries the same base64 (a multi-hundred-KB string). - Controlled A/B (same Claude Code CLI client): two identical servers — one with structured output ON → truncation + base64-as-text; one with
structured_output=False→ clean (image still renders). The only difference is structured output.
| server | truncated | base64-as-text | image rendered |
|---|---|---|---|
| structured output ON | yes | yes | yes |
| structured_output=False | no | no | yes |
Expected
When a tool result has image content blocks and a structuredContent that embeds the same image data, Claude Code should render the image natively and not inject the base64 as text. More generally, don't serialize large binary data fields from structuredContent into the model's text context.
Server-side workaround (not a real fix)
Set structured_output=False on image-returning FastMCP tools (or drop the return annotation). But this requires every server author to know about it; the proper fix is client-side.
Environment
Claude Code 2.1.170; reproduced on both the VSCode extension and the CLI.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗