O maior portal de MU Online do Brasil — desde 2003
Tutorial Avançado Website

Como criar um bot de Discord com o status do servidor de MU

Monte um bot de Discord que exibe status online/offline, jogadores conectados e rankings do seu servidor de MU Online, com atualização automática e comandos slash.

BR Bruno · Atualizado em 10 jul 2025 · ⏱ 18 min de leitura
Resposta rápida

Um bot de Discord que mostra o status do seu servidor de MU Online em tempo real é uma das ferramentas de comunidade com melhor retorno sobre esforço que você pode montar. Enquanto o jogador está no Discord conversando, ele vê num piscar de olhos se o servidor está no ar, quantas pessoas estão conec

Um bot de Discord que mostra o status do seu servidor de MU Online em tempo real é uma das ferramentas de comunidade com melhor retorno sobre esforço que você pode montar. Enquanto o jogador está no Discord conversando, ele vê num piscar de olhos se o servidor está no ar, quantas pessoas estão conectadas e quem lidera o ranking de resets — sem precisar abrir o cliente ou o site. Isso reduz drasticamente as perguntas repetidas de "tá on?" nos canais e projeta uma imagem de servidor cuidado e profissional. Neste tutorial você vai montar, do zero, um bot em Node.js com a biblioteca discord.js que consulta o estado do servidor e publica um painel que se atualiza sozinho, além de responder a comandos slash como /status e /online. Vamos tratar tanto do caminho de ler o banco de dados diretamente quanto do caminho mais seguro de consumir uma API do próprio site. Lembre-se desde já: nomes de tabelas, colunas e portas variam por versão e emulador (Season 6, Season 15, IGCN, MuEMU, etc.), então os exemplos aqui são esqueleto a adaptar, não verdade universal.

Pré-requisitos

Antes de escrever qualquer linha de código, garanta que o ambiente base está pronto. Um bot é apenas um cliente a mais consumindo dados que já existem; se a fonte de dados não estiver acessível e estável, nenhum código salva. Se você ainda está montando a infraestrutura, vale revisar antes o guia de como criar servidor de MU Online, porque o bot pressupõe um servidor já funcional.

  • Node.js 18 LTS ou superior instalado na máquina onde o bot vai rodar (o discord.js v14 exige no mínimo Node 16.11).
  • Acesso ao banco de dados do servidor (SQL Server na maioria das versões) ou uma API de status no site.
  • Uma conta no Discord Developer Portal com permissão para criar aplicações.
  • Um servidor Discord onde você tenha permissão de administrador para adicionar o bot.
  • Conhecimento básico de linha de comando e edição de arquivos de configuração.
  • Firewall ajustado: se for ler o banco de outra máquina, a porta do SQL Server (ex.: 1433) precisa estar liberada apenas para o IP do bot.

Arquitetura: banco direto vs. API do site

Existem dois modelos para o bot obter os dados, e a escolha define toda a segurança do projeto.

AbordagemVantagensDesvantagensQuando usar
Ler o banco diretoSimples, sem camada extra, dados brutosExpõe a porta do SQL na rede; risco se o token/credencial vazarBot roda no mesmo VPS do banco, rede fechada
Consumir API do siteVocê controla exatamente o que sai; não abre o bancoExige criar e manter um endpoint no siteBot roda em máquina externa; ambiente de produção

A recomendação para produção é a API do site: você cria um endpoint como /api/status.php que devolve um JSON enxuto, e o bot só enxerga aquilo. Assim, mesmo que o token do bot vaze, ninguém alcança o banco. Vamos mostrar os dois, mas trate a API como o caminho preferencial.

Passo 1 — Criar a aplicação e o bot no Discord

  1. Acesse o Discord Developer Portal e clique em New Application. Dê um nome como StatusMU.
  2. No menu lateral, entre em Bot e clique em Add Bot.
  3. Em Privileged Gateway Intents, para este bot de status você normalmente não precisa de intents privilegiadas, o que simplifica a aprovação. Deixe-as desligadas se só for publicar embeds.
  4. Clique em Reset Token, copie o token e guarde-o com cuidado — ele será usado no .env.
  5. Vá em OAuth2 → URL Generator, marque os escopos bot e applications.commands, e nas permissões marque Send Messages, Embed Links e Read Message History.
  6. Copie a URL gerada, abra no navegador e adicione o bot ao seu servidor Discord.

Passo 2 — Estrutura do projeto

No terminal da máquina do bot, crie a pasta e instale as dependências:

mkdir statusmu && cd statusmu
npm init -y
npm install discord.js dotenv mssql axios

