{"record":{"id":"448ced457321469c","repo":"RocketChat/Rocket.Chat","slug":"mcp-tool-response-exceeds-the-5-mib-limit","errorCode":null,"errorMessage":"MCP tool response exceeds the 5 MiB limit","messagePattern":"MCP tool response exceeds the 5 MiB limit","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/ee/server/api/mcp/dispatch.ts","lineNumber":39,"sourceCode":"export const createMcpResponseBudget = (maxBytes = MAX_TOOL_RESPONSE_BYTES): McpResponseBudget => {\n\tlet remainingBytes = maxBytes;\n\tconst formattedLimit = formatByteLimit(maxBytes);\n\n\treturn {\n\t\tconsume(bytes) {\n\t\t\tif (bytes > remainingBytes) {\n\t\t\t\tthrow new Error(`MCP batch response exceeds the ${formattedLimit} limit`);\n\t\t\t}\n\n\t\t\tremainingBytes -= bytes;\n\t\t},\n\t};\n};\n\nconst readResponseText = async (response: Response, responseBudget?: McpResponseBudget): Promise<string> => {\n\tconst contentLength = Number(response.headers.get('content-length'));\n\tif (Number.isFinite(contentLength) && contentLength > MAX_TOOL_RESPONSE_BYTES) {\n\t\tthrow new Error('MCP tool response exceeds the 5 MiB limit');\n\t}\n\n\tif (!response.body) {\n\t\treturn '';\n\t}\n\n\tconst reader = response.body.getReader();\n\tconst decoder = new TextDecoder();\n\tconst chunks: string[] = [];\n\tlet receivedBytes = 0;\n\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) {\n\t\t\tbreak;\n\t\t}\n\n\t\treceivedBytes += value.byteLength;","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/ee/server/api/mcp/dispatch.ts#L21-L57","documentation":"Fast-fail guard in readResponseText: before reading the body of the loopback REST response for an MCP tool call, it parses the content-length header and throws when the declared size already exceeds MAX_TOOL_RESPONSE_BYTES (5 MiB). The oversized single-tool response is rejected without transferring its body.","triggerScenarios":"dispatchTool fetches the REST endpoint behind an MCP tool and that endpoint declares content-length greater than 5,242,880 bytes (e.g. a list endpoint returning thousands of records because no count was passed).","commonSituations":"Tools mapped to export/list endpoints that ignore pagination params; test workspaces seeded with large datasets queried without a count; tool args not forwarded to the REST query.","solutions":["Call the tool with stricter pagination args (count/offset) so the response stays under 5 MiB","Use a narrower filter or a tool that returns summaries instead of full objects","Return a reference (file URL, export job id) instead of inline bulk data"],"exampleFix":"// before\nconst result = await callTool('channels_list', {}); // full dataset, content-length > 5 MiB\n\n// after\nconst result = await callTool('channels_list', { count: 100, offset: 0 });","handlingStrategy":"validation","validationCode":"const response = await fetch(url);\nconst contentLength = Number(response.headers.get('content-length'));\nif (Number.isFinite(contentLength) && contentLength > 5 * 1024 * 1024) {\n  throw new Error('tool response would exceed 5 MiB - narrow the query (count/offset)');\n}\nconst text = await response.text();","typeGuard":null,"tryCatchPattern":"try {\n  return await callTool(name, args);\n} catch (error) {\n  if (error instanceof Error && error.message.includes('MCP tool response exceeds the 5 MiB limit')) {\n    return callTool(name, { ...args, count: Math.min(args.count ?? 100, 100) });\n  }\n  throw error;\n}","preventionTips":["Always send pagination params when calling list-type tools","Test MCP tools against a heavily populated workspace before shipping","Map only paginated REST endpoints to MCP tools"],"tags":["mcp","http","content-length","payload-limit"],"backgroundTag":"payload-too-large","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}