Skip to content

HTTP transport has no request body size limit and no cap on concurrent sessions #243

Description

@bug-ops

Description

run_http in crates/mcpls-core/src/transport.rs:120-196 (opt-in transport-http feature) mounts rmcp::transport::streamable_http_server::StreamableHttpService directly via axum::Router::nest_service/route_service with no additional tower/axum middleware layers — no RequestBodyLimitLayer, no DefaultBodyLimit, nothing. Two unbounded-resource paths result, both reachable by any client that can reach the bound port (which, per #233, may be attempted on a non-loopback address with no authentication):

  1. Unbounded request body: rmcp's POST handler (expect_json in rmcp-2.2.0/src/transport/common/server_side_http.rs:171-202) calls body.collect().await and buffers the entire request body into memory before attempting JSON deserialization, with no size cap at any layer — not in expect_json, not in StreamableHttpServerConfig (rmcp-2.2.0/src/transport/streamable_http_server/tower.rs:42- has no body-limit field at all), and not added by mcpls's own run_http. A single POST with an arbitrarily large body is fully buffered before any validation occurs.
  2. Unbounded concurrent sessions: LocalSessionManager::create_session (rmcp-2.2.0/src/transport/streamable_http_server/session/local.rs:50-53) inserts into sessions: RwLock<HashMap<SessionId, LocalSessionHandle>> with no capacity check or rejection path. Each session spawns a worker task and per-session channels (channel_capacity default 16). Idle sessions are eventually reaped via keep_alive (default 300s) and completed_cache_ttl (default 60s), but nothing bounds how many sessions can be created within that window — a client opening many concurrent session-initializing requests accumulates unbounded worker tasks/memory before any TTL-based eviction fires.

Both gaps are in mcpls's control to close (add a body-size layer to the axum::Router in run_http; cap concurrent sessions or apply a lower keep_alive/connection-rate limit) even though the underlying buffering/session-creation code lives in the rmcp dependency.

This is a fresh angle distinct from already-tracked issues: #233 covers the inverted authentication log wording (not sizing/concurrency), and #234 covers the in-process diagnostics notification cache, not HTTP request/session handling.

Reproduction Steps

  1. Build with --features transport-http and run mcpls with Transport::Http bound to a local port.
  2. POST a very large JSON body (e.g. tens/hundreds of MB) with Content-Type: application/json and the required Accept header to the mount path — observe it is fully read into memory with no rejection based on size.
  3. Separately, open many concurrent initialize POSTs against the same endpoint within the 300s keep-alive window — observe each creates a new session entry with no upper bound or rejection.

Expected Behavior

The HTTP transport should reject oversized request bodies early (e.g. via a tower_http/axum body-size-limit layer around the mounted service) and should cap the number of concurrent sessions (or otherwise rate-limit session creation), returning an explicit error (413/429) rather than accepting unbounded growth.

Actual Behavior

No body size limit exists at any layer reachable from run_http; no session count cap exists in LocalSessionManager. Both allow a network client to drive unbounded memory/task growth in the mcpls process.

Environment

  • Version: 0.3.7 (current main, commit 2c8ad7f)
  • Features: transport-http (rmcp 2.2.0)

Logs / Evidence

  • crates/mcpls-core/src/transport.rs:120-196 (run_http, no middleware layers added to axum::Router)
  • rmcp-2.2.0/src/transport/common/server_side_http.rs:171-202 (expect_json, unbounded body.collect())
  • rmcp-2.2.0/src/transport/streamable_http_server/tower.rs:42- (StreamableHttpServerConfig, no body-limit field)
  • rmcp-2.2.0/src/transport/streamable_http_server/session/local.rs:50-53 (create_session, unconditional insert, no capacity check)

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium: suboptimal behavior, minor inconsistencybugSomething isn't workingmcpls-coremcpls-core crate changes

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions