agentscope-ai/agentscope · error · ValueError

An MCP named {mcp_record.name!r} already exists for this use

Error message

An MCP named {mcp_record.name!r} already exists for this user.

What it means

Raised by SQLStorage.upsert_mcp when creating or updating an installed-MCP record whose name is already taken by a different MCP record owned by the same user. Names are unique per user, so the check compares the existing record's id with the incoming mcp_record.id; a mismatch means a name collision with another record.

Source

Thrown at src/agentscope/app/storage/_sql/_storage.py:838

        return result.rowcount > 0

    # ------------------------------------------------------------------
    # Installed MCPs and skills
    #
    # ``(user_id, name)`` is unique on both tables. The pre-write lookup
    # below turns the common case into the same ``ValueError`` the Redis
    # backend raises; the constraint is the backstop that closes the
    # read-then-write window between concurrent writers.
    # ------------------------------------------------------------------

    async def upsert_mcp(self, user_id: str, mcp_record: MCPRecord) -> str:
        """Create or update an installed-MCP record for *user_id*.

        Same contract as :meth:`RedisStorage.upsert_mcp`.
        """
        holder = await self.get_mcp_by_name(user_id, mcp_record.name)
        if holder is not None and holder.id != mcp_record.id:
            raise ValueError(
                f"An MCP named {mcp_record.name!r} already exists for "
                f"this user.",
            )
        mcp_record.user_id = user_id
        await self._write_row(MCPRow, mcp_record)
        return mcp_record.id

    async def list_mcps(self, user_id: str) -> list[MCPRecord]:
        """Return every installed-MCP record for *user_id*."""
        from sqlalchemy import select

        async with self._session() as sess:
            rows = (
                (
                    await sess.execute(
                        select(MCPRow).where(MCPRow.user_id == user_id),
                    )
                )

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Choose a unique name for the MCP record before upserting
  2. If updating an existing MCP, load it first (get_mcp_by_name) and reuse its id and mutate fields instead of creating a new record
  3. Delete the conflicting record (delete_mcp) before re-registering with the same name

Example fix

// before
await storage.upsert_mcp(user_id, MCPRecord(id=new_id, name="fs"))  # name clash
// after
existing = await storage.get_mcp_by_name(user_id, "fs")
if existing:
    existing.command = new_cmd
    await storage.upsert_mcp(user_id, existing)  # same id -> update
else:
    await storage.upsert_mcp(user_id, MCPRecord(name="fs", ...))
Defensive patterns

Strategy: validation

Validate before calling

existing = await storage.get_mcp_by_name(user_id, record.name)
if existing is not None and existing.id != record.id:
    record.name = f"{record.name}-{uuid4().hex[:6]}"  # or merge into existing

Try / catch

try:\n    await storage.upsert_mcp(user_id, rec)\nexcept ValueError as e:\n    if \"already exists\" in str(e): handle_name_collision(rec)\n    else: raise

Prevention

When it happens

Trigger: Calling upsert_mcp(user_id, record) where record.name matches an existing MCP for that user but record.id differs (e.g. a new record reusing an existing name, or an update that changed the id).

Common situations: Re-installing an MCP under a name already registered for the user; copying MCP config between environments without preserving record ids; concurrent installs racing on the same name.

Related errors


AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28). Data as JSON: /api/errors/8d0e93358589f79f. Report an issue: GitHub.