Securing Elicitation and Sampling: When Your MCP Server Asks the Client for Something

Most MCP security writing, ours included, treats the session as one-directional: a client calls a tool, the server checks a token and answers. Two features in the specification reverse that direction. With elicitation, the server asks the user for structured input in the middle of a tool call. With sampling, the server asks the client's model to produce text on the server's behalf.

Both are useful. Both are also the part of an MCP server that a security reviewer has usually not thought about yet, which means the questions arrive late and the answers have to be written under time pressure. This is how we design and review them.

What each feature actually is

Elicitation lets a server, while handling a request, send a request back to the client asking the user for additional information. The server supplies a JSON Schema describing the fields it wants. The client renders a prompt, the user accepts, declines, or cancels, and the client returns the response. Elicitation was added in the 2025-06-18 revision of the specification and is negotiated as a client capability during initialization.

Sampling lets a server ask the client to run a model completion. The server sends messages and preferences; the client decides which model to use, may show the request to the user, and returns the completion. Sampling is also a negotiated client capability.

The important structural fact for both: the server is the requester and the client holds the human. The server cannot force either one. Every design decision below follows from that.

Capability negotiation is not optional

A server may only send elicitation/create or sampling/createMessage if the client declared the matching capability in its initialize result. Many clients declare neither.

So a tool whose only path to completion runs through elicitation will fail for a large share of the clients that connect to you. Design each tool with a defined behaviour for a client that cannot elicit:

  • return a structured error that names the missing input, or
  • accept the same value as an explicit tool argument, or
  • refuse the operation and say why.

Write that behaviour down per tool. Reviewers ask what happens on the degraded path, and "it hangs" is a finding.

What a server must never ask for

The specification is direct that elicitation must not be used to request secrets, and this is the rule that gets broken in prototypes. A few concrete prohibitions we apply and test for:

  • No passwords, API keys, access tokens, refresh tokens, or client secrets.
  • No full payment card numbers or bank credentials.
  • No "paste the code from your authenticator app".
  • No prompt that re-collects an identity the token already establishes. If the access token carries the subject and tenant, do not ask the user which account to act on. Ask the token.

The reason is not only that the field could be logged. It is that the elicitation prompt is rendered by the client under the client's chrome, so a user has no reliable way to tell an honest server's request from a hostile one. Credentials must travel over the authorization flow, where the identity provider owns the login surface. If a tool needs a downstream credential, the answer is token exchange or a linked-account flow, not a text box.

Treat elicitation as a consent surface, not a form

The useful mental model is that elicitation is where a human confirms an action, not where the server collects data it was too lazy to scope.

Good uses:

  • Confirming a destructive or irreversible write before it happens, with the concrete target named in the message: "Delete invoice INV-2291 for Northwind, dated 12 March."
  • Disambiguating between records the user is already entitled to see.
  • Collecting a short, non-sensitive business value the API requires, such as a reason code.

Rules that survive review:

  1. The message must be self-describing. The user should be able to decide without scrolling back through the conversation.
  2. Never include untrusted content unlabelled. If any part of the message text came from a document, ticket, or web page the agent read, it is attacker-controlled. Do not let it set the framing of the question.
  3. Keep schemas flat and typed. Primitive properties, enumerations where the value set is known, explicit maximum lengths, required stated deliberately. A narrow schema is both easier for clients to render and easier to validate.
  4. Validate the response server-side anyway. A returned value is user input arriving through an untrusted path. Re-check it against the schema and against the caller's permissions before use.
  5. Distinguish decline from cancel. Decline is a decision; cancel is an abandonment. Do not treat either as consent, and do not retry the prompt in a loop.

A confirmation prompt does not upgrade a caller's authority. If the token's scopes do not permit the delete, the answer is a denial before the prompt, not a prompt followed by a denial.

Sampling: you are borrowing someone else's model

Sampling is convenient for a server that wants to summarize a result or classify a document without holding its own model credentials. It also creates three problems worth stating plainly to a reviewer.

Cost and abuse. Every sampling request spends the client's tokens and the customer's money. Rate-limit sampling per user, per tenant, and per session, and cap the size of the messages you send. Sampling driven by a loop over untrusted records is how a modest tool call becomes a bill.

Data flow. Whatever you put in a sampling request leaves your server, goes to the client, and from there to whichever model the client chose. You do not control that choice. If your data-flow diagram claims customer data stays within your processors, sampling contradicts it. Either exclude regulated fields from sampling requests, redact before sending, or do not use sampling for that tool. Say which, in writing, in the evidence pack.

Injection. The messages you send are usually derived from data the agent or your database supplied, and the completion comes back as text. Never route that completion into a privileged action without a check. Model output is a suggestion. Parse it into a constrained type, validate it, and enforce authorization on whatever it asks for, exactly as you would for a tool argument.

As with elicitation, define the fallback: if the client did not declare sampling, what does the tool do?

The confused-deputy shape

Elicitation and sampling both create the classic confused-deputy risk in a new place. The server is a trusted component acting between a human and a model, and both features let untrusted content reach the human's decision or the model's context through a path the human trusts.

The defence is boring and works: authority comes from the validated token, never from a returned elicitation value, never from a model completion, never from a tool argument. Human confirmation is a second gate on an action that was already authorized, not the gate itself.

Audit events

If a human approved a destructive action, the record of that approval is evidence, and it is the first thing a reviewer asks for after an incident. Emit an event for each request and each outcome, with at least:

  • session and request identifiers, so the prompt can be tied to the tool call that raised it
  • subject and tenant, from the token
  • the tool and operation the prompt gates
  • the schema identifier or version, not the returned values
  • the outcome: accept, decline, cancel, timeout, or client-not-capable
  • for sampling: model preferences sent, message and response sizes, and a token count if the client returns one

Do not log elicitation response contents by default. They are user-entered free text and can carry personal data you never intended to hold. Log the shape and the decision, not the payload.

A short review checklist

  • Client capabilities are checked before every server-initiated request, with a defined fallback path per tool.
  • No elicitation schema can request a credential, token, code, or card number. This is asserted in a test, not only in a policy.
  • Every elicitation message is self-describing and names the concrete target of the action.
  • Untrusted content in prompts is labelled and cannot set the framing.
  • Responses are validated server-side and re-authorized against the token before use.
  • Decline, cancel, and timeout are handled distinctly, with no retry loops.
  • Sampling is rate-limited and size-capped per user and tenant.
  • Data sent in sampling requests is documented in the data-flow diagram, with regulated fields excluded or redacted.
  • Model completions are never routed into privileged actions without validation and an authorization check.
  • Approval decisions are audited without logging response contents.

Where this fits

Most servers we review either do not use these features at all, or use them in one tool and have never written down the rules. Both are fine positions to start from. What fails a review is a server that prompts a user for something sensitive, or spends a customer's model budget in a loop, and cannot show the audit trail afterwards.

If you are adding elicitation or sampling to a server that is heading into an enterprise security review, this is the kind of thing our audits cover, and the answer is sometimes that you should not use the feature for that tool at all. That answer costs you a paragraph in the evidence pack instead of a finding.