El mayor portal de MU Online de Brasil — desde 2003
Tutorial Avanzado Tutoriais

Cómo Integrar un Bot de Discord con tu Servidor de MU Online

Aprende a crear y configurar un bot de Discord que se conecta a la base de datos SQL Server de tu servidor MU Online para mostrar rankings, estado y notificaciones.

EQ Equipo ViciadosMU · Actualizado el 3 jul 2026 · ⏱ 12 min de lectura

Resumen

Integrar un bot de Discord con tu servidor de MU Online te permite automatizar tareas como mostrar rankings en tiempo real, notificar el Castle Siege, anunciar los top resets y monitorear el estado del servidor — todo directamente en los canales de Discord de tu comunidad.

Este tutorial cubre la creación de un bot con Node.js + discord.js v14, la conexión al SQL Server del MuServer (Season 6 Episode 3, compatible con S4–S13) y la implementación en el mismo VPS con Windows Server donde corre el servidor MU.


Requisitos previos

  • VPS con Windows Server 2012/2016/2019 y MuServer instalado
  • SQL Server 2008/2012/2014/2017 con la base de datos MuOnline accesible
  • Node.js 18 LTS instalado en el VPS (o en otra máquina con acceso al puerto 1433)
  • Una cuenta de desarrollador de Discord con permiso para crear aplicaciones
  • Acceso al panel de Discord Developer Portal

Parte 1 — Crear la Aplicación y el Bot en Discord

1. Accede a discord.com/developers/applications y haz clic en New Application.

2. Asigna un nombre a la aplicación (ej: MuBot ViciadosMU) y confirma.

3. En el menú lateral, ve a Bot → haz clic en Add Bot → confirma.

4. En Privileged Gateway Intents, habilita:

  • SERVER MEMBERS INTENT
  • MESSAGE CONTENT INTENT

5. Copia el Token del bot — lo usarás en el archivo .env. Nunca compartas este token públicamente.

6. Ve a OAuth2 → URL Generator, marca los scopes bot y applications.commands, y en permisos marca:

  • Send Messages
  • Embed Links
  • Read Message History
  • Use Slash Commands

7. Copia la URL generada, ábrela en el navegador y agrega el bot al servidor de Discord de tu comunidad.


Parte 2 — Configurar SQL Server para Conexiones

1. Abre el SQL Server Configuration Manager en el VPS.

2. En SQL Server Network Configuration → Protocols for MSSQLSERVER, habilita TCP/IP.

3. Haz doble clic en TCP/IP → pestaña IP Addresses → desplázate hasta IPAll → establece TCP Port en 1433.

4. Reinicia el servicio de SQL Server:

net stop MSSQLSERVER
net start MSSQLSERVER

5. Crea un usuario SQL de solo lectura exclusivo para el bot (no uses sa):

USE [master]
GO

CREATE LOGIN [mubot_reader] WITH PASSWORD = 'TuContrasenaSegura!123',
    DEFAULT_DATABASE = [MuOnline],
    CHECK_EXPIRATION = OFF,
    CHECK_POLICY = OFF;
GO

USE [MuOnline]
GO

CREATE USER [mubot_reader] FOR LOGIN [mubot_reader];
GO

-- Permiso de lectura solo en las tablas necesarias
GRANT SELECT ON [dbo].[Character] TO [mubot_reader];
GRANT SELECT ON [dbo].[MEMB_INFO] TO [mubot_reader];
GRANT SELECT ON [dbo].[CastleSiege] TO [mubot_reader];
GO
Atenção: Nunca otorgues permisos de INSERT, UPDATE o DELETE al usuario del bot. El acceso de escritura a la base de datos de MU Online puede comprometer la integridad del servidor.

6. Si el bot se ejecuta en una máquina externa, abre el puerto 1433 en el Firewall de Windows:

netsh advfirewall firewall add rule name="SQL Server MuBot" ^
    protocol=TCP dir=in localport=1433 action=allow

