BerriAI/litellm · warning · HTTPException

MCP Server not found, passed server_id={server_id}

Error message

MCP Server not found, passed server_id={server_id}

What it means

Returned (404) by the delete MCP server endpoint when delete_mcp_server finds no DB row for server_id (it returns None, which the endpoint converts to this 404). Deletion operates purely on the database: a server that exists only in config.yaml or only in the in-memory registry has no row and therefore cannot be deleted here.

Source

Thrown at litellm/proxy/management_endpoints/mcp_management_endpoints.py:2011

            "Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keys"
        )

        # Authz - restrict only admins to delete mcp servers
        if LitellmUserRoles.PROXY_ADMIN != user_api_key_dict.user_role:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail={
                    "error": "Call not allowed to delete MCP server. User is not a proxy admin. route={}".format(
                        "DELETE /v1/mcp/server"
                    )
                },
            )

        # try to delete the mcp server
        mcp_server_record_deleted: Final = await delete_mcp_server(prisma_client, server_id)

        if mcp_server_record_deleted is None:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail={"error": f"MCP Server not found, passed server_id={server_id}"},
            )
        global_mcp_server_manager.remove_server(mcp_server_record_deleted)

        # Ensure registry is up to date by reloading from database
        await global_mcp_server_manager.reload_servers_from_database()

        # TODO: Enterprise: Finish audit log trail
        if litellm.store_audit_logs:
            pass

        # TODO: Delete from virtual keys

        # TODO: Delete from teams

        # Update from global mcp store

View on GitHub (pinned to 77b7c6c40c)

Solutions

  1. List servers first and confirm the exact server_id exists in the DB-backed list.
  2. Treat 404 on delete as success when your goal is 'make it gone'.
  3. For config-defined servers, remove the entry from the config and restart/reload the proxy instead of calling the delete endpoint.

Example fix

# before
resp = requests.delete(f"{PROXY}/v1/mcp/server/{server_id}", headers=AUTH)
resp.raise_for_status()

# after: idempotent delete
resp = requests.delete(f"{PROXY}/v1/mcp/server/{server_id}", headers=AUTH)
if resp.status_code == 404:
    pass  # already gone
else:
    resp.raise_for_status()
Defensive patterns

Strategy: try-catch

Validate before calling

servers = requests.get(f"{PROXY}/v1/mcp/server", headers=AUTH).json()["servers"]
if server_id not in {s["server_id"] for s in servers}:
    return  # nothing to delete; config-defined servers are removed via config.yaml instead

Try / catch

try:
    delete_server(server_id)
except HTTPError as e:
    if e.response.status_code == 404:
        return  # idempotent delete: already gone
    raise

Prevention

When it happens

Trigger: DELETE /v1/mcp/server/{server_id} with a typo'd id; deleting a server that was already deleted (double-delete, or concurrent deletes); attempting to delete a config-defined server that was never persisted to the DB.

Common situations: Cleanup scripts re-run after success; server actually defined in the proxy config file rather than the DB; another admin removed the server first.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18). Data as JSON: /api/errors/ebca5ef95744c6f7. Report an issue: GitHub.