{"record":{"id":"1822c458e32f843c","repo":"paperclipai/paperclip","slug":"request-body-too-large-1822c4","errorCode":null,"errorMessage":"Request body too large.","messagePattern":"Request body too large\\.","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/kv-demo-mcp-server/src/http.ts","lineNumber":52,"sourceCode":"    \"content-type\": \"text/html; charset=utf-8\",\n    \"content-length\": Buffer.byteLength(html),\n  });\n  res.end(html);\n}\n\nfunction presentedToken(req: IncomingMessage): string | null {\n  const header = req.headers.authorization;\n  if (header && header.startsWith(\"Bearer \")) return header.slice(\"Bearer \".length).trim();\n  return null;\n}\n\nasync function readJsonBody(req: IncomingMessage): Promise<unknown> {\n  const chunks: Buffer[] = [];\n  let size = 0;\n  for await (const chunk of req) {\n    const buffer = chunk as Buffer;\n    size += buffer.length;\n    if (size > 1_000_000) throw new Error(\"Request body too large.\");\n    chunks.push(buffer);\n  }\n  if (chunks.length === 0) return undefined;\n  const raw = Buffer.concat(chunks).toString(\"utf8\").trim();\n  if (!raw) return undefined;\n  return JSON.parse(raw);\n}\n\nasync function handleMcp(\n  req: IncomingMessage,\n  res: ServerResponse,\n  store: KvStore,\n): Promise<void> {\n  // Stateless: a fresh MCP server + transport per request. The shared store is\n  // what carries state between calls, so no session bookkeeping is needed.\n  let parsedBody: unknown;\n  try {\n    parsedBody = req.method === \"POST\" ? await readJsonBody(req) : undefined;","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/kv-demo-mcp-server/src/http.ts#L34-L70","documentation":"Identical guard to the google-sheets server: readJsonBody in the kv-demo MCP HTTP layer caps total streamed body at 1,000,000 bytes and throws mid-stream. The kv-demo store API is small but the same cap applies to MCP requests and to bulk set operations.","triggerScenarios":"Any request to the kv-demo HTTP endpoint whose body exceeds 1 MiB — typically a POST /api/state with a very large value, a bulk set, or an MCP tools/call with oversized arguments.","commonSituations":"Storing a large blob (image base64, big JSON document) as a single KV value; a client retrying with an ever-growing payload.","solutions":["Store the large value out-of-band and keep only a reference in the KV store.","Chunk the value across multiple keys.","If genuinely needed, fork and raise the 1_000_000 literal."],"exampleFix":"// before\nawait set('big', hugeJsonString)  // > 1MiB -> error\n// after\nawait set('big.ref', uploadLargeBlobElsewhere(hugeJsonString))","handlingStrategy":"validation","validationCode":"function under1MiB(payload: unknown): boolean {\n  return Buffer.byteLength(JSON.stringify(payload), 'utf8') <= 1_000_000;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep KV values small — store large blobs externally and keep references.","Estimate body size client-side before POSTing to /api/state.","Treat the 1 MiB cap as a fixed contract."],"tags":["http","request-size-limit","dos-guard","kv-demo-mcp"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}