PrefectHQ/fastmcp · error · ValueError
Component already exists: {component.key}
Error message
Component already exists: {component.key} What it means
LocalProvider was configured with on_duplicate='error', and a component with the same key (type + identifier + version) is already registered. Adding it again raises ValueError including the duplicate key, instead of silently replacing or ignoring.
Source
Thrown at fastmcp_slim/fastmcp/server/providers/local_provider/local_provider.py:190
f"Cannot add unversioned {type_name} {logical_name!r}: "
f"versioned {type_name}s with this name already exist "
f"(e.g., version={existing.version!r}). "
f"Either version all components or none."
)
def _add_component(self, component: _C) -> _C:
"""Add a component to unified storage.
Args:
component: The component to add.
Returns:
The component that was added (or existing if on_duplicate="ignore").
"""
existing = self._components.get(component.key)
if existing:
if self._on_duplicate == "error":
raise ValueError(f"Component already exists: {component.key}")
elif self._on_duplicate == "warn":
logger.warning(f"Component already exists: {component.key}")
elif self._on_duplicate == "ignore":
return existing # type: ignore[return-value] # ty:ignore[invalid-return-type]
# "replace" and "warn" fall through to add
# Check for versioned/unversioned mixing before adding
self._check_version_mixing(component)
self._components[component.key] = component
return component
def _remove_component(self, key: str) -> None:
"""Remove a component from unified storage.
Args:
key: The prefixed key of the component.
View on GitHub (pinned to 1f02114297)
Solutions
- Set on_duplicate='replace' (or 'ignore'/'warn') when constructing the provider/server to permit re-registration.
- Guard registration so each component is added only once (idempotent init, module-level once-guard).
- Bump or vary the component version/name if the duplicate is genuinely a distinct variant.
Example fix
// before mcp = FastMCP() # on_duplicate defaults to 'error' mcp.add_tool(my_tool) mcp.add_tool(my_tool) # raises // after from fastmcp.server.providers import LocalProvider provider = LocalProvider(on_duplicate='replace') mcp.add_provider(provider) mcp.add_tool(my_tool) mcp.add_tool(my_tool) # replaces
Defensive patterns
Strategy: try-catch
Validate before calling
existing_keys = {c.key for c in provider._components.values()}
if my_tool.key in existing_keys:
logging.warning('skipping duplicate registration for %s', my_tool.key)
else:
mcp.add_tool(my_tool) Type guard
def already_registered(provider, component) -> bool:
return component.key in {c.key for c in provider._components.values()} Try / catch
try:
mcp.add_tool(my_tool)
except ValueError as e:
if str(e).startswith('Component already exists'):
logging.info('tool already registered: %s', e)
else:
raise Prevention
- Make registration idempotent: guard with a once-flag or check existing keys.
- Configure on_duplicate='replace' or 'ignore' when re-registration is expected (tests, hot reload).
- Avoid executing registration modules multiple times against the same server instance.
- Give distinct variants distinct names or versions instead of re-adding the same key.
When it happens
Trigger: Calling add_tool/add_resource/add_template/add_prompt twice with the same name/uri/version while the provider's on_duplicate policy is 'error'; re-importing/re-running a registration module against a long-lived server object.
Common situations: Module-level registrations executed twice (hot reload, notebook re-runs, tests reusing a server fixture); plugin systems registering the same component from two files.
Related errors
- mcp_tool() got unexpected keyword argument(s): {sorted(unkno
- mcp_resource() got unexpected keyword argument(s): {sorted(u
- mcp_prompt() got unexpected keyword argument(s): {sorted(unk
- {name!r} moved to the fastmcp-tasks package. Install it with
- module {__name__!r} has no attribute {name!r}
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/9dee4e92507db8f1.
Report an issue: GitHub.