Repository navigation
Cap the upstream response size of a tool call - #1279
Merged
Merged
Conversation
A single tool call could load an upstream body of any size. One JSON-RPC response of about 55 MB took some 2.6 s to parse and serialize, and the event loop served no other request in that time. The REST (also JSON-RPC and OData), GraphQL and SOAP engines now pass a limit to axios as maxContentLength. axios counts the decompressed bytes while it reads and stops at the limit, so an oversized body is never buffered in full. The outbound adapter restates axios' error as our own ResponseTooLargeError (code TOOL_RESPONSE_TOO_LARGE), whose message asks the model to narrow the request with filters, fewer fields or a limit. The limit is 10 MB by default on Cloud and self-hosted, and TOOL_MAX_RESPONSE_BYTES overrides it.
helpcodeai
enabled auto-merge (squash)
October 26, 2026 12:52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A tool call could load an upstream response of any size. In production one JSON-RPC call (
odoo_search_read) returned about 55 MB. Parsing and serializing it blocked the Node event loop for about 2.6 s, and every other request waited.This PR caps the upstream response body a tool call reads. The default is 10 MB.
TOOL_MAX_RESPONSE_BYTESchanges it. When a body is larger, the call fails with our own error and does not load the body.How it works:
maxContentLengthfromtoolMaxResponseBytes().Content-Lengthdoes not help, and a gzip body is counted after decompression.common/outbound-http.ts. The adapter turns axios'maxContentLength size of N exceededinto aResponseTooLargeErrorwith codeTOOL_RESPONSE_TOO_LARGE. It has no HTTP status, so the model and the call log can tell it apart from an upstream error. The message says what to do: add filters, ask for fewer fields, set a lower limit or page size, or fetch smaller pages.maxContentLength. Today only the tool engines do, so token, login, spec import and alert requests behave as before.What the MCP client sees:
{ "error": "The API response is larger than 10 MB, the limit for one tool call, so AnythingMCP stopped reading it and returned nothing. Narrow the request: add filters, ask for fewer fields, set a lower limit or page size, or fetch the data in smaller pages. An administrator can raise the limit with TOOL_MAX_RESPONSE_BYTES.", "code": "TOOL_RESPONSE_TOO_LARGE" }Cloud and self-hosted: same behavior and same 10 MB default in both. The env var is passed through in
docker-compose.ymlanddocker-compose.cloud.yml. An empty or invalid value falls back to the default.Why 10 MB: it matches the existing 10 MB caps (
OUTBOUND_FETCH_DEFAULTS.maxBytesfor file downloads andHARD_MAX_BINARY_BYTESfor attached files). So no file that could be attached today is lost.Why there is no second cap on the text sent to the MCP client: the rendered text comes from a body that is now at most 10 MB. A second limit on the pretty-printed text would either fail responses that passed the first limit (pretty printing adds whitespace) or repeat it. The opt-in
responseMapping.transform.maxBytesstill shapes output per tool.Changes
packages/backend/src/common/response-size-limit.ts(new): default, env reader,ResponseTooLargeError,restateResponseTooLarge.packages/backend/src/common/outbound-http.ts: the adapter restates axios' size error.packages/backend/src/connectors/engines/rest.engine.ts,graphql.engine.ts,soap.engine.ts: setmaxContentLength. SOAP passes the error through instead of wrapping it.common/response-size-limit.spec.ts,connectors/engines/response-size-limit.engines.spec.ts(real local HTTP server through each engine), one case inmcp-server/dynamic-mcp-tools.spec.tsfor the tool result..env.example,docs/deployment.mdenv table,docs/tool-definition.md(howtransform.maxBytesandbinary.maxBytesrelate to the new limit). Compose files pass the variable through.Behavior changes to note:
$metadatadocument requested through a tool now fails above 10 MB. An operator can raise the limit.Not covered here (possible follow-ups): the MCP client engine (proxy to a remote MCP server) reads through the MCP SDK with
fetch, and database engines already cap rows at 1000 (MAX_ROWS). Neither goes through axios.Type
Testing
The engine spec runs a real HTTP server on 127.0.0.1 and covers: a 1 MB JSON-RPC body passes under the default; an 11 MB body fails with
ResponseTooLargeErrorand the 10 MB message;TOOL_MAX_RESPONSE_BYTESlowers and raises the limit; a body exactly at the limit passes and one byte less fails; a gzip body is counted after decompression; GraphQL and SOAP pass under the limit and fail over it. I checked that the REST cases fail when themaxContentLengthline is removed (4 of the 5 failed, as expected).Commands and results (Node v22, macOS):
packages/backendDATABASE_URL=postgresql://u:p@localhost:5433/x npx prisma generatepackages/backendnpm run lintpackages/backendnpx tsc --noEmit -p tsconfig.jsonpackages/backendnpm testnode scripts/validate-adapters.mjs --warnNo baseline failures.
Checklist
npm test)Related Issues
No issue. The maintainer approved a cap on tool response size after the production incident above. No Prisma schema change, no auth change, nothing under
ee/.