Walk through a sampling request/response and its human-in-the-loop approval step.

5 minadvancedmcpsamplinghuman-in-the-loopflow

Quick Answer

A server sends sampling/createMessage with the messages it wants sampled, optional systemPrompt, modelPreferences (hints about cost/speed/intelligence tradeoffs, not a specific model name), includeContext (whether to include none, this server's, or all servers' context), and maxTokens. Before actually calling a model, a well-behaved client is expected to surface this request to the user for approval — showing what's being asked and why — since the server is effectively asking to spend the user's model budget and potentially expose conversation context to itself. Only after approval does the client call its own LLM, and it may also let the user review/edit the generated completion before returning it to the server as the sampling/createMessage result.

Detailed Answer

Sampling's approval step exists because the server asks to use resources — model access, potentially cost, potentially context — that belong to the user, not to the server.

The full request

{"method": "sampling/createMessage", "params": {
  "messages": [
    {"role": "user", "content": {"type": "text", "text": "Draft a one-sentence changelog entry for this diff: ..."}}
  ],
  "systemPrompt": "You are a terse technical writer.",
  "includeContext": "thisServer",
  "modelPreferences": {
    "hints": [{"name": "claude-haiku"}],
    "costPriority": 0.8, "speedPriority": 0.9, "intelligencePriority": 0.2
  },
  "maxTokens": 60
}}

The approval step, conceptually

Server sends sampling/createMessage
        |
        v
Client shows the user: "acme-server wants to generate text using your LLM. Preview: [messages]"
        |
   User approves / edits / rejects
        |
        v (if approved)
Client calls its own configured LLM with the (possibly user-edited) request
        |
        v
Client optionally lets the user review the generated completion before sending it back
        |
        v
Client returns the result to the server as the sampling/createMessage response

Why modelPreferences is hints, not a model name

The request expresses priorities — favor cost, favor speed, favor intelligence — plus optional named hints, rather than mandating an exact model. The client, not the server, actually knows which models are available, what they cost, and what the user prefers. The server describes what it needs. The client decides how best to satisfy that.

Why this matters for trust

Without a human-in-the-loop step, a malicious or buggy server could silently spend a user's model budget. Worse, it could smuggle a manipulative instruction into a sampling request, designed to make the client's LLM produce output favorable to the server's own agenda — an early form of the confused-deputy-style risk this primitive is exposed to. Surfacing the request for approval, and ideally showing exactly what will be sent, is the mitigation the spec expects clients to implement. The precise UI for doing so is left to each host.

Related Resources