Model Context Protocol (MCP) is having a rough year. In the last fourteen months: a CVSS 9.4 RCE in Anthropic's own MCP Inspector, a prompt-injection exfiltration bug in GitHub's MCP server, a supply-chain disclosure in April 2026 that touched the official SDKs across four languages, and — just this June — RufRoot: an unauthenticated MCP bridge in an open-source agent platform with 67,000+ GitHub stars, giving full remote code execution from a single HTTP request.
Existing red-teaming tools (garak, PyRIT, promptfoo) are built for prompt injection and jailbreaks against a model. None of them connect to a live MCP server and test the protocol-level failure modes above — the ones that don't care what the model says, only what the server actually lets happen.
So I built mcp-redteam: a small tool that connects to a real MCP server — over stdio or Streamable HTTP — and runs six adversarial scenarios, each modeled on a real, disclosed incident or a currently-open issue on a funded organization's own project. Not hypotheticals.
The bug I didn't expect to find
Building the HTTP test fixtures, I hit something strange: the second request to a stateless StreamableHTTPServerTransport instance always failed with a bare 500 and an empty body — no exception, no stack trace, nothing reaching my error handlers. The first request (an initialize call) always worked. Every request after it, on the same transport instance, didn't.
I reproduced it two independent ways — raw node:http and Express — before finding modelcontextprotocol/typescript-sdk#1994: a confirmed, still-open regression. The 1.25.0 rewrite bridges Node's HTTP objects through @hono/node-server's getRequestListener, and an exception thrown inside that bridge becomes a generic Hono 500 — bypassing the SDK's own onerror callback and JSON-RPC error formatting entirely. It's a real trap: the SDK's own documented "stateless mode" example doesn't reuse a transport across requests, but nothing stops you from doing it, and when you do, the failure is nearly undiagnosable from the outside.
I posted an independent confirmation on the issue — reproduced on the current published SDK version, confirmed it wasn't specific to one HTTP framework — and the fix (construct a fresh transport per request) is now baked into mcp-redteam's own test fixtures with a comment explaining exactly why.
What the tool actually checks
Six scenarios, each with a real citation, not a vibe:
- Tool description/schema stability — does a tool change what it does after being inspected once ("rug pull")
-
Unannotated destructive tools — destructive-sounding tools with no
destructiveHintannotation -
Oversized-payload handling (opt-in) — does a "read-only" tool bound a large argument or hang — echoes a still-open finding on a real
litellmPR - Unauthenticated tool exposure — modeled directly on RufRoot (CVE-2026-59726, CVSS 10.0)
- Token audience validation — does the server actually enforce the MCP spec's own MUST-validate-audience requirement, or just check that some Authorization header exists
-
tools/callauthorization bypass — istools/callgated as strictly astools/list, modeled on the same pattern showing up independently inwso2/api-platform#2869and two separatelitellmissues (#31977,#36358)
Testing it against something real
I didn't want to ship this against only my own fixtures, so I ran it against LangFlow (153K+ GitHub stars) — a platform with a real, currently-relevant CVE (CVE-2026-33017, an unauthenticated RCE via its MCP adapter, still exploitable in the version the ecosystem widely believed was patched, per JFrog's research). The result was a clean negative: LangFlow's actual MCP protocol endpoint correctly requires authentication across every scenario. Worth stating plainly — that's not a miss, it's the tool telling the truth. The real CVE lives in a different layer (LangFlow's own REST API session-bootstrap logic, not its MCP server's protocol handling), which is outside what a pure MCP-protocol tester like this one checks — and I'd rather say that clearly than force a positive result to make the story better.
Why this, and not another jailbreak scanner
Prompt injection tooling is already a crowded, well-funded lane (OpenAI acquired Promptfoo for this exact space in March 2026). Protocol-level MCP testing — does the server actually enforce what its own spec requires — is not. Every scenario above traces to something a real, funded organization is dealing with right now, not a hypothetical I invented to have something to build.
Repo: https://github.com/AAH20/mcp-redteam — 18/18 tests passing, CI green on Node 20/22/24, Apache-2.0.
Top comments (1)
The protocol-level point is the useful bit here. A lot of agent safety writing still treats the model as the whole attack surface, but MCP moves part of the risk into ordinary server behavior, transport state, and auth boundaries. A 500 on the second request is exactly the kind of boring bug that becomes expensive once tools are allowed to take real actions.