skip to content

How do you keep MCP sampling approval prompts from being rubber-stamped by users?

level: principalimportance: nice to knowfreq 28%

answer

  1. Fewer decisions, each worth making
  2. Approve an exchange, not a message
  3. Budget per server beats a click per call
  4. A summary is not the prompt
  5. The strongest control is not offering it

basics

~20 s

Ask less often and ask better. Approve an exchange rather than every message, attach a per-server token budget the user can reason about, show what actually changed since the last approval, and make refusing free — which in MCP it is, since declining is just not retrying.

solid answer

~50 s

A dialog that appears on every model call trains people to click through it, so the design goal is fewer, more meaningful decisions. Practical shape: the user approves a *server* and an *exchange* with an explicit budget and iteration cap, the host continues automatically inside those limits, and it re-prompts only when a limit is about to be crossed or the request materially changes. Show the real prompt text, the server identity the host derived from its own configuration rather than the untrusted `io.modelcontextprotocol/serverInfo`, and what is new relative to the last approval. Log every approved request so unattended runs can be audited after the fact. Because MCP cannot enforce any of this — the host is the enforcement boundary — this is a product decision, and for many deployments the right answer is not to advertise the `sampling` capability at all, which is consistent with its deprecation in revision 2026-07-28.

go deeper

for a junior

Understand that a person can approve or refuse a sampling request, and that asking too often makes people stop reading. Recognise rubber-stamping as a real risk, not a theoretical one.

for a middle

Explain why the unit of consent should be an exchange with a budget rather than a single completion, and that MCP itself cannot enforce any of it — the host application is where the gate lives.

for a senior

Describe a shipped design: trust tiers per server, a diff of what changed since the last approval, budget and iteration caps, identity taken from host configuration rather than untrusted serverInfo, and an audit log for unattended runs.

for a principal

Own the decision of whether to offer sampling at all. Weigh the cost of a genuinely non-fatiguing consent experience against a feature deprecated in 2026-07-28, and be able to defend either investing in it or declining the capability outright.

## The failure mode being designed against MCP's sampling guidance asks the client to let a user review a server's prompt before the model runs and review the completion before it is returned. Implemented naively — a modal per request — this degrades within minutes of real use. Users approve reflexively, and a reflexive approval is worse than no approval, because the system now records consent that was never given in any meaningful sense and everyone downstream believes a human checked. So the question is not "how do we prompt" but "how many decisions can a person actually make well, and what should each one be about". ## Make the unit of consent bigger than a message A single completion is the wrong unit. It is too small for the user to have an opinion about and too frequent to sustain attention. The unit that works is an **exchange with declared limits**: "this server wants to use your model for this operation, up to N round trips and a stated token budget." One decision, made with the information that matters, covering everything that follows inside those bounds. Crossing a bound is what brings the human back. This maps cleanly onto the 2026-07-28 mechanics. Because server-initiated requests were removed, every step of a sampling exchange is the client re-issuing its own request — so the host is already the loop driver and can stop at any boundary it chooses. And because declining is expressed by simply not retrying, aborting is free: there is no error to construct, no cleanup handshake, no penalty for saying no. ## Make each prompt carry decision-relevant information When you do ask, show: - **The actual prompt text**, not a summary. A summary is a second model's opinion of what the first one was asked; the point of review is to see what is really being sent. - **What changed** since the last approval for this server. A diff is scannable; a wall of text is not. If nothing changed, that itself is the useful signal. - **Server identity you can trust.** Use the host's own configuration entry for the server. Revision 2026-07-28 is explicit that `io.modelcontextprotocol/serverInfo` is self-reported and untrusted, so a friendly name from the server is not an identity claim. - **Cost so far** in the current exchange and against the server's budget, so the decision is quantitative rather than vibes. - **Both directions.** The completion returning to the server is the data-egress half of the feature and deserves its own review step, at least for servers that are not fully trusted. ## Tier trust instead of treating all servers alike Different servers earn different defaults: a locally developed server may run inside a generous budget without prompting; an unfamiliar remote one may be restricted to a small budget and prompted every time; some are simply denied sampling. Tiering is what makes prompting rare enough to be meaningful. It should be explicit configuration, revocable, and visible — never an implicit "you approved this once, so it is trusted forever". ## Design for unattended runs honestly A great deal of MCP usage is not interactive. In batch or agent contexts, there is no human to prompt, and a system that silently auto-approves in that mode has quietly removed the control while keeping the appearance of it. Better: make unattended mode a distinct policy where sampling either runs inside a hard pre-authorised budget or is refused outright, and where every request is logged for after-the-fact review. Retrospective audit is a legitimate control when synchronous consent is impossible — but only if someone actually reads it, so pair it with alerting on budget anomalies. ## Accept the protocol's limits None of this is enforceable on the wire. MCP cannot make a host draw a dialog, and no field in a response proves that one appeared. The specification's consistent position is that the host is the enforcement boundary. That is a governance fact, not a gap to be closed with cleverness: if you do not control the host, you do not control sampling consent, and your remaining lever is which servers are installed at all. ## The strategic option Sampling is deprecated as of revision 2026-07-28 — deprecated features remain for at least twelve months, new implementations should not adopt them, and the earliest removal is the first revision released on or after 2027-07-28. The migration guidance is for servers to integrate directly with LLM provider APIs. For an organisation weighing the cost of building a genuinely good approval experience against a feature on its way out, not advertising the `sampling` capability is a defensible and often correct decision. Saying so — rather than designing an elaborate consent UI for a deprecated feature — is the answer that shows judgment.

  • What is a legitimate control when there is no human present at all?
    Pre-authorisation plus audit. Unattended mode should be an explicit policy where sampling either runs inside a hard, pre-agreed budget per server or is refused outright, with every request and completion logged. Retrospective review only counts as a control if someone reads it, so pair the log with alerting on budget or volume anomalies rather than treating the log itself as consent.
  • Why not just show a friendly server name from the response metadata in the dialog?
    Because it is self-reported. Revision 2026-07-28 states plainly that `io.modelcontextprotocol/serverInfo` is untrusted, so a server can name itself anything, including something that impersonates a server the user trusts. The identity shown to a user making a security decision must come from the host's own configuration entry for that server.
  • Given sampling's deprecation, is building a good approval UI for it worth the effort?
    Often not. Sampling was deprecated in revision 2026-07-28 with a migration to direct LLM provider integration, and deprecated features are removable from the first revision on or after 2027-07-28. Many hosts get a better return by not advertising the `sampling` capability and putting the same effort into the consent gate for tool calls, which is not going away.

saying these in an interview costs you the question

  • Adds a modal per completion and calls it consent
  • Treats one approval as permanent trust for a server
  • Shows a model-written summary instead of the real prompt
  • Displays the server's self-reported name as its identity
  • Auto-approves silently in unattended mode

context