Crie um arquivo .env na raiz do projeto. Este arquivo nunca deve ir para o Git:

DISCORD_TOKEN=cole_seu_token_aqui
CLIENT_ID=id_da_aplicacao
GUILD_ID=id_do_seu_servidor_discord
STATUS_CHANNEL_ID=id_do_canal_de_status

# Opção A: banco direto
DB_SERVER=127.0.0.1
DB_PORT=1433
DB_DATABASE=MuOnline
DB_USER=mubot_reader
DB_PASSWORD=SenhaForte!123

# Opção B: API do site
STATUS_API_URL=https://seusite.com/api/status.php

Passo 3 (opção A) — Endpoint de status no site

Se você optar pela API — o caminho seguro —, crie no site um arquivo PHP que devolve o status como JSON. Ele encapsula toda a lógica de consulta e nunca expõe credenciais ao bot:

<?php
// api/status.php
header('Content-Type: application/json');

$host = '127.0.0.1';
$db   = 'MuOnline';
$user = 'site_reader';
$pass = 'SenhaDoSite!123';

try {
    $conn = new PDO("sqlsrv:Server=$host;Database=$db", $user, $pass);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // Jogadores conectados — nome da tabela varia por versão
    $stmt = $conn->query("SELECT COUNT(*) AS online
                          FROM MEMB_STAT WHERE ConnectStat = 1");
    $online = (int) $stmt->fetch(PDO::FETCH_ASSOC)['online'];

    echo json_encode([
        'status'  => 'online',
        'online'  => $online,
        'updated' => date('c'),
    ]);
} catch (Exception $e) {
    echo json_encode(['status' => 'offline', 'online' => 0]);
}

Teste abrindo a URL no navegador — você deve ver um JSON limpo. A grande vantagem: o bot só conhece essa URL, e você decide exatamente quais campos aparecem.

Passo 4 — Testar de fato se o servidor está no ar

O erro clássico é considerar o servidor "online" só porque o banco respondeu. O banco continua de pé mesmo com o GameServer parado. Para refletir o estado real, faça também um teste de porta TCP no GameServer. Em Node.js:

// checkPort.js
const net = require('net');

function checkPort(host, port, timeout = 3000) {
  return new Promise((resolve) => {
    const socket = new net.Socket();
    socket.setTimeout(timeout);
    socket.once('connect', () => { socket.destroy(); resolve(true); });
    socket.once('timeout', () => { socket.destroy(); resolve(false); });
    socket.once('error', () => { resolve(false); });
    socket.connect(port, host);
  });
}

module.exports = { checkPort };

Use a porta do seu GameServer (frequentemente 55901 ou 44405, mas varia por versão). Só marque como online quando a porta responder E a consulta de dados funcionar.

Passo 5 — O bot principal com painel automático

Crie o index.js. Ele consulta o status a cada 60 segundos e edita uma única mensagem fixa no canal, mantendo o painel sempre atual sem poluir o chat:

require('dotenv').config();
const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js');
const axios = require('axios');
const { checkPort } = require('./checkPort');

const client = new Client({ intents: [GatewayIntentBits.Guilds] });
let statusMessageId = null;

async function fetchStatus() {
  try {
    const gameOnline = await checkPort('127.0.0.1', 55901);
    const { data } = await axios.get(process.env.STATUS_API_URL, { timeout: 5000 });
    return {
      online: gameOnline && data.status === 'online',
      players: data.online ?? 0,
    };
  } catch (err) {
    return { online: false, players: 0 };
  }
}

function buildEmbed(status) {
  return new EmbedBuilder()
    .setTitle('Status do Servidor')
    .setColor(status.online ? 0x2ecc71 : 0xe74c3c)
    .addFields(
      { name: 'Estado', value: status.online ? '🟢 Online' : '🔴 Offline', inline: true },
      { name: 'Jogadores', value: `${status.players}`, inline: true },
    )
    .setFooter({ text: 'Atualizado' })
    .setTimestamp();
}

async function updatePanel() {
  const channel = await client.channels.fetch(process.env.STATUS_CHANNEL_ID);
  const status = await fetchStatus();
  const embed = buildEmbed(status);

  if (statusMessageId) {
    try {
      const msg = await channel.messages.fetch(statusMessageId);
      await msg.edit({ embeds: [embed] });
      return;
    } catch { statusMessageId = null; }
  }
  const sent = await channel.send({ embeds: [embed] });
  statusMessageId = sent.id;
}

client.once('ready', () => {
  console.log(`Bot online como ${client.user.tag}`);
  updatePanel();
  setInterval(updatePanel, 60_000);
});

client.login(process.env.DISCORD_TOKEN);

Passo 6 — Comandos slash

Além do painel automático, dê ao jogador o comando /status sob demanda. Registre o comando com um script de deploy e trate a interação no bot:

// deploy-commands.js
require('dotenv').config();
const { REST, Routes, SlashCommandBuilder } = require('discord.js');

const commands = [
  new SlashCommandBuilder().setName('status')
    .setDescription('Mostra o status atual do servidor').toJSON(),
];

const rest = new REST({ version: '10' }).setToken(process.env.DISCORD_TOKEN);
rest.put(
  Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID),
  { body: commands }
).then(() => console.log('Comandos registrados')).catch(console.error);

