Skip to content

fix: bound request body size in SSE and Streamable HTTP transports#839

Open
devcrocod wants to merge 2 commits into
mainfrom
fix/sse-request-body-limit
Open

fix: bound request body size in SSE and Streamable HTTP transports#839
devcrocod wants to merge 2 commits into
mainfrom
fix/sse-request-body-limit

Conversation

@devcrocod

Copy link
Copy Markdown
Contributor

Caps the size of incoming HTTP POST bodies in both server transports so an oversized request can no longer exhaust server memory

How Has This Been Tested?

new tests

Breaking Changes

binary incompatible for SseServerTransport constuctors

Types of changes

  • Bug fix (non-breaking change which fixes a
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would to change)
  • Documentation update

Checklist

  • I have read the [MCP Documentation](https:
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a bounded request-body reader and wires it into the server-side SSE and Streamable HTTP transports to prevent oversized HTTP POST bodies (including chunked requests without Content-Length) from exhausting server memory.

Changes:

  • Introduced receiveTextWithLimit(...) + RequestBodyTooLargeException and used it in SSE and Streamable HTTP request parsing.
  • Added/updated transport and route configuration to pass a maxRequestBodySize (default 4 MiB) and return 413 Payload Too Large on oversize bodies.
  • Added new JVM tests covering oversize bodies (including chunked/no Content-Length) and UTF-8 multibyte chunk-boundary decoding.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/RequestBody.kt Adds shared size-limited request-body reader and exception.
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransport.kt Switches POST body parsing to the new size-limited reader.
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SSEServerTransport.kt Adds max body size support and enforces it in SSE POST handling.
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt Exposes maxRequestBodySize through public mcp(...) route/application setup.
kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/RequestBodyTest.kt New tests for receiveTextWithLimit(...) behavior and UTF-8 safety.
kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SseServerTransportTest.kt New SSE transport tests for not-started behavior and 413 rejection.
kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransportTest.kt Adds a chunked/no-Content-Length oversize test and updates line-reading utilities.
kotlin-sdk-server/api/kotlin-sdk-server.api Updates API dump for new/changed public signatures.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +25 to +33
internal suspend fun ApplicationCall.receiveTextWithLimit(maxBytes: Long): String {
val buffer = Buffer()
val read = receiveChannel().readRemaining(maxBytes + 1).transferTo(buffer)
if (read > maxBytes) {
buffer.clear()
throw RequestBodyTooLargeException(maxBytes)
}
return buffer.readString()
}
Comment on lines 51 to 63
@KtorDsl
@Suppress("LongParameterList")
public fun Route.mcp(
path: String,
enableDnsRebindingProtection: Boolean = true,
allowedHosts: List<String>? = null,
allowedOrigins: List<String>? = null,
maxRequestBodySize: Long = DEFAULT_MAX_REQUEST_BODY_SIZE,
block: ServerSSESession.() -> Server,
) {
route(path) {
mcp(enableDnsRebindingProtection, allowedHosts, allowedOrigins, block)
mcp(enableDnsRebindingProtection, allowedHosts, allowedOrigins, maxRequestBodySize, block)
}
@devcrocod devcrocod added the security Security-related label Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

security Security-related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants