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 cannot be applied directly to a classmethod object. When name_or_fn is a classmethod (i.e. @prompt is stacked BELOW @classmethod), the decorator raises TypeError immediately with a doc link. The supported ordering is @classmethod on top and @prompt underneath, so @prompt sees the plain function.

Source

Thrown at fastmcp_slim/fastmcp/prompts/function_prompt.py:413

def prompt(
    name_or_fn: str | Callable[..., Any] | None = None,
    *,
    name: str | None = None,
    version: str | int | None = None,
    title: str | None = None,
    description: str | None = None,
    icons: list[Icon] | None = None,
    tags: set[str] | None = None,
    meta: dict[str, Any] | None = None,
    auth: AuthCheck | list[AuthCheck] | None = None,
) -> Any:
    """Standalone decorator to mark a function as an MCP prompt.

    Returns the original function with metadata attached. Register with a server
    using mcp.add_prompt().
    """
    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 attach_metadata(fn: F, prompt_name: str | None) -> F:
        metadata = PromptMeta(
            name=prompt_name,
            version=version,
            title=title,
            description=description,
            icons=icons,
            tags=tags,
            meta=meta,
            auth=auth,
        )
        target = fn.__func__ if isinstance(fn, staticmethod | MethodType) else fn
        cast(Any, target).__fastmcp__ = metadata
        return fn

View on GitHub (pinned to 1f02114297)

Solutions

  1. Reorder the decorators so @classmethod is above @prompt: @classmethod @prompt def my_prompt(cls): ...
  2. Alternatively convert to a plain @staticmethod or module-level function and decorate with @prompt
  3. See the linked docs page for the supported method pattern

Example fix

// before
class Prompts:
    @prompt
    @classmethod
    def greeting(cls): ...
// after
class Prompts:
    @classmethod
    @prompt
    def greeting(cls): ...
Defensive patterns

Strategy: type-guard

Validate before calling

import inspect
if isinstance(name_or_fn, classmethod):
    raise TypeError('put @classmethod above @prompt')

Type guard

def is_valid_prompt_target(obj) -> bool:
    return not isinstance(obj, classmethod) and (inspect.isroutine(obj) or isinstance(obj, str) or obj is None)

Try / catch

try:
    decorated = prompt(my_method)
except TypeError as e:
    if 'classmethod' in str(e):
        raise SyntaxError('use @classmethod above @prompt') from e
    raise

Prevention

When it happens

Trigger: Writing: class Foo: @prompt @classmethod def my_prompt(cls): ... — i.e. @prompt placed above @classmethod, so prompt receives a classmethod descriptor as name_or_fn.

Common situations: Copy-pasting method-based prompt examples and flipping the decorator order; migrating tools to prompts while keeping classmethod layout; misunderstanding which decorator must be outermost.

Related errors


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