---
title: "Limit protocol server HTTP request size in C#"
url: https://recursiveai.org/onemodelcontext/cookbook/limit-http-request-size/
description: "Set a byte limit for incoming Model Context Protocol® HTTP bodies. Oversized requests receive HTTP 413."
version: "1.0.1"
---

# Limit protocol server HTTP request size in C#

**OneModelContext** is a free, open-source .NET SDK for the Model Context Protocol® from Recursive AI. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneModelContext) · [GitHub](https://github.com/recursive-ai-oss/onemodelcontext-csharp) · [Docs](https://recursiveai.org/onemodelcontext/docs/) · [Download example (.zip)](https://recursiveai.org/onemodelcontext/cookbook/limit-http-request-size/limit-http-request-size.zip)

Set a byte limit for incoming Model Context Protocol® HTTP bodies. Oversized requests receive HTTP 413.

```shell
dotnet add package \
  RecursiveAI.OneModelContext
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using RecursiveAI.OneModelContext;
using RecursiveAI.OneModelContext
    .Hosting;

var server = new ContextServer(
    "Limits", "1.0");
using var endpoint =
    new StreamableHttpEndpoint(server,
    new StreamableHttpOptions
    {
        MaxRequestBodyBytes = 128
    });
```

Creates an endpoint with a 128-byte body limit. The full program sends 129 bytes and prints `413`.

Unzip [the example](https://recursiveai.org/onemodelcontext/cookbook/limit-http-request-size/limit-http-request-size.zip), then `dotnet run`.

## The full program

The program starts a local listener on an automatically assigned port and posts 129 ASCII bytes to the endpoint.

```csharp
using RecursiveAI.OneModelContext;
using RecursiveAI.OneModelContext.Hosting;
using RecursiveAI.OneModelContext.Http;
using System.Net.Http.Headers;

var server = new ContextServer("Limits", "1.0");
using var endpoint = new StreamableHttpEndpoint(server,
    new StreamableHttpOptions { MaxRequestBodyBytes = 128 });
await using var http = new HttpServer(
    exchange => endpoint.HandleAsync(exchange),
    new HttpServerOptions { Port = 0 });
http.Start();
using var client = new HttpClient { BaseAddress = http.BaseAddress };
using var request = new HttpRequestMessage(HttpMethod.Post, "/");
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));
request.Content = new StringContent(new string('x', 129),
    System.Text.Encoding.UTF8, "application/json");
using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
```

`dotnet run` prints:

```text
413
```

An oversized declared body receives 413 without being read; chunked bodies are cut off at the configured limit.

## Variations

For a 1 MiB endpoint limit, use:

```csharp
new StreamableHttpOptions
{
    MaxRequestBodyBytes = 1024 * 1024
}
```

With that option and a `1024 * 1024 + 1` byte input, the program still prints `413`.

## Related recipes

- [Build a protocol server in C#](https://recursiveai.org/onemodelcontext/cookbook/build-a-server-in-csharp/)
- [Serve over HTTP without ASP.NET Core](https://recursiveai.org/onemodelcontext/cookbook/serve-over-http-without-aspnet/)

---

## The short answer

Set `StreamableHttpOptions.MaxRequestBodyBytes` when constructing your `StreamableHttpEndpoint`; its default is 8 MiB. The value is bytes, not characters or kilobytes. A request whose declared body exceeds the limit receives HTTP 413 without the endpoint reading that body. For chunked requests, the endpoint cuts off the body at the limit.

The runnable example sets a deliberately small limit so the rejected input is easy to understand: 129 ASCII bytes exceed a 128-byte allowance. It is an HTTP rejection example, not a valid protocol call that fails tool validation. The body does not need to be valid JSON to demonstrate rejection by declared size.

## How big can an HTTP request be?

For this endpoint, the configured body limit is the relevant boundary. The [pinned limits documentation](https://github.com/recursive-ai-oss/onemodelcontext-csharp/blob/d72d78c39c934697857be92dd8514efd4c415a88/docs/http-limits.md) gives a default of 8 MiB for `StreamableHttpOptions.MaxRequestBodyBytes`, while `ModelContext.ServeHttpAsync` uses 1 MiB. Those are two documented entry points with different defaults; do not copy a default from one and assume it applies to the other.

A body limit is not a limit on the entire request. The listener has separate controls for the request line, header block and header count. Its own `HttpServerOptions.MaxRequestBodyBytes` also defaults to 8 MiB, as shown in the [pinned listener options](https://github.com/recursive-ai-oss/onemodelcontext-csharp/blob/d72d78c39c934697857be92dd8514efd4c415a88/src/RecursiveAI.OneModelContext/Http/HttpServerOptions.cs). If you adjust the endpoint above the listener’s allowance, the listener may reject the request first. Set both layers intentionally when changing them.

The sample leaves the listener’s default body allowance in place and makes the endpoint’s limit smaller, so the endpoint rejects the generated body. In deployed hosting, check the host and any reverse proxy too. A larger application allowance cannot make an earlier layer accept a request it already refuses.

## How do I set an HTTP POST body size limit in C#?

Construct the options before creating the endpoint, then route requests to that endpoint’s `HandleAsync`. The full program uses the package’s built-in listener only to make the rejection observable in one runnable project. The key task is the endpoint option; it does not require a second tool handler or a special schema.

Choose the limit for the serialized bytes you intend to accept. UTF-8 text can use more than one byte per character. The test uses ASCII so its byte length is unambiguous. When testing a boundary with real JSON, count its encoded representation, including property names, punctuation and protocol metadata.

The variation uses `1024 * 1024` for one MiB and tests one byte beyond it. Increasing the allowance is not a substitute for streaming large application data through a suitable resource design. A declared body is buffered at its declared size, according to the library’s documented behavior.

## What happens when a request body is too large?

An oversized individual request receives 413. The endpoint also has a separate `MaxInFlightBodyBytes` budget, documented as 64 MiB by default, for bodies held in memory across requests. Exceeding that aggregate budget receives 503 with `Retry-After: 1`, not the per-body 413 demonstrated here.

Time is separate from size as well: `BodyReadTimeout` addresses a body that arrives too slowly. Raising the byte limit does not disable that timeout. Keep the individual-body allowance, aggregate memory budget and read timeout distinct when diagnosing a rejected upload.
