{"record":{"id":"427580339ef8bfe8","repo":"PrefectHQ/fastmcp","slug":"functions-with-args-are-not-supported-as-tools","errorCode":null,"errorMessage":"Functions with *args are not supported as tools","messagePattern":"Functions with \\*args are not supported as tools","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/tools/function_parsing.py","lineNumber":268,"sourceCode":"        cls,\n        fn: Callable[..., Any],\n        validate: bool = True,\n        wrap_non_object_output_schema: bool = True,\n    ) -> ParsedFunction:\n        if validate:\n            sig = inspect.signature(fn)\n            # Reject signatures that cannot be represented by MCP's\n            # object-shaped tool arguments.\n            for param in sig.parameters.values():\n                if param.kind == inspect.Parameter.POSITIONAL_ONLY:\n                    raise ValueError(\n                        \"Functions with positional-only parameters are not \"\n                        \"supported as tools because MCP passes tool arguments by \"\n                        \"name. Replace them with standard parameters that can be \"\n                        \"passed as keywords.\"\n                    )\n                if param.kind == inspect.Parameter.VAR_POSITIONAL:\n                    raise ValueError(\"Functions with *args are not supported as tools\")\n                if param.kind == inspect.Parameter.VAR_KEYWORD:\n                    raise ValueError(\n                        \"Functions with **kwargs are not supported as tools\"\n                    )\n\n        # collect name and description before we potentially modify the function\n        fn_name = getattr(fn, \"__name__\", None) or fn.__class__.__name__\n        outer_docstring = parse_docstring(fn)\n\n        # if the fn is a callable class, we need to get the __call__ method from here out\n        if not inspect.isroutine(fn) and not isinstance(fn, functools.partial):\n            fn = fn.__call__\n        # if the fn is a staticmethod, we need to work with the underlying function\n        if isinstance(fn, staticmethod):\n            fn = fn.__func__\n\n        # For callable classes, parameter descriptions must come from\n        # __call__'s docstring — where the exposed parameters are actually","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/tools/function_parsing.py#L250-L286","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"# before\ndef search(term, *filters): ...\n# after\ndef search(term, filters: list[str] | None = None): ...","handlingStrategy":"validation","validationCode":"import inspect\ndef tool_ready(fn) -> bool:\n    return not any(p.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD)\n                   for p in inspect.signature(fn).parameters.values())","typeGuard":null,"tryCatchPattern":"try:\n    tool = FunctionTool.from_function(fn)\nexcept ValueError as e:\n    if \"*args\" in str(e):\n        raise TypeError(f\"{fn.__name__} must declare explicit parameters to be a tool\")\n    raise","preventionTips":["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."],"tags":["python","valueerror","var-args","signature-validation","tool"],"backgroundTag":"unsupported-signature","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}