Parte 3 — Instalar y Configurar el Proyecto del Bot

1. En el VPS (o el servidor que alojará el bot), abre PowerShell y crea la estructura del proyecto:

mkdir C:\MuBot
cd C:\MuBot
npm init -y
npm install discord.js@14 mssql dotenv

2. Crea el archivo C:\MuBot\.env:

DISCORD_TOKEN=TU_TOKEN_AQUI
CLIENT_ID=ID_DE_TU_APLICACION
GUILD_ID=ID_DE_TU_SERVIDOR_DISCORD
DB_SERVER=127.0.0.1
DB_PORT=1433
DB_DATABASE=MuOnline
DB_USER=mubot_reader
DB_PASSWORD=TuContrasenaSegura!123

3. Crea C:\MuBot\database.js:

const sql = require('mssql');
require('dotenv').config();

const config = {
    server: process.env.DB_SERVER,
    port: parseInt(process.env.DB_PORT),
    database: process.env.DB_DATABASE,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    options: {
        encrypt: false,
        trustServerCertificate: true,
        enableArithAbort: true,
    },
    pool: {
        max: 10,
        min: 0,
        idleTimeoutMillis: 30000,
    },
    connectionTimeout: 15000,
    requestTimeout: 15000,
};

const pool = new sql.ConnectionPool(config);
const poolConnect = pool.connect();

pool.on('error', err => {
    console.error('[DB] Error en el pool de conexiones:', err);
});

module.exports = { pool, poolConnect, sql };

Parte 4 — Implementar los Comandos Slash

1. Crea C:\MuBot\commands\ranking.js:

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const { pool, poolConnect, sql } = require('../database');

module.exports = {
    data: new SlashCommandBuilder()
        .setName('ranking')
        .setDescription('Muestra el Top 10 de resets del servidor'),

    async execute(interaction) {
        await interaction.deferReply();

        try {
            await poolConnect;
            const request = pool.request();

            const result = await request.query(`
                SELECT TOP 10
                    ROW_NUMBER() OVER (ORDER BY c.Resets DESC, c.cLevel DESC) AS Posicion,
                    c.Name        AS Personaje,
                    c.Resets      AS Resets,
                    c.cLevel      AS Level,
                    CASE c.Class
                        WHEN 0  THEN 'Dark Wizard'
                        WHEN 1  THEN 'Soul Master'
                        WHEN 2  THEN 'Grand Master'
                        WHEN 16 THEN 'Dark Knight'
                        WHEN 17 THEN 'Blade Knight'
                        WHEN 18 THEN 'Blade Master'
                        WHEN 32 THEN 'Fairy Elf'
                        WHEN 33 THEN 'Muse Elf'
                        WHEN 34 THEN 'High Elf'
                        WHEN 48 THEN 'Magic Gladiator'
                        WHEN 64 THEN 'Dark Lord'
                        WHEN 80 THEN 'Summoner'
                        ELSE 'Desconocido'
                    END AS Clase
                FROM MuOnline.dbo.Character c
                WHERE c.Name NOT LIKE 'GM_%'
                ORDER BY c.Resets DESC, c.cLevel DESC
            `);

            const embed = new EmbedBuilder()
                .setTitle('🏆 Top 10 Resets')
                .setColor(0xFFD700)
                .setTimestamp()
                .setFooter({ text: 'ViciadosMU' });

            const lineas = result.recordset.map(row =>
                `**${row.Posicion}.** ${row.Personaje} — ` +
                `${row.Resets} Resets | Lv ${row.Level} | ${row.Clase}`
            ).join('\n');

            embed.setDescription(lineas || 'No se encontraron datos.');

            await interaction.editReply({ embeds: [embed] });

        } catch (err) {
            console.error('[ranking] Error:', err);
            await interaction.editReply('Error al consultar la base de datos. Intenta de nuevo.');
        }
    },
};

2. Crea C:\MuBot\commands\status.js:

