Skip to content

How to Handle MCP v2 Sampling Deprecation in Your Server

Problem

I had been planning to add sampling to one of my MCP servers. Then OP on r/mcp wrote that in v2 “sampling is getting deprecated… so it’s a bit of a ‘well that window’s closed’ feeling.” I had assumed “deprecated” meant “renommed and still works,” so my plan was to call it the same way and rename later.

It does not. Sampling is being removed, so any server that depends on it needs a redesign before the v2 upgrade, not a rename.

Environment

  • MCP v1 server, TypeScript SDK
  • Tool flows that delegate a model call to the connected client/host
  • Target: MCP v2, which drops sampling as a server capability

What happened?

Sampling is an odd direction. Normally the client calls the server’s tools. With sampling, the server turns around and asks the client/host to run an LLM call on the server’s behalf.

Sampling direction in v1
client --[call tool]--> server
server --[requestSampling]--> client (host runs the LLM)
client --[sampled text]--> server
server --[tool result]--> client

My v1 code looked like this:

v1-style MCP sampling request
server.onCallTool(async (req) => {
const sampled = await server.session.requestSampling({
messages: [{ role: "user", content: { type: "text", text: prompt } }],
modelPreferences: { hints: [{ name: "claude" }] },
});
return { text: sampled.content.text };
});

I can explain the key parts:

  • requestSampling goes UP the stack — the server is asking the host to run a model.
  • modelPreferences is a hint, not a guarantee. The host decides which model actually runs.
  • The result comes back into the server as if the server had called the model itself.

This looked elegant, but it made my server depend on three things I do not control: the host having a model available, the host’s billing policy, and the host’s permission flow. The moment I deploy behind a client that has no model configured, the tool breaks.

How to solve it?

There is no one-for-one replacement. The pattern shifts: in v2, the server makes its own model calls directly, or the client decides what to run without the server asking the model.

I tried the option that fits my server best — call my own model provider:

v2-style: server calls its own model provider
import { generateText } from "your-model-sdk";
server.onCallTool(async (req) => {
const { text } = await generateText({
model: "claude-...",
prompt,
});
return { text };
});

What changed and why:

  • The model call now lives in my server’s own code and config. The host is back to being a normal MCP client.
  • I control which model runs, what credentials it uses, and how it is billed.
  • Permissions are explicit. No more “the host will allow it if it feels like it.”

The other option is to redesign the flow so the client drives the model. In that case the server exposes a normal tool that takes a model_choice or similar argument, and the client picks the model instead of the server nudging it.

Direction reversal after the migration
v1: server --[requestSampling]--> client (host runs model)
host owns: model, billing, permission
v2: server --[generateText]--> model provider (server's own SDK)
server owns: model, billing, permission

You can see that I succeeded to make the tool work without depending on the host. It runs identically whether the host is a full-featured IDE or a thin CLI with no model.

The reason

I think the key reason sampling is being removed is that it conflicts with two things v2 cares about.

First, statelessness (covered in my other post). Sampling keeps context on the host tied to a session. That host-held context is exactly the kind of state the protocol is trying to push off the wire.

Second, predictable permission and billing. When the server asks the host to run a model, the host has to decide, at runtime, whether to pay for it. There is no clean way for the host to know whether to trust the server’s request. Servers that own their own model calls sidestep the whole question.

A common mistake I want to avoid is treating deprecation as “still supported, just renamed.” It is being removed. Any sampling-based feature is a dead path under v2 and will throw at runtime, not fall back gracefully. The right move is a real redesign: either bring the model into the server, or push the model-picking decision out to the client as a normal tool argument.

Summary

In this post, I showed what MCP sampling was and what to do now that MCP v2 deprecates it. The key point is to move model invocation into your own server (or let the client drive it through a normal tool) instead of asking the host to run the model for you.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments