MCP truncation at 2048 chars is invisible: tool `description` leaves no log, `/mcp` shows the untruncated text

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 3 comments · opened Jul 26, 2026

MCP instructions and tool description are silently truncated at 2048 chars

Version: 2.1.220 · Platform: macOS (darwin 25.5.0) · Transport: stdio

Summary

Claude Code truncates two MCP server-provided strings at 2048 characters before
they reach the model:

  1. InitializeResult.instructions
  2. every tool's description

Neither limit is part of the MCP specification — the spec types instructions as
an unbounded optional string, and reference SDKs impose no length cap. The
truncation is a client-side decision, and the server is never told it happened:
no error, no field in the response, no warning.

Truncation itself is defensible — these strings enter the system prompt of every
request. The bug is that it is invisible, and for tool descriptions it is
invisible everywhere.

Impact observed on one machine

502 truncation events across all MCP logs under
~/Library/Caches/claude-cli-nodejs/*/mcp-logs-*/*.jsonl.

Worst single case: 10780 → 2048 chars, an 81% loss.

Most affected servers include Anthropic's own connectors:

 87  claude-ai-Figma
 78  synapse-bridge      (ours)
 57  pencil
 39  claude-ai-<connector>
 23  claude-ai-<connector>

An operator has no reason to suspect this. In our case a 9029-character protocol
description had been silently reduced to 2048 for two months across 16 projects;
we found it only by grepping the client's own debug logs.

The two problems

1. Tool description truncation leaves no trace at all

instructions truncation at least writes a debug line:

{"debug":"Server instructions truncated from 9029 to 2048 chars",
 "timestamp":"2026-07-25T13:43:41.185Z","sessionId":"...","cwd":"..."}

Tool description has no equivalent log line. It is truncated at the same 2048
boundary with no record in the MCP log, no notice to the server, and no
indication to the user.

2. /mcp shows the full description; the model receives the truncated one

The value surfaced in the /mcp UI is the untruncated string, while the string
assembled into the API request is the truncated one. An author verifying their
tool description in /mcp sees text the model will never receive.

Reproduction

Minimal stdio MCP server, one tool, description of exactly 3000 characters with
distinct markers at the head and tail:

HEADMARK_DESC_A1S2D3 <2960 chars of filler> TAILMARK_DESC_P0O9I8

Connect it, then ask the model to quote the end of the tool's description.

Expected: the model can quote TAILMARK_DESC_P0O9I8.
Actual: the model quotes HEADMARK_DESC_A1S2D3, never sees the tail, and the
text it received ends mid-word at exactly character 2048. /mcp displays the full
3000 characters. Nothing appears in the MCP log.

The same procedure on InitializeResult.instructions truncates identically, but
does produce the debug line quoted above.

Requests, in order of value

  1. Log description truncation the way instructions truncation is already

logged. This alone would make the problem discoverable.

  1. Surface truncation in /mcp — mark a truncated field rather than

displaying the full text the model will not receive.

  1. Communicate the budget to the server. The cleanest fix: return the

per-field character budget in the initialize response, so a server can adapt
its own text rather than discovering the loss months later from logs.

  1. Make the limit configurable (env var or setting). Optional if 1–3 land —

with the loss visible, authors can fit the budget deliberately.

Prior art

  • #41593 — "MCP tool descriptions truncated at 2KB breaks code execution tools"

(opened 2026-03-31, closed 2026-05-06 as not planned by the stale bot, no
maintainer response). That report asked to raise or configure the limit and
documented a concrete failure mode: a code_executor tool whose description
embedded 60 function signatures had 45 of them cut, after which the model
hallucinated non-existent function names. Its author resorted to binary-patching
the constant (WoH=2048WoH=15e3) after every update. In 2.1.220 the same
constant is now D$=2048 — renamed, not removed.

  • #31302 — "MCP tool schemas with complex/nested properties are silently

truncated" (closed 2026-03-06).

This report is deliberately not a duplicate of #41593. It does not ask to raise
the limit. Truncating strings that enter every request's system prompt is a
reasonable policy. The ask here is that the truncation be observable — which is
strictly cheaper to implement, and is already half-done: instructions truncation
is logged, description truncation is not. Closing the asymmetry would have let
both #41593's author and us find the problem in minutes instead of months.

Notes

  • The limit counts UTF-16 code units (JS String.length), so the documented

phrasing "2KB each" is imprecise: 2048 Cyrillic characters are ~4096 bytes of
UTF-8, and astral-plane characters count as 2.

  • notifications/claude/channel params.content is not subject to this limit,

which is the workaround we adopted. Worth documenting explicitly, since it is
currently the only automatic path into context without a length cap.

View original on GitHub ↗

3 Comments

rilian · 20 days ago

was any solution found ?

koshak01 · 20 days ago

Server-side confirmation + the workaround we run, in case it helps before the fixes land.

We operate a Rust MCP server (rmcp) that bridges Claude Code sessions into a peer network — the same "16 projects / months of silent truncation" shape described here. Two things we do:

1. We fit instructions and every tool description into the 2048 budget ourselves, on the server. We treat 2048 as a hard cap and gate at an 1800-char safe threshold (margin for later wording tweaks). Anything past the safe threshold is logged loudly and trimmed/rejected by us — so we decide what survives instead of an invisible trailing cut. Today this is the only reliable defense, since description truncation has no log at all.

2. For content that must arrive whole, we don't use instructions — we push it through notifications/claude/channel. As the issue notes at the end, that content field is the one path into context with no length cap. Each peer's full profile / protocol doc (multi-KB) is delivered as channel-notification content, never stuffed into instructions. It lands complete every time.

So the pattern: keep instructions/description under 2048 by construction, and route anything larger through the uncapped channel content.

Strong +1 on the priority list — even just logging description truncation (item 1) would have turned a two-month invisible failure into a one-line grep.

rilian · 19 days ago

Fable suggested me to also include in my MCP server a tool "read-first" that would dynamically return long instructions, with the hope model pays more attention to it

I reported issue in Claude Support chat, hopefully this will speed up resolution...