const { SlashCommandBuilder, EmbedBuilder } = require('discord.js');
const { pool, poolConnect, sql } = require('../database');

module.exports = {
    data: new SlashCommandBuilder()
        .setName('status')
        .setDescription('Muestra el estado actual del servidor MU Online'),

    async execute(interaction) {
        await interaction.deferReply();

        try {
            await poolConnect;
            const request = pool.request();

            const result = await request.query(`
                SELECT COUNT(*) AS Online
                FROM MuOnline.dbo.MEMB_STAT
                WHERE ConnectStat = 1
            `);

            const online = result.recordset[0].Online;

            const embed = new EmbedBuilder()
                .setTitle('🟢 Estado del Servidor')
                .setColor(0x00FF00)
                .addFields(
                    { name: 'Jugadores en línea', value: `${online}`, inline: true },
                    { name: 'Servidor', value: 'En línea', inline: true }
                )
                .setTimestamp()
                .setFooter({ text: 'ViciadosMU' });

            await interaction.editReply({ embeds: [embed] });

        } catch (err) {
            console.error('[status] Error:', err);
            await interaction.editReply('Servidor no disponible o error de conexión.');
        }
    },
};

Parte 5 — Archivo Principal y Registro de Comandos

1. Crea C:\MuBot\index.js:

const { Client, GatewayIntentBits, Collection } = require('discord.js');
const fs = require('fs');
const path = require('path');
require('dotenv').config();

const client = new Client({
    intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMessages,
    ],
});

client.commands = new Collection();

const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs.readdirSync(commandsPath).filter(f => f.endsWith('.js'));

for (const file of commandFiles) {
    const command = require(path.join(commandsPath, file));
    client.commands.set(command.data.name, command);
}

client.once('ready', () => {
    console.log(`[Bot] En línea como ${client.user.tag}`);
});

client.on('interactionCreate', async interaction => {
    if (!interaction.isChatInputCommand()) return;

    const command = client.commands.get(interaction.commandName);
    if (!command) return;

    try {
        await command.execute(interaction);
    } catch (err) {
        console.error(err);
        if (interaction.replied || interaction.deferred) {
            await interaction.followUp({ content: 'Error interno.', ephemeral: true });
        } else {
            await interaction.reply({ content: 'Error interno.', ephemeral: true });
        }
    }
});

client.login(process.env.DISCORD_TOKEN);

2. Crea C:\MuBot\deploy-commands.js para registrar los slash commands en Discord:

const { REST, Routes } = require('discord.js');
const fs = require('fs');
const path = require('path');
require('dotenv').config();

const commands = [];
const commandsPath = path.join(__dirname, 'commands');
const commandFiles = fs.readdirSync(commandsPath).filter(f => f.endsWith('.js'));

for (const file of commandFiles) {
    const command = require(path.join(commandsPath, file));
    commands.push(command.data.toJSON());
}

const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);

(async () => {
    try {
        console.log('Registrando slash commands...');
        await rest.put(
            Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID),
            { body: commands }
        );
        console.log('Slash commands registrados correctamente.');
    } catch (err) {
        console.error(err);
    }
})();

3. Ejecuta el registro de comandos:

cd C:\MuBot
node deploy-commands.js

4. Inicia el bot:

node index.js

Parte 6 — Mantener el Bot Activo con PM2

Para que el bot inicie automáticamente y se reinicie en caso de fallo, usa PM2:

npm install -g pm2
cd C:\MuBot
pm2 start index.js --name "mubot"
pm2 save
pm2 startup
Dica: Usa pm2 logs mubot para monitorear los logs en tiempo real y pm2 restart mubot para reiniciar el bot después de actualizaciones.

Solución de Problemas

Error ECONNREFUSED 127.0.0.1:1433 → SQL Server no está escuchando en el puerto 1433. Verifica que el protocolo TCP/IP esté habilitado en SQL Server Configuration Manager y que el servicio haya sido reiniciado.

