Repository navigation
Commit be37d17
committed
Bound the
## Motivation and Context
A stateful session keeps the `clientInfo` and `capabilities` of the `initialize` request that created it,
for as long as the session lives, and `initialize` is validated for shape only. The session count and
the idle timeout bound how many sessions exist, and `max_request_bytes` bounds one request, but nothing bounded
what each session retained, so the sessions together could retain up to `max_sessions` times `max_request_bytes`
of client-supplied data. The documentation described the session limits as bounding what sessions retain,
which held for their number and not for their data. The TypeScript and Python SDKs keep the initialize data
whole and bound neither.
The body of an `initialize` request in stateful mode is now bounded by a new `max_initialize_request_bytes:` keyword,
64 KiB by default, which leaves room for large `experimental` capabilities while an ordinary `initialize` is under 2 KiB.
A larger body is rejected with HTTP 413 before any session is created, so nothing over the bound is ever retained;
`nil` removes the bound, and stateless mode, which retains nothing, ignores it.
A byte bound alone does not tightly bound the memory a session keeps, because the parsed objects, not the bytes,
are what it keeps: a body made of many small values parses into far more objects than its size suggests.
The `params` of an `initialize` are therefore also limited to 1024 JSON values, counted in a walk that stops at the limit,
and a request over it is rejected the same way; an ordinary `initialize` holds a few dozen. Like `MAX_JSON_NESTING`,
this structural limit applies in stateful mode whatever `max_initialize_request_bytes` is, including `nil`,
so removing the byte bound does not reopen the object count; a keyword can follow if a real client ever needs more.
Together the two bound both the serialized input and the number of parsed values a session can retain,
and the documentation now states that budget instead of the earlier claim.
## How Has This Been Tested?
New tests in `test/mcp/server/transports/streamable_http_transport_test.rb` send an `initialize` over the bound,
one exactly at it and one a byte over, one under `nil`, and one in stateless mode, and check the 413,
that no session exists afterwards, and that a regular request larger than the bound is still governed by `max_request_bytes` alone.
Further tests send `params` over the value bound while under the byte bound, exactly at it and one value over,
a large number of values within it, the same over-bound `params` under `nil`, and in stateless mode,
and check that object keys are counted and that nested shapes are refused.
Against the previous library an `initialize` just under `max_request_bytes` creates a session that keeps it.
One more sends a representative `initialize` with several icons, every capability, and an `experimental` object of many members,
and checks that it is accepted well inside both bounds.
## Breaking Changes
Requests that earlier releases accepted are now refused at the new bounds: an `initialize` request larger than
64 KiB is refused in stateful mode unless `max_initialize_request_bytes:` is raised or set to `nil`, and one whose
`params` hold more than 1024 JSON values is refused in stateful mode.initialize request a session retains1 parent 08e20ed commit be37d17
3 files changed
Lines changed: 344 additions & 16 deletions
File tree
- docs/_server
- lib/mcp/server/transports
- test/mcp/server/transports
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
222 | 222 | | |
223 | 223 | | |
224 | 224 | | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
231 | 235 | | |
232 | 236 | | |
233 | 237 | | |
234 | | - | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
235 | 244 | | |
236 | | - | |
237 | | - | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
238 | 252 | | |
239 | 253 | | |
240 | | - | |
| 254 | + | |
241 | 255 | | |
242 | 256 | | |
243 | 257 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
82 | 82 | | |
83 | 83 | | |
84 | 84 | | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
91 | 89 | | |
92 | 90 | | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
93 | 106 | | |
94 | 107 | | |
95 | 108 | | |
| |||
137 | 150 | | |
138 | 151 | | |
139 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
140 | 159 | | |
141 | 160 | | |
142 | 161 | | |
| |||
168 | 187 | | |
169 | 188 | | |
170 | 189 | | |
| 190 | + | |
171 | 191 | | |
172 | 192 | | |
173 | 193 | | |
| |||
233 | 253 | | |
234 | 254 | | |
235 | 255 | | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
236 | 263 | | |
237 | 264 | | |
238 | 265 | | |
| |||
1356 | 1383 | | |
1357 | 1384 | | |
1358 | 1385 | | |
| 1386 | + | |
| 1387 | + | |
| 1388 | + | |
| 1389 | + | |
| 1390 | + | |
| 1391 | + | |
| 1392 | + | |
| 1393 | + | |
| 1394 | + | |
| 1395 | + | |
1359 | 1396 | | |
1360 | 1397 | | |
1361 | 1398 | | |
| |||
1584 | 1621 | | |
1585 | 1622 | | |
1586 | 1623 | | |
| 1624 | + | |
| 1625 | + | |
| 1626 | + | |
| 1627 | + | |
| 1628 | + | |
| 1629 | + | |
| 1630 | + | |
| 1631 | + | |
| 1632 | + | |
| 1633 | + | |
| 1634 | + | |
| 1635 | + | |
| 1636 | + | |
| 1637 | + | |
| 1638 | + | |
| 1639 | + | |
| 1640 | + | |
| 1641 | + | |
| 1642 | + | |
| 1643 | + | |
| 1644 | + | |
| 1645 | + | |
| 1646 | + | |
| 1647 | + | |
| 1648 | + | |
| 1649 | + | |
| 1650 | + | |
| 1651 | + | |
| 1652 | + | |
| 1653 | + | |
| 1654 | + | |
| 1655 | + | |
| 1656 | + | |
| 1657 | + | |
| 1658 | + | |
| 1659 | + | |
| 1660 | + | |
| 1661 | + | |
| 1662 | + | |
1587 | 1663 | | |
1588 | 1664 | | |
1589 | 1665 | | |
| |||
0 commit comments