Build1 publisher3 min readPublished
Red-team lab lands attacker prose in an MCP agent's context before any tool runs
Mike Moore's harness shows MCP's server-authored instructions field placing hostile prose in an agent's context, and a caching proxy passing it to a second caller. The harness measures where the text lands, with no model in the loop.
The Engineer · Build desk

What happened
- Mike Moore, a solution architecture leader at Solo.io, published a red-team lab showing that an MCP server can place attacker-written instructions into an agent's context before the agent's first tool call.
- The instructions field sits outside individual tool definitions: older MCP versions return it during initialize, and the July 28th, 2026 specification can return it through server/discover.
- All four of the lab's scenarios reach its trusted prompt region or cross its caller boundary when defenses are disabled, and the guarded configuration blocks all four.
- Anthropic's Claude Code documentation says each server's instructions load at session start, to help Claude find MCP tools whose definitions are deferred.
- An August 28th audit of the official MCP registry reported 5,462 of 8,235 responding servers, 66%, returning an instructions value, with a median length of 577 characters and a maximum of 68,669.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- exposure Because server-authored prose reaches the model before any tool call, the permissions already granted to the agent decide how far a poisoned discovery response can travel.
- cost Clients that cap the field pay for the defense in dropped text. The longest instructions value in the registry audit is roughly 34 times Claude Code's 2KB limit, so a legitimate server writing at that length loses most of its guidance.
- constraint Moore ran the harness without a language model and without testing a named gateway, so this cannot yet be priced as a production vulnerability, only as a demonstrated path into a context region.
MCP's discovery specification marks its example result publicly cacheable for one hour [6]. The same specification describes the `instructions` field as optional natural-language guidance for helping an LLM use a server effectively [5]. Guidance for a model is, at prompt-assembly time, more prompt. Much of the industry's prompt-injection work has concentrated on individual tool definitions, and this field sits outside them [3].
Moore's four scenarios run against a simulated hostile server, a caching proxy and an enforcement layer. They are a direct override, a directive buried in a 24,000-character payload, a change to already-approved instructions after several discovery requests, and a response marked `cacheScope: "public"` [7]. That last one is the cross-caller test. Client A requests discovery from the hostile server and fills the proxy cache; client B then receives the same instructions from the proxy without ever connecting to the hostile server [10]. A gateway that aggregates MCP traffic becomes the distribution point for poisoned metadata when its cache key ignores server identity, authorization context or caller identity [11].
Library defaults do not agree. MCP's Python SDK caching documentation warns that a public scope lets a shared gateway serve a response across users, including authenticated requests, and its safe default is an immediately stale, private response [12]. The Rust SDK caches discovery responses that carry a positive lifetime [13]. Gateway and client behavior has to be evaluated implementation by implementation [13].
The guarded run of the harness blocks all four scenarios, using isolation, a 4,096-character cap, caller-bound cache keys and a digest that rejects changed instructions. The repository carries eight assertions across the defended and undefended outcomes [9].
Claude Code caps each server's instructions at 2KB [17]. That is 2,048 bytes, half the cap the harness enforces [1], and it passes roughly 9% of the 24,000-character payload [2]. So the cap removes most of the volume attack, while the direct-injection route stays open, because shorter server-authored instructions still enter the model context [17].
The registry audit gives the scale of that route. Its median instructions value sits well inside Claude Code's cap [3], and its longest is about 34 times the cap [4]. Those are self-reported research results backed by a downloadable server-level dataset, not measurements Moore's lab reproduced [19]. The runtimewire account of the work says the same audit narrows the immediate reach of the public-cache scenario [20].
The harness establishes something narrower than its four scenario names suggest. It runs without a language model, and it does not demonstrate compromise of a named commercial gateway or agent framework [14]. It tests whether server-controlled text enters a region the harness labels trusted, and actual impact depends on the client's prompt assembly, the model's behavior and the permissions available to the agent [15].
What to watch
- Whether gateway vendors publish cache-key rules that bind discovery responses to server identity, authorization context and caller.
- Whether the MCP specification changes the publicly-cacheable-for-one-hour example, or the SDK caching defaults converge.
- Whether anyone reruns the four scenarios with a live model and real tool permissions. That rerun is what would establish impact.