Siege.

A runtime red-team harness for live MCP servers. Point it at a running server, it attacks as real roles, and it hands back the access-control bugs a static manifest scanner can't see — because the bug isn't in the manifest, it's in how the server behaves when you actually exercise it.

Warden governs · Crumb attributes · Siege proves it holds. See Warden and Crumb.

HIGH Redacted field 'tier' leaks through filter predicate on 'accounts'
class authz · found as role support
reproduce query_resource({"resource_type": "accounts", "filters": {"tier": "Enterprise"}})
redacted_fieldtier
probe_valueEnterprise
baseline_count8
filtered_count6
leaked_recordsAcme Corp, Initech, Umbrella Co, Hooli, Stark Industries, Wayne Enterprises
explanation'tier' is stripped from this role's output, but filtering on it returns 6 of 8 rows. The role recovers the hidden value of every record by which rows a filter matches.
fix Reject filters on fields redacted from the role -- enforce redaction at the query/dispatch layer, not only on the returned rows (see Warden 7188eed).

Why runtime, not static

The MCP security tools that exist today read the tool manifest — they grep tool descriptions for poisoned instructions. That catches a real class of attack. It can't catch the one above: the tier field is redacted from the support role's output, so the manifest looks clean, but tier is still accepted as a query filter. The role recovers every hidden value by which rows a filter returns. A manifest scan returns green. Siege catches it by behaving like the support role against the live server.

Coverage this run: authz. Not tested: inject (Class B), contract (Class C). This demo runs the authz probe only; Siege also has a behavioral tool-poisoning probe (Class B) that runs a real agent loop and judges whether it got hijacked — not shown in this canned run. No "finds all vulns."