Problem
MCP tool results are passed into the model's context uncapped. A single oversized result β e.g. an agent running cat on a multi-MB build or job log through an SSH/exec MCP server β can exceed the model's entire context window. The next completion request is then rejected by the provider (in our case an OpenAI-compatible endpoint returned 400 with ~4.37M prompt tokens against a 131k-context model) and the turn is lost.
Built-in tools already handle this: their output goes through truncateOutput (see #2835, where one built-in tool missing that call was fixed as a bug). MCP tool results have no equivalent β there is no truncation path and no config knob for it. Checked against the config schema on current main: the only related knobs are the ls tool's max_depth/max_items and per-model max_tokens, neither of which bounds an MCP result. #824 looks like the same failure mode reported from the provider side ("probably some tool returned a large result").
Server-side caps can't be assumed: most third-party MCP servers return unbounded results, and users can't patch every server they connect. The client is the natural last line of defense, same as it already is for built-in tools.
Proposal
A config option to cap MCP tool result size before it is added to context β ideally settable globally with per-server override, e.g.:
{
"mcp": {
"myserver": {
"type": "stdio",
"command": "...",
"max_tool_result_bytes": 131072
}
}
}
On overflow, keep the head (~75%) and tail (~25%) of the cap and insert a marker in between stating how much was dropped, e.g.:
[... 41.2 MB truncated (returned first 96 KB + last 32 KB). Narrow the command with head/tail/grep, or write to a file and sample it. ...]
The head+tail+marker shape matters: head keeps the command banner/first errors, tail keeps the final error/exit summary, and the marker teaches the model to self-correct with a narrower command on the next call instead of retrying the same one.
Prior art
We implemented exactly this server-side in an SSH MCP server (enkiEng/mcp-ssh-go#1 β bounded head + ring-buffer tail, per-call override, inline marker) and it works well: the model reliably narrows its next command when it hits the marker. But that only protects one server; a client-side cap would cover every MCP server crush connects to.
Problem
MCP tool results are passed into the model's context uncapped. A single oversized result β e.g. an agent running
caton a multi-MB build or job log through an SSH/exec MCP server β can exceed the model's entire context window. The next completion request is then rejected by the provider (in our case an OpenAI-compatible endpoint returned 400 with ~4.37M prompt tokens against a 131k-context model) and the turn is lost.Built-in tools already handle this: their output goes through
truncateOutput(see #2835, where one built-in tool missing that call was fixed as a bug). MCP tool results have no equivalent β there is no truncation path and no config knob for it. Checked against the config schema on current main: the only related knobs are the ls tool'smax_depth/max_itemsand per-modelmax_tokens, neither of which bounds an MCP result. #824 looks like the same failure mode reported from the provider side ("probably some tool returned a large result").Server-side caps can't be assumed: most third-party MCP servers return unbounded results, and users can't patch every server they connect. The client is the natural last line of defense, same as it already is for built-in tools.
Proposal
A config option to cap MCP tool result size before it is added to context β ideally settable globally with per-server override, e.g.:
{ "mcp": { "myserver": { "type": "stdio", "command": "...", "max_tool_result_bytes": 131072 } } }On overflow, keep the head (~75%) and tail (~25%) of the cap and insert a marker in between stating how much was dropped, e.g.:
The head+tail+marker shape matters: head keeps the command banner/first errors, tail keeps the final error/exit summary, and the marker teaches the model to self-correct with a narrower command on the next call instead of retrying the same one.
Prior art
We implemented exactly this server-side in an SSH MCP server (enkiEng/mcp-ssh-go#1 β bounded head + ring-buffer tail, per-call override, inline marker) and it works well: the model reliably narrows its next command when it hits the marker. But that only protects one server; a client-side cap would cover every MCP server crush connects to.