PrefectHQ/fastmcp · error · TypeError
Cannot specify both a name as first argument and as keyword
Error message
Cannot specify both a name as first argument and as keyword argument. Use either @tool('{name_or_fn}') or @tool(name='{name}'), not both. What it means
@tool accepts a tool name either as the first positional string argument or via the name keyword, but not both. Passing both is ambiguous, so FastMCP raises a TypeError explaining the two supported forms.
Source
Thrown at fastmcp_slim/fastmcp/server/providers/local_provider/decorators/tools.py:329
meta=meta,
task=task,
timeout=timeout,
auth=auth,
enabled=enabled,
run_in_thread=run_in_thread,
)
target = fn.__func__ if hasattr(fn, "__func__") else fn
target.__fastmcp__ = metadata # type: ignore[attr-defined] # ty:ignore[unresolved-attribute]
self.add_tool(fn)
return fn
if inspect.isroutine(name_or_fn):
return decorate_and_register(name_or_fn, name)
elif isinstance(name_or_fn, str):
# Case 3: @tool("custom_name") - name passed as first argument
if name is not None:
raise TypeError(
"Cannot specify both a name as first argument and as keyword argument. "
f"Use either @tool('{name_or_fn}') or @tool(name='{name}'), not both."
)
tool_name = name_or_fn
elif name_or_fn is None:
# Case 4: @tool() or @tool(name="something") - use keyword name
tool_name = name
else:
raise TypeError(
f"First argument to @tool must be a function, string, or None, got {type(name_or_fn)}"
)
# Return partial for cases where we need to wait for the function
return partial(
self.tool,
name=tool_name,
version=version,
title=title,View on GitHub (pinned to 1f02114297)
Solutions
- Keep only one: either @tool('name') or @tool(name='name').
- If the two names differ, decide which one is intended and remove the other; the description-style first argument does not exist — only name is positional.
Example fix
// before
@tool('my_tool', name='my_tool')
def my_tool(x: int) -> str:
...
// after
@tool('my_tool')
def my_tool(x: int) -> str:
... Defensive patterns
Strategy: validation
Validate before calling
def check_tool_args(*args, **kwargs):
positional_names = [a for a in args if isinstance(a, str)]
if positional_names and kwargs.get('name') is not None:
raise TypeError('pass the tool name either positionally or via name=, not both')
check_tool_args('my_tool', name='my_tool') # would raise Type guard
def name_conflict(first_arg, name) -> bool:
return isinstance(first_arg, str) and name is not None Try / catch
try:
register_tools()
except TypeError as e:
if 'both a name as first argument and as keyword' in str(e):
logging.error('remove the duplicate tool name argument')
raise Prevention
- Pick one convention repo-wide, e.g. always @tool('name').
- Never pass name= together with a positional string.
- Let linters/review flag decorator calls with both positional string and name=.
When it happens
Trigger: Calling @tool('my_tool', name='my_tool') or @tool('custom', name='other') — a string as the first argument together with a non-None name keyword.
Common situations: Refactoring from @tool(name='x') to @tool('x') (or vice versa) and leaving both in place; IDE auto-completes adding a duplicate name argument; copy-paste from two examples.
Related errors
- To decorate a classmethod, use @classmethod above @tool. See
- The function '{fn_name}' has '{params[0]}' as its first para
- First argument to @tool must be a function, string, or None,
- mcp_tool() got unexpected keyword argument(s): {sorted(unkno
- mcp_resource() got unexpected keyword argument(s): {sorted(u
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/f5a748db4ca2c9fa.
Report an issue: GitHub.