paperclipai/paperclip · warning · Error

Request body too large.

Error message

Request body too large.

What it means

The google-sheets MCP server reads the JSON body off the incoming HTTP request in readJsonBody and enforces a hard 1,000,000-byte (1 MiB) cap. As soon as the running sum of streamed chunk sizes crosses the limit it throws synchronously inside the async iterator, aborting the request before JSON.parse ever runs. This is a request-size DoS guard applied before any token validation or parsing.

Source

Thrown at packages/google-sheets-mcp-server/src/http.ts:44

    "content-type": "application/json",
    "content-length": Buffer.byteLength(payload),
  });
  res.end(payload);
}

function presentedToken(req: IncomingMessage): string | null {
  const header = req.headers.authorization;
  if (header?.startsWith("Bearer ")) return header.slice("Bearer ".length).trim();
  return null;
}

async function readJsonBody(req: IncomingMessage): Promise<unknown> {
  const chunks: Buffer[] = [];
  let size = 0;
  for await (const chunk of req) {
    const buffer = chunk as Buffer;
    size += buffer.length;
    if (size > 1_000_000) throw new Error("Request body too large.");
    chunks.push(buffer);
  }
  if (chunks.length === 0) return undefined;
  const raw = Buffer.concat(chunks).toString("utf8").trim();
  if (!raw) return undefined;
  return JSON.parse(raw);
}

async function handleMcp(
  req: IncomingMessage,
  res: ServerResponse,
  config: GoogleSheetsMcpConfig,
  client: GoogleSheetsClient,
): Promise<void> {
  let parsedBody: unknown;
  try {
    parsedBody = req.method === "POST" ? await readJsonBody(req) : undefined;
  } catch (error) {

View on GitHub (pinned to 67001ec6eb)

Solutions

  1. Split the payload into multiple smaller tool calls (paginate rows or batch ranges under 1 MiB).
  2. If the legitimate workload truly needs larger bodies, fork the server and raise the 1_000_000 literal in readJsonBody (there is no env override).
  3. Inspect the actual request size being sent by the client and trim redundant fields before sending.

Example fix

// before: one huge call
await tools.call('update_values', { range: 'A1:Z100000', values: giantMatrix });
// after: chunked calls
for (const chunk of chunkMatrix(giantMatrix, 5000)) {
  await tools.call('update_values', { range: chunk.range, values: chunk.values });
}
Defensive patterns

Strategy: validation

Validate before calling

function estimateJsonBytes(payload: unknown): number {
  return Buffer.byteLength(JSON.stringify(payload), 'utf8');
}
// before sending
if (estimateJsonBytes(args) > 1_000_000) throw new Error('payload would exceed 1MiB server cap');

Prevention

When it happens

Trigger: A client POSTs an MCP tools/call request to the google-sheets MCP HTTP endpoint whose body exceeds 1 MiB — e.g. a values_batch_update payload embedding a very large range or a tools/call with an oversized inline argument. The check fires per-chunk during the for-await loop over the IncomingMessage stream.

Common situations: Pushing a large spreadsheet range (many rows/columns) as inline values in a single tool call; an agent batching many writes into one request; a misconfigured client that serializes an entire sheet into one call.

Related errors


AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12). Data as JSON: /api/errors/79c1a2890206c0fc. Report an issue: GitHub.