{"record":{"id":"4cf873186a1adda4","repo":"PrefectHQ/fastmcp","slug":"the-function-fn-name-has-params-0-as-its-4cf873","errorCode":null,"errorMessage":"The function '{fn_name}' has '{params[0]}' as its first parameter. Use the standalone @tool decorator and register the bound method:\n\n    from fastmcp.tools import tool\n\n    class MyClass:\n        @tool\n        def {fn_name}(...):\n            ...\n\n    obj = MyClass()\n    mcp.add_tool(obj.{fn_name})\n\nSee https://gofastmcp.com/servers/tools#using-with-methods","messagePattern":"The function '(.+?)' has '(.+?)' as its first parameter\\. Use the standalone @tool decorator and register the bound method:\n\n    from fastmcp\\.tools import tool\n\n    class MyClass:\n        @tool\n        def (.+?)\\(\\.\\.\\.\\):\n            \\.\\.\\.\n\n    obj = MyClass\\(\\)\n    mcp\\.add_tool\\(obj\\.(.+?)\\)\n\nSee https://gofastmcp\\.com/servers/tools#using-with-methods","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py","lineNumber":287,"sourceCode":"            annotations = ToolAnnotations(**annotations)\n\n        if isinstance(name_or_fn, classmethod):\n            raise TypeError(\n                \"To decorate a classmethod, use @classmethod above @tool. \"\n                \"See https://gofastmcp.com/servers/tools#using-with-methods\"\n            )\n\n        def decorate_and_register(\n            fn: AnyFunction, tool_name: str | None\n        ) -> FunctionTool | AnyFunction:\n            # Check for unbound method\n            try:\n                params = list(inspect.signature(fn).parameters.keys())\n            except (ValueError, TypeError):\n                params = []\n            if params and params[0] in (\"self\", \"cls\"):\n                fn_name = getattr(fn, \"__name__\", \"function\")\n                raise TypeError(\n                    f\"The function '{fn_name}' has '{params[0]}' as its first parameter. \"\n                    f\"Use the standalone @tool decorator and register the bound method:\\n\\n\"\n                    f\"    from fastmcp.tools import tool\\n\\n\"\n                    f\"    class MyClass:\\n\"\n                    f\"        @tool\\n\"\n                    f\"        def {fn_name}(...):\\n\"\n                    f\"            ...\\n\\n\"\n                    f\"    obj = MyClass()\\n\"\n                    f\"    mcp.add_tool(obj.{fn_name})\\n\\n\"\n                    f\"See https://gofastmcp.com/servers/tools#using-with-methods\"\n                )\n\n            from fastmcp.tools.function_tool import ToolMeta\n\n            metadata = ToolMeta(\n                name=tool_name,\n                version=version,\n                title=title,","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py#L269-L305","documentation":"@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.","triggerScenarios":"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.","commonSituations":"Class-based tool organization; migrating tools from functions into a class; auto-generated code decorating methods in place.","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."],"exampleFix":"// before\nclass MyClass:\n    @tool\n    def lookup(self, key: str) -> str:\n        ...\n\n// after\nfrom fastmcp.tools import tool\n\nclass MyClass:\n    @tool\n    def lookup(self, key: str) -> str:\n        ...\n\nobj = MyClass()\nmcp.add_tool(obj.lookup)","handlingStrategy":"validation","validationCode":"import inspect\n\ndef validate_tool_fn(fn):\n    params = list(inspect.signature(fn).parameters)\n    if params and params[0] in ('self', 'cls'):\n        raise TypeError('use standalone @tool and register bound method: mcp.add_tool(obj.fn)')\n    return fn","typeGuard":"def is_unbound_method(fn) -> bool:\n    try:\n        params = list(inspect.signature(fn).parameters)\n    except (ValueError, TypeError):\n        return False\n    return bool(params) and params[0] in ('self', 'cls')","tryCatchPattern":"try:\n    mcp.add_tool(svc.lookup)\nexcept TypeError as e:\n    if \"first parameter\" in str(e) and ('self' in str(e) or 'cls' in str(e)):\n        logging.error('decorate in class body is not supported for tools')\n    raise","preventionTips":["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."],"tags":["python","fastmcp","tools","methods"],"backgroundTag":"decorator-applied-to-method","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}