CreateMessageResult yourself when you want to report the real model name or hand back content that isn’t text. If the handler raises, the client sends the error back in place of a completion and the server’s tool decides what to do about it.
Handler Template
mode="auto" negotiates whichever protocol era the server speaks, and one handler covers both of the routes an era can use — see Request Routes.
Handler Parameters
Everything the server sends arrives in the first two arguments. The messages are the conversation to complete; the parameters are how the server would like it completed. You decide how much of that to honor, since the client owns the model — a preference your provider cannot express is yours to ignore.SamplingParams
str | None
Optional system prompt the server wants to use
ModelPreferences | None
Server preferences for model selection (hints, cost/speed/intelligence priorities)
float | None
Sampling temperature
int
Maximum tokens to generate
list[str] | None
Stop sequences for sampling
list[Tool] | None
Tools the LLM can use during sampling
ToolChoice | None
Tool usage behavior (
auto, required, or none)Built-in Handlers
Writing the provider call yourself is rarely worth it. FastMCP ships handlers for OpenAI, Anthropic, and Google Gemini that implement the full sampling API, tool use included, and translate the protocol’s parameters into each provider’s own. Give one a default model and pass it where your own handler would go. Write a custom handler when you need routing across providers, caching, or a provider FastMCP does not cover.OpenAI Handler
Install the OpenAI handler with
pip install 'fastmcp[openai]'.Anthropic Handler
Install the Anthropic handler with
pip install 'fastmcp[anthropic]'.Google Gemini Handler
Install the Google Gemini handler with
pip install 'fastmcp[gemini]'.Tool Use
A sampling request can carry tools. When it does, your handler passes them to the model and returns whatever comes back, tool calls included — the server executes the tools itself and sends a follow-up sampling request with the results if it needs another turn. Your handler never runs a tool. Registering anysampling_handler advertises full sampling support, tools included. A handler that only generates text should say so, so servers know not to send tools it will drop:
Request Routes
Servers reach your handler by two routes, and which one applies depends on the protocol era the connection negotiated. A handshake-era server pushes asampling/createMessage request down the open session while a tool is running and waits for the reply. A modern (2026-07-28) connection has no such channel, so the tool ends its round by returning a request for a completion instead; the client answers from your handler and calls the tool again with the result attached.
One registration covers both, so this is rarely something you configure — it matters only when you pin an era, since mode="legacy" is the sole route that carries a pushed request. See protocol negotiation for how the era is chosen, and Sampling under Servers for how a server issues these requests.