Error Login failed for user 'mubot_reader' → Confirma que SQL Server esté en modo de autenticación mixta (SQL Server and Windows Authentication). Revísalo en Properties → Security en SQL Server Management Studio.

Los slash commands no aparecen en Discord → Ejecuta node deploy-commands.js nuevamente. Los comandos de guild aparecen en hasta 1 minuto; los comandos globales pueden tardar hasta 1 hora en propagarse.

La consulta devuelve 0 jugadores en línea → Verifica que la tabla MEMB_STAT exista en tu base de datos. Algunas versiones de MuServer usan ConnectServer.dbo.MEMB_STAT en una base de datos separada.

Nota: El nombre de la tabla Character varía según la versión de MuServer: puede ser T_Character, Characters o dbo.Character. Confirma el nombre correcto ejecutando SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' contra tu base de datos.

Perguntas frequentes

¿Qué versión de Node.js debo usar?

Usa Node.js 18 LTS o superior. Las versiones anteriores pueden tener incompatibilidades con discord.js v14, que requiere al menos Node.js 16.9.0.

¿El bot necesita estar en el mismo servidor (VPS) que MU Online?

No necesariamente. El bot puede ejecutarse en cualquier máquina con acceso al SQL Server. Solo abre el puerto 1433 en el firewall del VPS y configura SQL Server para aceptar conexiones remotas.

¿Cómo evito que el bot exponga datos sensibles de los jugadores?

Nunca retornes campos como password, serial o md5pwd en tus consultas. Usa SELECT solo en las columnas necesarias (Name, Level, Class, Reset) y crea un usuario SQL de solo lectura exclusivo para el bot.

El bot deja de responder después de unas horas — ¿por qué?

Esto normalmente indica que la conexión con SQL Server fue cerrada por inactividad. Implementa reconexión automática con pool de conexiones (mssql usa pool por defecto) y configura connectionTimeout y requestTimeout en el objeto de configuración.

EQ

Equipo ViciadosMU

Equipe editorial do ViciadosMU — portal de MU Online no ar desde 2003.

Sigue leyendo

Artículos relacionados

🖥️
Tutorial

Cómo Integrar el Sitio Web y el Juego en tu Servidor de MU Online

Aprende a conectar tu servidor de juego MU Online con un panel web, compartiendo la misma base de datos para gestión de cuentas, rankings y funciones web.

18 min · Avanzado
🛡️
Tutorial

Cómo crear un servidor de MU Online (guía completa 2026)

Guía completa paso a paso para crear tu propio servidor de MU Online: los 4 componentes que necesitas (SQL Server, MuServer, cliente/Main, y launcher), el orden correcto de instalación y configuración, cómo configurar las tasas de experiencia y drop, cómo conectar el servidor a internet con No-IP o IP fija, los puertos que debes abrir en el router y el firewall, los errores más comunes al iniciar por primera vez y cómo resolverlos, la diferencia entre un servidor de prueba local y un servidor público, y las consideraciones básicas de seguridad antes de abrir el servidor a jugadores externos.

12 min · Avanzado
🐬
Tutorial

Instalar MySQL y phpMyAdmin para el sitio del servidor de MU

Guía completa para instalar MySQL y phpMyAdmin para el sitio web de un servidor de MU Online: la diferencia entre MySQL (para el sitio) y SQL Server (para el juego), cuándo instalar MySQL de forma dedicada en lugar de usar XAMPP o AppServ, el proceso paso a paso de instalación de MySQL Community Server en Windows, cómo configurar MySQL como servicio de Windows, la instalación de phpMyAdmin como interfaz gráfica, cómo crear la base de datos y el usuario dedicado para el sistema web de MU, cómo importar las tablas del sistema web, buenas prácticas de seguridad para MySQL en servidores de MU (contraseña de root, no exponer el puerto 3306, usuario dedicado), y cómo conectar el sistema web con el MySQL recién instalado.

12 min · Principiante