Skip to content

Build1 publisher2 min readPublished

sampling/createMessage lets an MCP server run its own prompt through your model

In MCP's Sampling flow the server composes the prompt and the client runs the completion on its own model. The includeContext default is "none", and the two wider values only work if the client declares a capability.

The Engineer · Build desk

Illustration accompanying sampling/createMessage lets an MCP server run its own prompt through your model

What happened

  • MCP Sampling reverses the usual call direction: a server sends sampling/createMessage up to the client and asks it to run an LLM completion on a prompt the server composed.
  • The messages and systemPrompt fields of that request are written by the server, so the text the model is asked to act on originates with a remote party rather than the client.
  • The includeContext field decides how much of the conversation gets folded into the server's prompt, and it accepts "none", "thisServer" or "allServers", defaulting to "none".
  • Both wider values are soft-deprecated, and a compliant client honors them only if it has declared a sampling-context capability of its own.
  • The spec expects the client to show the user the server's prompt before running it, with the option to edit, approve or reject, and says the text reaches the model only on approval.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • exposure Every MCP server you install becomes a party that can author a prompt against a model you authenticated, so an install review has to cover what a server can send back up, not only what its tools return.
  • cost The inference for a server's reasoning step is charged to the client's model credentials, and the server gets to argue for the more capable model while someone else's account settles it.
  • decision Client authors have a cheap lever: declining to declare the sampling-context capability keeps conversation history out of server-written prompts without any per-server policy work.
  • constraint The two human checkpoints that make the design defensible live entirely in client code, so a client that renders them badly weakens the protection while remaining protocol-compliant.

At runtime the direction of the call is the story. A server is midway through a tool call, needs a judgment it has no model for, and emits `sampling/createMessage` back up to the client [3]. The client runs the completion on its own LLM, hands the text back, and the server resumes from where it paused [1]. In the expense case the dev.to write-up uses, a server hits a transaction it cannot categorize, asks the client which account the description belongs to, and carries on once the answer arrives [4].

The example request printed in that post sets `includeContext` to `"thisServer"` [9]. A client that has not declared a sampling-context capability will not honor that value at all [8]. Soft-deprecated, in this case, means the field still parses.

Strip the conversation history out and the interesting part remains. `messages` and `systemPrompt` both come from the server; the client wrote neither [5]. "A third party's server got to write a prompt and run it through the model I authenticated, on context I own," the post's author wrote [12], describing the feature as "a clean new way to get into your model's context" [18]. The completion then goes back to the server that asked for it [1].

`modelPreferences` is the lobbying channel. A server can send `hints`, `costPriority`, `intelligencePriority` and `speedPriority`, and the client still makes the final model pick [6]. The printed example hints `claude-3-sonnet`, sets `intelligencePriority` to 0.8 against `costPriority` 0.3, and caps the reply at `maxTokens` 100 [9]. Divide one by the other and the request weights capability about 2.7 times cost [15]. Sampling exists so that a server does not have to ship its own model and API key [14]. The tokens are billed to whoever owns the client's credentials [16].

The protocol authors did not leave the request unsupervised. Before the call, the client is supposed to show the prompt so it can be edited, approved or rejected [10]. Before the result returns, the client is supposed to show the completion so it can be approved or blocked [11]. "The catch is the word supposed to," the author wrote [13]. The text available here breaks off while asking whether a given client implements that gate well, or implements Sampling at all, and it names no client that does [17].

That is where an audit has to start, and it is a client-side audit. The spec's threat model assumes two human checkpoints inside code you may not have written [10][11]. If your client renders the server's prompt in a dialog nobody reads, or skips the dialog, the protocol is still being followed [13].

What to watch

  • Whether the MCP spec draft promotes thisServer and allServers or drops them, and which clients declare the sampling-context capability.
  • A named client shipping both approval screens, with a log of server-written prompts, would move this from spec text to auditable behaviour.
  • Whether client vendors report token spend attributable to sampling calls separately from user-initiated ones.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories