PrefectHQ/fastmcp · error · TypeError
The function '{fn_name}' has '{params[0]}' as its first para
Error message
The function '{fn_name}' has '{params[0]}' as its first parameter. Use the standalone @tool decorator and register the bound method:
from fastmcp.tools import tool
class MyClass:
@tool
def {fn_name}(...):
...
obj = MyClass()
mcp.add_tool(obj.{fn_name})
See https://gofastmcp.com/servers/tools#using-with-methods What it means
@tool was applied to an unbound method whose first parameter is `self` (or `cls`). FastMCP does not auto-bind methods at decoration time inside a class body, so it refuses and directs you to decorate with the standalone @tool and register the bound method on the server.
Source
Thrown at fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py:287
annotations = ToolAnnotations(**annotations)
if isinstance(name_or_fn, classmethod):
raise TypeError(
"To decorate a classmethod, use @classmethod above @tool. "
"See https://gofastmcp.com/servers/tools#using-with-methods"
)
def decorate_and_register(
fn: AnyFunction, tool_name: str | None
) -> FunctionTool | AnyFunction:
# Check for unbound method
try:
params = list(inspect.signature(fn).parameters.keys())
except (ValueError, TypeError):
params = []
if params and params[0] in ("self", "cls"):
fn_name = getattr(fn, "__name__", "function")
raise TypeError(
f"The function '{fn_name}' has '{params[0]}' as its first parameter. "
f"Use the standalone @tool decorator and register the bound method:\n\n"
f" from fastmcp.tools import tool\n\n"
f" class MyClass:\n"
f" @tool\n"
f" def {fn_name}(...):\n"
f" ...\n\n"
f" obj = MyClass()\n"
f" mcp.add_tool(obj.{fn_name})\n\n"
f"See https://gofastmcp.com/servers/tools#using-with-methods"
)
from fastmcp.tools.function_tool import ToolMeta
metadata = ToolMeta(
name=tool_name,
version=version,
title=title,View on GitHub (pinned to 1f02114297)
Solutions
- Use the standalone @tool decorator on the method and register the bound method: mcp.add_tool(obj.method).
- Make it a staticmethod (no self) if instance state isn't needed, or a module-level function.
- For classmethods, place @classmethod above @tool.
Example fix
// before
class MyClass:
@tool
def lookup(self, key: str) -> str:
...
// after
from fastmcp.tools import tool
class MyClass:
@tool
def lookup(self, key: str) -> str:
...
obj = MyClass()
mcp.add_tool(obj.lookup) Defensive patterns
Strategy: validation
Validate before calling
import inspect
def validate_tool_fn(fn):
params = list(inspect.signature(fn).parameters)
if params and params[0] in ('self', 'cls'):
raise TypeError('use standalone @tool and register bound method: mcp.add_tool(obj.fn)')
return fn Type guard
def is_unbound_method(fn) -> bool:
try:
params = list(inspect.signature(fn).parameters)
except (ValueError, TypeError):
return False
return bool(params) and params[0] in ('self', 'cls') Try / catch
try:
mcp.add_tool(svc.lookup)
except TypeError as e:
if "first parameter" in str(e) and ('self' in str(e) or 'cls' in str(e)):
logging.error('decorate in class body is not supported for tools')
raise Prevention
- Register bound methods post-instantiation: mcp.add_tool(obj.method).
- Use staticmethod or plain functions when instance state isn't required.
- For classmethods keep @classmethod above @tool.
When it happens
Trigger: Decorating an instance method (def method(self, ...)) or classmethod's underlying function with @tool inside a class body and expecting it to be registered as-is.
Common situations: Class-based tool organization; migrating tools from functions into a class; auto-generated code decorating methods in place.
Related errors
- The function '{fn_name}' has '{params[0]}' as its first para
- To decorate a classmethod, use @classmethod above @tool. See
- Cannot specify both a name as first argument and as keyword
- First argument to @tool must be a function, string, or None,
- mcp_tool() got unexpected keyword argument(s): {sorted(unkno
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/4cf873186a1adda4.
Report an issue: GitHub.