First Bot Tutorial
This page is the slow path. It walks through every step of getting a Discord bot running, with no assumptions about prior experience. If you have set up a Discord bot before, Quickstart is the short version of this same flow.
Who this tutorial is for
You have heard of Discord bots. You have not set one up yourself, you have not built a Rust project, and “Docker” is at most a vague impression. That is fine. By the end of this page you will have a real bot in a real Discord server, running on hardware you control. You will copy a few files, fill in a few blanks, and run a few commands.
What you will build
A Discord bot you fully own:
- Online in a server you control.
- Responds to
!m helpwith a command list. - Plays music in a voice channel with
!m play <url>. - Chats with you when you @mention it (if you provide an AI API key).
- Can play Wordle and other small games.
- Stores its data in a PostgreSQL database that runs alongside it.
The whole thing runs in Docker on one machine. There is no website to set up, no domain to buy, no public IP needed.
Section 1: Create the Discord application
Discord calls the parent object that owns a bot an “application.” Creating one takes a few clicks in their developer portal.
- Open https://discord.com/developers/applications and log in with your normal Discord account.
- Click New Application in the top right.
- Give it a name (this becomes the bot’s display name; you can change it later), accept the terms, and click Create.
You are now on the General Information page.
Find the Application ID and copy it. Save it in a notes file labeled
CLIENT_ID. You will need it later.
Get the bot token
The token is the secret password your code uses to log in as this bot.
- Click Bot in the left sidebar.
- In the Token section, click Copy (or Reset Token if no token
is shown), and save the value as
DISCORD_TOKEN.
Treat this string like a banking password. Do not paste it in chat, do not screenshot it, do not commit it to git. The configuration files you will create later are gitignored specifically so a slip of the keyboard cannot leak it. If you ever do leak it, click Reset Token again and the old token stops working immediately.
Turn on the privileged intents
Still on the Bot page, scroll to Privileged Gateway Intents.
Turn on Server Members Intent and Message Content Intent. Leave
Presence Intent off. The bot needs Server Members so it can react to
joins (welcome and auto-role features), and Message Content so it can read
@mentions for AI chat and parse text commands like !m help.
Click Save Changes at the bottom.
Section 2: Invite the bot to your server
The application exists, but it is not in any server yet.
- Click Installation in the sidebar (or OAuth2 → URL Generator on older portals).
- Under Scopes, check
bot. (applications.commandsisn’t needed — the bot has no slash commands — but checking it is harmless if your workflow already includes it.) - Under Bot Permissions, check at minimum: View Channels, Send Messages, Embed Links, Attach Files, Read Message History, Connect, Speak, Manage Roles, Kick Members, Ban Members, Moderate Members. You can drop any of these later if you do not use the matching feature.
- Copy the URL at the bottom, paste it into a new tab, choose your server (you must have Manage Server there), and click Authorize.
The bot now appears in your server’s member list with a grey dot. The dot turns green once you start the code.
Get the server ID
- In Discord, open User Settings → Advanced and turn on Developer Mode.
- Right-click your server icon and choose Copy Server ID.
- Save it as
GUILD_ID.
You should now have three values:
DISCORD_TOKEN=...
CLIENT_ID=...
GUILD_ID=...
Section 3: Install Docker
Docker runs the bot. The bot ships as a container so you do not have to install Rust, set up a database server, or worry about library versions.
Linux. Use the convenience script at https://get.docker.com, or your
distribution’s packages: apt install docker.io docker-compose-v2 on
Debian/Ubuntu, dnf install docker docker-compose on Fedora. Add yourself
to the docker group with sudo usermod -aG docker $USER, then log out
and back in.
macOS. Install Docker Desktop and launch it once after install.
Windows. Install Docker Desktop with the WSL2 backend, install a WSL2 Linux distribution from the Microsoft Store (Ubuntu is fine), and run all the commands in this tutorial from inside that distribution. Native PowerShell is technically possible but not worth the friction.
Verify in a terminal:
docker --version
docker compose version
Both should print a version.
Section 4: Clone and configure
Fetch the code:
git clone https://github.com/MrMcEpic/discord-bot-rs.git
cd discord-bot-rs
Make a copy of the example instance directory:
cp -r instances/example instances/mybot
cp instances/mybot/.env.example instances/mybot/.env
mybot is just a directory name. Pick whatever you like.
Open instances/mybot/.env in any text editor and paste in the three
values you saved earlier:
DISCORD_TOKEN=...
CLIENT_ID=...
GUILD_ID=...
A few lines down, change DB_SCHEMA to match your instance name:
DB_SCHEMA=mybot
That is the minimum. Save the file.
Open instances/mybot/config.toml. The first few lines control identity:
bot_name = "My Bot"
command_prefix = "!"
Change bot_name to whatever you want shown in help text. Leave
command_prefix as ! for now; the rest of the documentation assumes it.
Save and close.
If you want AI chat, also paste a DEEPSEEK_API_KEY or GEMINI_API_KEY
into .env. Both are free to start with — see
Prerequisites for signup links. You can add them later.
One last required step: generate an MCP auth token. The bundled stack
won’t start without one, because the embedded MCP server and the
mcp-gateway sidecar both refuse to run without a shared secret set.
Generate one random value and install it in two places: MCP_AUTH_TOKEN
in instances/mybot/.env (the bot reads it) and MCP_GATEWAY_AUTH_TOKEN
in a new .env at the repo root (Docker Compose reads it and feeds it to
the gateway). Both must hold the same value — the gateway uses it as
the bearer when reaching the bot, so a mismatch locks the two out of each
other:
TOKEN=$(openssl rand -hex 32) && \
sed -i.bak "s|^MCP_AUTH_TOKEN=.*|MCP_AUTH_TOKEN=$TOKEN|" instances/mybot/.env && \
rm instances/mybot/.env.bak && \
echo "MCP_GATEWAY_AUTH_TOKEN=$TOKEN" >> .env
If you prefer editing by hand, run openssl rand -hex 32, copy the
output, paste it after MCP_AUTH_TOKEN= in instances/mybot/.env, and
add a single line MCP_GATEWAY_AUTH_TOKEN=<paste> to a new file called
.env at the repo root (next to docker-compose.yml).
Section 5: First run
Start the stack:
INSTANCE_DIR=./instances/mybot docker compose up -d
The first run takes a few minutes because Docker has to download PostgreSQL and build the bot from source. Once it finishes, you get your shell prompt back.
Tail the logs:
docker compose logs -f bot
You will see, roughly in order:
- Postgres starting up and reporting it is ready to accept connections.
- The bot connecting to Postgres and creating its schema (“Database initialized (schema: mybot)”).
- The bot loading its instance config (“Instance config loaded: My Bot (prefix: !)”).
- The bot connecting to Discord (“Starting bot…” → shard running → “My Bot is connected! (ID: …)”).
- The MCP server binding to port 9090. From here on the bot is online.
Press Ctrl+C to stop tailing. The bot keeps running. To stop everything,
run docker compose down from the repo root.
Section 6: Test it
Open Discord. Your bot should now have a green dot in the member list.
In any channel the bot can see, type:
!m help
You should get a help embed listing the available commands. discord-bot-rs
uses prefix commands only — there are no slash commands — so !m help is
how you discover everything.
Section 7: What to try next
Now that the bot works, here are some things to play with.
- Customize the personality. Edit
instances/mybot/personality.txtand put whatever you want the bot’s voice to be. Restart withdocker compose restart bot. - Try AI chat. With an API key set, @mention the bot and ask it something. It will reply in the personality you defined.
- Try music. Join a voice channel, then run
!m play <YouTube URL>in any text channel.!m skipskips,!m queueshows the queue. - Try Wordle. Run
!m wordlein a channel. - Read Features to see everything the bot can do and how to enable the optional pieces.
Section 8: Common first-time mistakes
If something is not working, the issue is almost always one of these.
Bot stays grey (offline) and never goes green. The token is wrong, the
privileged intents are off, or both. Check docker compose logs bot —
“Invalid Token” means reset the token and paste the new value; “Disallowed
intents” means go back to the Bot page in the portal and verify both Server
Members Intent and Message Content Intent are enabled.
!m help returns nothing. The bot needs Message Content Intent
enabled in the Discord developer portal to read prefix commands. If you
skipped that in Section 1, re-enable it and restart the bot with
docker compose restart bot. Also check that the bot has permission to
read and send messages in the channel you are typing in.
Bot replies to !m help but not to @mentions. AI chat is disabled
because no API key is set. Add DEEPSEEK_API_KEY or GEMINI_API_KEY to
.env, then docker compose restart bot.
Postgres keeps restarting. Run docker compose logs postgres. Usually
this is a disk space issue or a corrupted volume from an unclean shutdown.
docker compose down followed by docker compose up -d resolves most
transient issues.
The first build hangs or fails. The Rust build downloads many crates and compiles for several minutes. If your machine has very little RAM (under 2 GB), the build may run out of memory. The smallest VPS that reliably builds the project is 2 GB RAM with at least 2 GB of swap.
If none of these apply, run through Verifying Your Setup for a more thorough diagnostic, or open an issue on GitHub.