You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: document input-hardening limits in CHANGELOG and transports guide
Add CHANGELOG entries and docs/transports.md sections for the JSON-RPC
batch size cap (maxBatchSize) and the StreamableHttpTransport request
body size cap (maxBodyBytes), plus the type-based single-vs-batch
message detection.
Copy file name to clipboardExpand all lines: CHANGELOG.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -31,6 +31,9 @@ All notable changes to `mcp/sdk` will be documented in this file.
31
31
*[BC Break]`ResourceDefinition::__construct()` signature changed — `$title` parameter added between `$name` and `$description`. Callers using positional arguments must switch to named arguments.
32
32
*[BC Break]`ResourceTemplate::__construct()` signature changed — `$title` parameter added between `$name` and `$description`. Callers using positional arguments must switch to named arguments.
33
33
*[BC Break]`McpResource` and `McpResourceTemplate` attribute signatures changed — `$title` parameter added between `$name` and `$description`. Callers using positional arguments must switch to named arguments.
34
+
* Harden JSON-RPC input parsing: single-message vs batch is now decided from the decoded JSON type (object → single, list array → batch) instead of the raw first byte. Scalars, empty payloads, and non-object batch elements are surfaced as `InvalidInputMessageException` entries instead of triggering warnings or a `TypeError`.
35
+
* Add `maxBatchSize` (default `100`) to `MessageFactory` — oversized JSON-RPC batches are rejected before any message is constructed, guarding against amplification.
36
+
* Add `maxBodyBytes` (default 4 MiB) to `StreamableHttpTransport` — POST bodies exceeding the cap are rejected with `413`. Unknown-size/chunked bodies are read incrementally and stopped at the cap so they cannot exhaust memory.
Copy file name to clipboardExpand all lines: docs/transports.md
+35Lines changed: 35 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -112,6 +112,7 @@ $transport = new StreamableHttpTransport(
112
112
-**`streamFactory`** (optional): `StreamFactoryInterface` - PSR-17 factory for creating response body streams. Auto-discovered if not provided.
113
113
-**`logger`** (optional): `LoggerInterface` - PSR-3 logger for debugging. Defaults to `NullLogger`.
114
114
-**`middleware`** (optional): `iterable<MiddlewareInterface>|null` - PSR-15 middleware chain. `null` (omitted) installs the [default stack](#default-middleware). `[]` disables all defaults — useful when the surrounding application already handles CORS, host validation, etc.
115
+
-**`maxBodyBytes`** (optional): `int` - Upper bound on the POST request body read, in bytes. Defaults to 4 MiB (`StreamableHttpTransport::DEFAULT_MAX_BODY_BYTES`). See [Request Body Size Limit](#request-body-size-limit).
115
116
116
117
### PSR-17 Auto-Discovery
117
118
@@ -230,6 +231,40 @@ use Mcp\Server\Transport\Http\Middleware\ProtocolVersionMiddleware;
230
231
new ProtocolVersionMiddleware(supportedVersions: [ProtocolVersion::V2025_11_25]);
231
232
```
232
233
234
+
### Request Body Size Limit
235
+
236
+
`StreamableHttpTransport` caps the POST body it reads to guard against memory exhaustion from an oversized or
237
+
unbounded (chunked) payload. The default cap is 4 MiB. A body over the cap is rejected with `413` and never reaches
238
+
message parsing.
239
+
240
+
```php
241
+
use Mcp\Server\Transport\StreamableHttpTransport;
242
+
243
+
// Raise the cap to 16 MiB
244
+
$transport = new StreamableHttpTransport($request, maxBodyBytes: 16 * 1024 * 1024);
245
+
```
246
+
247
+
When the request stream advertises a size, the transport rejects it up-front. Otherwise (e.g. chunked transfer with
248
+
unknown size) the body is read incrementally and aborted as soon as it crosses the cap, so an unbounded stream cannot
249
+
exhaust memory. A value below `1` throws `InvalidArgumentException`.
250
+
251
+
### JSON-RPC Batch Size Limit
252
+
253
+
A JSON-RPC batch (top-level array) is capped at 100 messages by default. Oversized batches are rejected before any
254
+
message is constructed, so a single small request cannot amplify into arbitrarily many operations. The cap lives on
0 commit comments