PrefectHQ/fastmcp · error · NotImplementedError
Subclasses must implement run()
Error message
Subclasses must implement run()
What it means
Tool is an abstract base class; `run()` is the abstract method every concrete tool must implement to execute and produce a ToolResult. Calling `run()` on a subclass that didn't override it raises NotImplementedError. The base class deliberately fails fast instead of silently returning nothing.
Source
Thrown at fastmcp_slim/fastmcp/tools/base.py:365
)
async def run(self, arguments: dict[str, Any]) -> ToolResult:
"""
Run the tool with arguments.
This method is not implemented in the base Tool class and must be
implemented by subclasses.
`run()` can EITHER return a list of ContentBlocks, or a tuple of
(list of ContentBlocks, dict of structured output).
A tool that requests client input (SEP-2322 multi-round-trip) does so by
returning an `InputRequiredResult` from its body; the run machinery wraps
that in an `InputRequiredToolResult` — a `ToolResult` subclass — so it
stays inside the declared `ToolResult` result type and flows through the
middleware chain as an ordinary result (see `FunctionTool.run`).
"""
raise NotImplementedError("Subclasses must implement run()")
def convert_result(self, raw_value: Any) -> ToolResult:
"""Convert a raw result to ToolResult.
Handles ToolResult passthrough and converts raw values using the tool's
attributes (output_schema) for proper conversion.
"""
if isinstance(raw_value, ToolResult):
return raw_value
if isinstance(raw_value, CallToolResult):
return ToolResult.from_mcp_result(raw_value)
if is_prefab_app(raw_value):
return _prefab_to_tool_result(
raw_value,
fastmcp_app_name=_get_fastmcp_app_name(self),
)View on GitHub (pinned to 1f02114297)
Solutions
- Implement `run(self, context) -> ToolResult` in your subclass.
- Prefer subclassing `FunctionTool` and using `from_function` rather than implementing Tool from scratch.
- After upgrades, check whether your override should be `run` vs `_run` and rename accordingly.
- Make custom base classes themselves raise early or be ABCs so misuse is caught at instantiation.
Example fix
# before
class MyTool(Tool):
def _run(self, ctx):
...
# after
class MyTool(Tool):
async def run(self, context):
return ToolResult(content="done") Defensive patterns
Strategy: validation
Validate before calling
def ensure_concrete(tool_cls) -> bool:
return getattr(tool_cls.run, "__isabstractmethod__", False) is not True and \
not (getattr(tool_cls.run, "__qualname__", "").startswith("Tool.")) Try / catch
try:
result = await tool.run(ctx)
except NotImplementedError:
raise TypeError(f"{type(tool).__name__} does not implement run()") Prevention
- Use abc.ABC / @abstractmethod on custom base classes to fail at instantiation.
- Subclass FunctionTool instead of the abstract Tool base.
- After upgrades, grep custom tools for `def _run` and confirm the run/_run contract.
When it happens
Trigger: Subclassing `Tool` (or another Tool subclass) and implementing only `_run`/metadata without overriding `run()`; calling `run()` on the base class or an incomplete subclass instance; refactoring that renamed an override so it no longer binds as `run`.
Common situations: Custom tool abstractions layered on top of FastMCP that only override internal hooks; after a library upgrade, an inherited class whose overridden method was renamed (run vs _run contract change); instantiating an abstract-like helper class directly in tests.
Related errors
- Functions with positional-only parameters are not supported
- Functions with *args are not supported as tools
- Functions with **kwargs are not supported as tools
- module {__name__!r} has no attribute {name!r}
- Cannot resolve tool reference: {fn!r}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/607e35ce48b22a92.
Report an issue: GitHub.