PrefectHQ/fastmcp · error · TypeError

To decorate a classmethod, use @classmethod above @prompt. S

Error message

To decorate a classmethod, use @classmethod above @prompt. See https://gofastmcp.com/servers/prompts#using-with-methods

What it means

The `@prompt` decorator does not support decorating a `classmethod` object directly. If `name_or_fn` is a `classmethod`, a TypeError is raised pointing at the documented method-registration pattern.

Source

Thrown at fastmcp_slim/fastmcp/server/providers/local_provider/decorators/prompts.py:156

        Returns:
            The registered FunctionPrompt or a decorator function.

        Example:
            ```python
            provider = LocalProvider()

            @provider.prompt
            def analyze(topic: str) -> list:
                return [{"role": "user", "content": f"Analyze: {topic}"}]

            @provider.prompt("custom_name")
            def my_prompt(data: str) -> list:
                return [{"role": "user", "content": data}]
            ```
        """
        if isinstance(name_or_fn, classmethod):
            raise TypeError(
                "To decorate a classmethod, use @classmethod above @prompt. "
                "See https://gofastmcp.com/servers/prompts#using-with-methods"
            )

        def decorate_and_register(
            fn: AnyFunction, prompt_name: str | None
        ) -> FunctionPrompt | 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 @prompt decorator and register the bound method:\n\n"
                    f"    from fastmcp.prompts import prompt\n\n"

View on GitHub (pinned to 1f02114297)

Solutions

  1. Put `@classmethod` above `@prompt` (classmethod outermost) if using the standalone decorator
  2. Prefer the documented pattern: decorate with standalone `@prompt` inside the class, then register the bound method via `mcp.add_prompt(obj.my_prompt)`
  3. Make the method a regular method or staticmethod if class access isn't required

Example fix

// before
class C:
    @provider.prompt
    @classmethod
    def p(cls, x): ...
// after
class C:
    @classmethod
    @prompt
    def p(cls, x): ...
obj = C()
mcp.add_prompt(obj.p)
Defensive patterns

Strategy: validation

Validate before calling

import inspect
if isinstance(fn, classmethod):
    raise TypeError('reorder decorators: @classmethod above @prompt')

Type guard

def decorable(fn) -> bool:
    import inspect
    return inspect.isroutine(fn) and not isinstance(fn, classmethod)

Try / catch

try:
    provider.prompt(fn)
except TypeError as e:
    if 'classmethod' in str(e): use_bound_method_pattern()

Prevention

When it happens

Trigger: Writing `@provider.prompt` above `@classmethod` (so the decorator receives the classmethod object), or calling `provider.prompt(classmethod(SomeClass.method))`.

Common situations: Decorating methods inside classes with the provider-scoped decorator; reordering decorators after refactoring; following old examples that stacked `@prompt` with `@classmethod`.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/1dfeec910efd1605. Report an issue: GitHub.