Rightshold™ Sign up

Evidence Delivery · $99 / 30 days · Offers open November 18, 2026 · online purchasing currently unavailable

Answers · MCP security

We're about to expose our MCP server over Streamable HTTP. What stops one anonymous client from knocking it offline with a broken or oversized request, or from grabbing the server so nobody else can connect, and what limits should the HTTP layer enforce before a request reaches the MCP SDK?

Last updated

TL;DR: Put the limits in the HTTP layer, in front of the SDK: a byte cap on the request body that answers 413, a try/catch around JSON parsing that answers 400, one transport per client session (or a stateless server) with caps on how many sessions exist, idle timeouts, request and header timeouts, and a rate limit. Three advisories for @tsparticles/mcp-server, added to GitHub's advisory database on November 9, 2026, show what happens without them. One malformed body such as {"jsonrpc": made JSON.parse throw outside any error handler and ended the Node.js process (CVE-2026-76892, fixed in 4.3.1). The handler buffered every chunk of a POST with no size check, so a chunked 300 MB stream got a container with a 256 MB memory cap OOM-killed (CVE-2026-63655, fixed in 4.3.1); the project's Docker image ran HTTP mode on 0.0.0.0:3000 out of the box. And one shared transport served every client, so the first anonymous initialize claimed it and every later client got "Server already initialized" until a restart (CVE-2026-76893, fixed in 4.3.2). None of the three needed a credential. The MCP 2026-07-28 specification retires the initialize handshake and the Mcp-Session-Id header, so a server on that version has no protocol session for anyone to grab, but body caps, parse errors and rate limits are still yours to handle.

What should I check, step by step?

1. Cap the request body by counting bytes as chunks arrive, not by trusting Content-Length; a chunked request has none. Stop buffering at the cap and answer 413.

  1. Wrap JSON parsing of every request in a local try/catch and answer 400 with a short error. One bad request should never reach the process-level crash handler.
  2. Give each client session its own server and transport, kept in a bounded map, or run stateless so no session exists. Never share one stateful transport across all HTTP clients.
  3. Cap total sessions and sessions per client, close sessions that go idle, and set request, header and keep-alive timeouts on the HTTP server so a slow sender can't hold a connection open.
  4. Rate limit per client and add a process-wide ceiling, because a per-IP limit alone can be spread across many source addresses. Derive the client address only from your own proxy's forwarding header.
  5. Run under a supervisor that restarts the process, with a memory limit, so a crash you didn't foresee costs seconds, not an outage that lasts until someone notices.
  6. Require a credential before any of this is reachable from another machine; bind to 127.0.0.1 when only local clients need it.
  7. Add tests that send a truncated JSON body, a body one byte over the cap, and two initialize requests from different clients, and assert 400, 413 and two working sessions.

How did one malformed or oversized request crash the @tsparticles/mcp-server HTTP mode (CVE-2026-76892, CVE-2026-63655, CVE-2026-76893)?

The HTTP mode of @tsparticles/mcp-server read POST /mcp bodies by pushing every data chunk into an array, joining them and calling JSON.parse on the result, then handing that to the SDK transport. GHSA-4p8p-pjpq-2w7h (CVE-2026-76892, CWE-248, CVSS 4.0 8.7) says the parse sat outside a request-local error boundary: the truncated body {"jsonrpc": ended the process in 3 out of 3 runs, and the service stayed down until an outside supervisor restarted it. It affects 4.3.0 and earlier and is fixed in 4.3.1, which answers 400 for invalid JSON.

What body, session, timeout and rate limits should an MCP server's HTTP mode enforce?

The project's current HTTP server code (main branch, read November 13, 2026) is a compact example of the limits above. It counts body bytes as they arrive, stops buffering past 1 MB and answers 413 once the body has been read, and answers 400 "Invalid JSON" when parsing throws. Each initialize gets a new server and transport pair kept in a map, with at most 500 concurrent sessions and 10 per client, and sessions idle for 30 minutes are closed by a sweep every 5 minutes.

Does the MCP 2026-07-28 stateless core stop one client from grabbing an MCP server's session?

The 2026-07-28 MCP specification retires the initialize/initialized exchange and the Mcp-Session-Id header (SEP-2575, SEP-2567). Each request carries its protocol version, client identity and capabilities itself, so any request can land on any server instance, and there is no shared protocol session for a first caller to claim. A server that also serves clients on older protocol versions still creates sessions for them, so keep the per-session limits until you drop those versions.

How do I ask Rightshold about this (free, no key)?

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “I just upgraded our @tsparticles/mcp-server deployment to 4.3.2 and put it behind our proxy. Check what it serves now: has its tool list changed from what was recorded, and does any tool definition carry hidden text?”

One-click setup

{
  "tool": "precall_check",
  "arguments": {
    "url": "<your server's https MCP URL>"
  }
}

Rightshold isn't affiliated with tsParticles or the Model Context Protocol project, and it doesn't load-test, fuzz or scan MCP servers. Advisory details are as published in GitHub's advisory database (GHSA-4p8p-pjpq-2w7h, GHSA-447x-qqwf-m7xq, GHSA-h7c4-q426-7jh9), the limits as written in the tsparticles/tsparticles repository's mcp-server HTTP source on its main branch, and the session and header changes as described in the MCP project's 2026-07-28 release announcement, all read November 13, 2026; advisories and code change, so confirm fixed versions on the linked pages.

What are the sources?

Related

Not legal advice. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'