How it works
MCP Sampling inverts the usual direction of the Model Context Protocol. Normally a client calls tools a server exposes. Sampling lets the server call back: it asks the client's model to produce a completion, then uses the result to continue its own work.
The loop:
- A server sends a
sampling/createMessagerequest carrying messages, an optional system-prompt hint, and model preferences (not a hard model choice). - The client — not the server — decides whether to honor it. It can inspect, edit, or reject the request before anything runs.
- The client picks the concrete model, subject to the server's stated preferences, and executes the inference on its own account and credentials.
- The client returns the generated message. The protocol expects a human to stay in the loop on both the outgoing prompt and the returned completion.
The consequence is a clean split of concerns. The server never holds an API key, never picks the exact model, and never sees your provider bill. It describes the language work it needs; the client owns how that work is done. A server can therefore behave agentically — summarize, classify, plan a next step — without shipping its own model or asking you to fund inference you cannot see.
Why it matters in an agent harness
Sampling is where inference authority lives, so it is a control surface, not a convenience.
- Single point of billing and policy. Every model call routes through one client. You get one bill, one place to apply rate limits, and one place to enforce which models are even allowed.
- Permission boundary. A server cannot silently spend your tokens or reach an arbitrary model. The client is the gatekeeper, which keeps a third-party server inside a bounded blast radius.
- Human-in-the-loop by design. Because the request passes through the client, you can present the prompt and the completion for approval before either takes effect — the same posture you want on any consequential agent action.
- Observability. All sampled calls funnel through the client, so trajectories, token spend, and prompts are logged in one stream instead of scattered across opaque servers.
- Failure containment. A buggy or compromised server cannot exfiltrate data or run up cost through unbounded generation if the client enforces budgets and reviews content.
The risk you accept: server-supplied messages are untrusted input. A prompt handed to your model can carry injected instructions, so the client's mediation has to treat that text as data, not commands.
MCP Sampling vs tool use
Both connect a client and server, but the direction of authority is opposite, and that changes who you trust with inference.
| Aspect | Tool use | MCP Sampling |
|---|---|---|
| Direction | Client's model calls the server's function | Server asks the client's model to generate |
| Who runs code/inference | Server executes the tool | Client executes the completion |
| Who pays | Whoever hosts the tool | The client, on its own account |
| Trust concern | Tool output as untrusted evidence | Server-supplied prompt as untrusted input |
If a server needs deterministic action, expose a tool. If it needs judgment or language work but should not carry a model, use sampling and keep the inference on your side of the boundary.
The Rifty take
We treat sampling as a permission surface first and a feature second. What we optimize for is a single, legible mediation point: every model call a server provokes should pass through the client's policy, budget, and log. The tradeoff we accept is friction — an approval step and some latency — because the alternative is inference authority leaking into components we do not control. The boundary we enforce is simple: no server routes to a model, or spends a token, without the client's consent.
Common failure modes
- Blind approval. Auto-accepting every
sampling/createMessagerecreates the exact risk the feature is meant to contain. Sample requests need real review or a scoped policy, not a rubber stamp. - Trusting the server's system prompt. Treat server-supplied messages as untrusted; a hidden instruction can hijack your model. Keep prompt injection in scope here.
- No budget. Without a token or call ceiling, a chatty or malicious server can drive cost through your account. Bind sampling to a tool budget.
- Honoring model preferences too literally. Preferences are hints. Map them to an allowed model set under your own routing policy rather than letting the server dictate the model.
- Missing logs. If sampled calls are not captured with the rest of the trajectory, you lose the observability that made the client the right place to run inference.
- Confusing sampling with tool use. Reaching for sampling when you needed a deterministic action gives up verifiability; reaching for a tool when you needed judgment pushes a model into the server.
Frequently asked questions
How is MCP Sampling different from calling a tool?
Direction of authority is reversed. With tool use, the client's model calls a function the server runs. With sampling, the server asks the client's model to generate a completion. In tool use the server executes and often pays; in sampling the client selects the model, runs inference, and pays.
Who pays for the inference in MCP Sampling?
The client does. The server issues a request describing the language work it needs, but the client selects the concrete model and runs the completion on its own account and credentials. The server never holds an API key or sees your provider bill, which keeps billing and model policy in one place.
Is MCP Sampling a security risk?
It concentrates risk where you can control it, but the server's prompt is untrusted input. A sampling request can carry injected instructions aimed at your model, and an unbounded server can drive cost. Mitigate with client-side review, a token budget, a strict allowed-model set, and treating server text as data.
Does MCP Sampling require a human in the loop?
The protocol expects the client to keep a human able to review both the outgoing prompt and the returned completion, and that posture is the point. You can scope trusted requests to a policy instead of prompting every time, but blindly auto-approving every sampling call defeats the boundary it provides.
When should a server use sampling instead of shipping its own model?
Use sampling when a server needs judgment or language work but should not carry credentials, pick models, or own inference cost. It lets a server behave agentically while the client keeps billing, model routing, logging, and approval. If the server needs deterministic action, expose a tool instead.