No index.js, adicione o listener de interação, reaproveitando fetchStatus() e buildEmbed() para responder com o mesmo embed. Comandos de guild aparecem em segundos; comandos globais podem levar até uma hora para propagar.

Passo 7 — Manter o bot vivo com PM2

O processo do bot precisa reiniciar sozinho se cair. Use o PM2:

npm install -g pm2
pm2 start index.js --name statusmu
pm2 save
pm2 startup

Com pm2 logs statusmu você acompanha a saída em tempo real, e pm2 restart statusmu recarrega após mudanças.

Erros comuns e soluções

SintomaCausa provávelSolução
Bot mostra "online" com servidor caídoSó checa o banco, não o GameServerAdicione teste de porta TCP no GameServer
ECONNREFUSED 1433TCP/IP desabilitado ou porta bloqueadaHabilite TCP/IP no SQL Config Manager e libere no firewall
Comandos slash não aparecemDeploy não executado ou escopo erradoRode deploy-commands.js e confira CLIENT_ID/GUILD_ID
Painel cria mensagem nova a cada cicloID da mensagem não persisteSalve o statusMessageId em arquivo/DB para sobreviver a restart
Invalid TokenToken errado ou regeneradoCopie o token atual em Bot → Reset Token e atualize o .env
Rate limit ao editarIntervalo curto demaisAumente o intervalo para 60s ou mais

Boas práticas de segurança

Nunca commite o .env. Crie um usuário de banco somente-leitura, com GRANT SELECT apenas nas tabelas necessárias, e jamais use a conta sa. Se for expor uma API de status no site, devolva só os campos estritamente públicos — nunca senhas, seriais ou e-mails. Prefira que o bot consuma a API em vez de abrir a porta do banco para a internet. E documente o intervalo de atualização para que futuras manutenções não o reduzam a ponto de gerar rate limit.

Checklist de lançamento

  • Node.js 18+ instalado na máquina do bot
  • Aplicação e bot criados no Developer Portal, token guardado no .env
  • Bot adicionado ao servidor Discord com permissões de enviar mensagens e embeds
  • Fonte de dados definida (API do site ou banco somente-leitura)
  • Teste de porta TCP do GameServer implementado
  • Canal de status criado e ID configurado
  • Painel automático atualizando a cada 60s
  • Comando /status registrado e respondendo
  • PM2 configurado com pm2 save e pm2 startup
  • .env fora do controle de versão e com permissões restritas

Perguntas frequentes

O bot precisa rodar no mesmo VPS do servidor de MU?

Não. Ele só precisa de acesso ao banco de dados ou a um endpoint HTTP do site. Pode rodar em outra máquina, desde que a porta do SQL Server (1433, por exemplo) esteja liberada ou o site exponha uma API de status.

Qual a diferença entre ler o banco direto e usar uma API do site?

Ler o banco é mais direto mas expõe o SQL na rede. Uma API HTTP no próprio site é mais segura porque você controla exatamente quais dados saem e não abre a porta do banco para fora.

Por que meu bot mostra 'online' mesmo com o servidor caído?

Provavelmente você está checando só a conexão com o banco, e o banco continua de pé mesmo com o GameServer parado. Faça também um teste de porta TCP no GameServer para refletir o estado real.

Com que frequência o bot deve atualizar o status?

Um intervalo de 60 segundos é seguro. Atualizações mais frequentes que 15 segundos podem esbarrar em rate limit do Discord ao editar a mesma mensagem várias vezes por minuto.

É seguro deixar o token do bot no código?

Nunca. O token dá controle total sobre o bot. Guarde-o em um arquivo .env fora do controle de versão e restrinja as permissões do arquivo no servidor.

BR
Editor de eventos, mapas e itens

Bruno é especialista em eventos, mapas, bosses e economia de itens do MU Online. Documenta cada detalhe com base em jogo real.

Continue lendo

Artigos relacionados