PrefectHQ/fastmcp · error · ValueError
Unsupported tool_choice mode: {tool_choice.mode!r}
Error message
Unsupported tool_choice mode: {tool_choice.mode!r} What it means
_convert_tool_choice_to_anthropic raises ValueError for a ToolChoice mode it does not recognize. Anthropic supports auto/any (required)/none mappings; anything else (e.g. a new MCP mode) is rejected rather than silently mis-mapped.
Source
Thrown at fastmcp_slim/fastmcp/client/sampling/handlers/anthropic.py:404
@staticmethod
def _convert_tool_choice_to_anthropic(
tool_choice: ToolChoice,
) -> ToolChoiceParam | None:
"""Convert MCP tool_choice to Anthropic format.
Returns None for "none" mode, signaling that tools should be omitted
from the request entirely (Anthropic doesn't have an explicit "none" option).
"""
if tool_choice.mode == "auto":
return ToolChoiceAutoParam(type="auto")
elif tool_choice.mode == "required":
return ToolChoiceAnyParam(type="any")
elif tool_choice.mode == "none":
# Anthropic doesn't have a "none" option - return None to signal
# that tools should be omitted from the request entirely
return None
else:
raise ValueError(f"Unsupported tool_choice mode: {tool_choice.mode!r}")
@staticmethod
def _message_to_result_with_tools(
message: Message,
) -> CreateMessageResultWithTools:
"""Convert Anthropic response to CreateMessageResultWithTools."""
if len(message.content) == 0:
raise ValueError("No content in response from Anthropic")
# Determine stop reason
stop_reason: StopReason
if message.stop_reason == "tool_use":
stop_reason = "toolUse"
elif message.stop_reason == "end_turn":
stop_reason = "endTurn"
elif message.stop_reason == "max_tokens":
stop_reason = "maxTokens"
elif message.stop_reason == "stop_sequence":View on GitHub (pinned to 1f02114297)
Solutions
- Set tool_choice.mode to 'auto', 'required', or 'none' before calling the handler.
- Upgrade fastmcp-slim in case a newer MCP mode has gained support.
- Catch ValueError and default tool_choice to auto in your sampling callback.
- Check the server implementation producing the sampling request for non-standard modes.
Example fix
// before params.tool_choice = ToolChoice(mode="specific") // after params.tool_choice = ToolChoice(mode="auto") # or 'required' / 'none'
Defensive patterns
Strategy: validation
Validate before calling
VALID_MODES = {"auto", "required", "none"}
if params.tool_choice and params.tool_choice.mode not in VALID_MODES:
params.tool_choice = None # or ToolChoice(mode="auto") Type guard
def is_valid_tool_choice(tc) -> bool:
return tc is None or getattr(tc, "mode", None) in {"auto", "required", "none"} Try / catch
try:
result = await handler(messages, params, context)
except ValueError as e:
if "Unsupported tool_choice mode" in str(e):
params.tool_choice = ToolChoice(mode="auto")
result = await handler(messages, params, context)
else:
raise Prevention
- Only use auto/required/none with the Anthropic handler
- Never forward another provider's tool_choice values verbatim
- Keep fastmcp-slim updated for new MCP tool_choice modes
- Validate SamplingParams server-side before sending
When it happens
Trigger: A server sends a sampling request with tool_choice.mode set to a value other than 'auto', 'required', or 'none' (or a newer MCP spec mode the handler predates).
Common situations: MCP spec updates introducing new tool_choice modes; hand-constructed SamplingParams with a typo'd mode string; forwarding a tool_choice from another provider unmodified.
Related errors
- Unsupported content type: {type(content)}
- Unsupported image MIME type for Anthropic: {content.mime_typ
- ImageContent is only supported in user messages for Anthropi
- AudioContent is not supported by the Anthropic API
- Unsupported content type for Anthropic: {type(item).__name__
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/864799a213248611.
Report an issue: GitHub.