
# Request Limits

> Bounded bodies and strict content types, before anything is parsed.

Every JSON-RPC `POST` is bounded before its body is read: at most 4 MiB, `Content-Type: application/json`. Both checks run after [origin](/security/origin) and [auth](/security/auth) — cheap header checks first — and before any parsing.

```ts
defineMcpHandler({
  name: "my-server",
  version: "1.0.0",

  limits: {
    maxBodySize: 1024 * 1024, // bytes (default: 4 MiB); `false` for unbounded
    contentType: ["application/json"], // default; `false` to accept any type
  },

  tools: [/* ... */],
});
```

## Responses

| Request                                 | Response |
| --------------------------------------- | -------- |
| Body larger than `maxBodySize`          | `413`    |
| Missing `Content-Type`                  | `400`    |
| Malformed `Content-Type`                | `422`    |
| `Content-Type` not in the accepted list | `415`    |

The rejection messages are static — a bad `Content-Type` is never echoed back to the sender.

## Never Fully Buffered

An oversized body is rejected up front when `Content-Length` declares it, and otherwise aborted **as it is read**, so a lying-small `Content-Length` on a chunked upload is still caught mid-stream. The body is never accumulated in memory just to measure it.

Only the request body is bounded, so a [`subscriptions/listen`](/guide/modern/subscriptions) POST — small body, long-lived response stream — is unaffected. `GET` and `DELETE` carry no body and skip both checks.

## Disabling

```ts
defineMcpHandler({
  name: "my-server",
  version: "1.0.0",
  limits: false,
  tools: [/* ... */],
});
```

Or relax one half only:

```ts
limits: {
  maxBodySize: false;
} // unbounded body, still application/json only
limits: {
  contentType: false;
} // any content type, still 4 MiB
```

> [!WARNING]
> `limits: false` makes the endpoint accept an unbounded body of any type. If something upstream already enforces limits, fine — otherwise this is the easiest denial-of-service vector an MCP endpoint has, because a single POST can consume memory before any of your code runs.

## Sizing the Limit

4 MiB is generous for JSON-RPC. Tighten it to what your largest legitimate request needs — a tool that accepts a pasted document may need a few hundred KiB; one that takes an id needs a few hundred bytes.

Remember that the limit applies to the whole body: a `tools/call` embedding base64 content pays roughly 4/3 of the raw byte size. If you need genuinely large inputs, take a URI or an id and fetch it server-side rather than raising the cap.
