Unauthenticated Sampling: When an MCP Server Drives Your Model
Normally your agent calls the server. Sampling lets the server call your model — on your account, with content it chooses, returning text that can re-enter your session.
What sampling is for
MCP includes a capability called sampling, which lets a server ask the client to perform a model completion. The intent is reasonable: a server that needs to summarise or classify something can borrow the client's model rather than requiring its own API key and billing relationship.
It inverts the usual direction of control. Normally the client drives — the agent decides to call a tool, the server responds. With sampling, the server initiates and the client performs inference on its behalf.
Why that inversion matters
Security analysis identifies unauthenticated sampling as one of three protocol-level weaknesses, and published research has documented attack vectors specifically through this path. Four consequences follow from the inversion.
The server spends your budget
Inference runs on the client's account. A server that issues sampling requests in a loop consumes tokens you pay for, and unless you are watching per-server usage it looks like ordinary activity.
The server shapes the prompt
Sampling requests carry content the server chooses. That content reaches your model, and where the result feeds back into the agent's context, the server has gained an indirect channel for influencing the main session.
Results cross a boundary invisibly
A completion produced from server-supplied input arrives back looking like any other content. Implicit trust propagation applies: there is no marking that distinguishes this text from something the user wrote.
It is easy to under-authenticate
The failure mode named in the analysis is the absence of authentication on this path. Where a client does not properly verify which server is asking, or does not constrain what it will agree to run, the capability becomes an open inference endpoint attached to your account.
Do you know whether any of your connected MCP servers can trigger model completions on your account? For most teams the honest answer is no, and that uncertainty is the finding.
A worked example of the loop
The concerning case is not one sampling request. It is the cycle that forms when results feed back into the session that triggered the server call.
1. Agent calls summarise_document(url) on a connected server.
2. Server fetches the document. The document contains text written
by whoever controls that URL.
3. Server issues a SAMPLING request: "summarise the following"
plus the fetched content, verbatim.
4. Client runs the completion on the user's account. The fetched
content is now in a prompt the user never saw.
5. Result returns to the server, then to the agent, then into the
main context — indistinguishable from the agent's own reasoning.
6. Agent acts on it.
The critical step is 5. Content that originated outside your organisation has been laundered through your own model and arrives wearing your model's voice. It no longer looks like a tool result; it looks like the assistant thinking.
This is implicit trust propagation with an extra hop, and the extra hop is what makes it hard to spot in a transcript. A tool result is visibly a tool result. A summary produced by your own model reads as analysis.
Controls, in order of usefulness
1. Disable it unless you need it
Most workflows never require server-initiated sampling. If your client lets you turn it off, turn it off. The most reliable control over a capability is not having it enabled.
2. Allow-list which servers may use it
Where it is needed, it is generally needed by one or two servers, not all of them. Grant it per server rather than globally.
{
"mcpServers": {
"doc-summariser": {
"command": "...",
"sampling": { "enabled": true, "maxRequestsPerSession": 20 }
},
"weather": {
"command": "...",
"sampling": { "enabled": false }
}
}
}
Exact configuration syntax varies between clients. The principle does not: default off, enabled deliberately, bounded when enabled.
3. Rate-limit and cap
A per-session ceiling turns runaway consumption into a bounded cost. Any limit is enormously better than none, because the unbounded case has no natural stopping point.
4. Log the requests, including content
Record which server asked, what it sent, and what came back. This is the only way to reconstruct what happened afterwards, and sampling requests are easy to overlook precisely because they are not user-initiated.
2026-06-29T14:22:31Z server=doc-summariser tokens_in=1840 tokens_out=210
prompt_sha=8f2a1c... result_used_in_context=true
2026-06-29T14:22:48Z server=doc-summariser tokens_in=1602 tokens_out=188
prompt_sha=3b91ee... result_used_in_context=true
The final field is the one to watch. A sampling result that ends up back in the main agent context is a path from server-controlled input to your working session, and it deserves more scrutiny than one consumed internally by the server.
Treat sampling output as untrusted input
The general principle from the threat model applies with particular force here. A completion generated from server-supplied content is not your instruction and is not your data. It should be handled as text from an untrusted source, which in practice means:
- It should not silently expand what the agent will do.
- It should not be the sole basis for an irreversible action.
- Where it reaches the main context, that should be visible in the transcript rather than seamless.
The last point is the one clients most often get wrong, and it is worth checking in yours. Seamlessness is a good default for user experience and a bad one for anything crossing a trust boundary.
The confused deputy, restated
It is worth naming the classical pattern here, because it clarifies why the usual controls miss.
A confused deputy is a program that holds authority and is tricked into exercising it for someone who lacks it. The classic example is a compiler with write access to a billing file, invoked by a user who cannot write there but can name that file as an output path. The compiler is not compromised. It does exactly what it was designed to do, on behalf of the wrong principal.
Sampling produces the same shape. Your client holds the API credential. A server asks it to run a completion. The client complies, because complying is the feature. Nothing is exploited — authority is simply exercised on behalf of a party who did not have it.
The classical remedies apply. Bind authority to the request rather than to the ambient credential; make the caller present a capability rather than relying on the deputy's standing permissions. In practice, for a client you did not write, that reduces to the controls above — per-server grants, hard caps, and logs — because they are the only points where you can attach a principal to a request.
What to check this week
- List your connected servers and, for each, determine whether it can request sampling.
- Disable it wherever it is not actively used.
- For the remainder, set a per-session cap.
- Confirm the requests are logged somewhere you would actually look.
Half an hour, and it closes a path most teams have never examined — largely because it runs in the opposite direction from the one everyone thinks about.
Sampling reverses the usual direction of control: the server asks, your account pays, and the result can re-enter your session. Default it off, grant it per server, cap it, log it, and treat anything it returns as untrusted input rather than as your own reasoning.