PrefectHQ/fastmcp · error
Functions with *args are not supported as tools
Error message
Functions with *args are not supported as tools
What it means
Tools reject `*args` because MCP arguments are a named JSON object — there is no way for a client to supply extra positional arguments, and `*args` can't be represented in the tool's input schema. `FunctionTool.from_function` raises ValueError when it sees a VAR_POSITIONAL parameter.
Source
Thrown at fastmcp_slim/fastmcp/tools/function_parsing.py:268
cls,
fn: Callable[..., Any],
validate: bool = True,
wrap_non_object_output_schema: bool = True,
) -> ParsedFunction:
if validate:
sig = inspect.signature(fn)
# Reject signatures that cannot be represented by MCP's
# object-shaped tool arguments.
for param in sig.parameters.values():
if param.kind == inspect.Parameter.POSITIONAL_ONLY:
raise ValueError(
"Functions with positional-only parameters are not "
"supported as tools because MCP passes tool arguments by "
"name. Replace them with standard parameters that can be "
"passed as keywords."
)
if param.kind == inspect.Parameter.VAR_POSITIONAL:
raise ValueError("Functions with *args are not supported as tools")
if param.kind == inspect.Parameter.VAR_KEYWORD:
raise ValueError(
"Functions with **kwargs are not supported as tools"
)
# collect name and description before we potentially modify the function
fn_name = getattr(fn, "__name__", None) or fn.__class__.__name__
outer_docstring = parse_docstring(fn)
# if the fn is a callable class, we need to get the __call__ method from here out
if not inspect.isroutine(fn) and not isinstance(fn, functools.partial):
fn = fn.__call__
# if the fn is a staticmethod, we need to work with the underlying function
if isinstance(fn, staticmethod):
fn = fn.__func__
# For callable classes, parameter descriptions must come from
# __call__'s docstring — where the exposed parameters are actuallyView on GitHub (pinned to 1f02114297)
Solutions
- Replace `*args` with explicit named parameters (e.g. `filters: list[str] | None = None`).
- Accept a list/dict parameter and iterate inside the function.
- Write a keyword-only wrapper function with explicit params and register that.
Example fix
# before def search(term, *filters): ... # after def search(term, filters: list[str] | None = None): ...
Defensive patterns
Strategy: validation
Validate before calling
import inspect
def tool_ready(fn) -> bool:
return not any(p.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD)
for p in inspect.signature(fn).parameters.values()) Try / catch
try:
tool = FunctionTool.from_function(fn)
except ValueError as e:
if "*args" in str(e):
raise TypeError(f"{fn.__name__} must declare explicit parameters to be a tool")
raise Prevention
- Design tool functions with fully explicit, typed parameters.
- Lint for VAR_POSITIONAL in modules registered as tools.
- Model variable argument sets as list/dict parameters.
When it happens
Trigger: `FunctionTool.from_function(fn)` or `@mcp.tool` on functions like `def search(term, *filters)`; wrappers that forward arbitrary args; decorating a generic dispatcher function as a tool.
Common situations: Exposing variadic helper/utility functions; thin wrappers around logging or CLI-style APIs; code written before joining the project that assumed variadics would work over MCP.
Related errors
- Functions with positional-only parameters are not supported
- Functions with **kwargs are not supported as tools
- Cannot resolve tool reference: {fn!r}
- Cannot determine tool name for {fn!r}
- File {name!r} not found. Available: {available}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/427580339ef8bfe8.
Report an issue: GitHub.