Skip to content

Custom scripts

Custom scripts let you extend discord-mcbe’s features with JavaScript or TypeScript. discord-mcbe loads the script when the bot starts, allowing you to receive events and control worlds and players.

At startup, discord-mcbe loads the file specified by script.entry in config.json and calls its default export function. The function receives discord-mcbe’s Application instance as its argument.

Both JavaScript and TypeScript are supported.

scripts/main.ts
import type { Application } from '@discord-mcbe/server';
export default function main(app: Application) {
app.logger.info('Custom script loaded');
}

BDS ServerNet connections are unauthenticated by default. To use Bearer authentication, add a token to .env and configure the authenticator from a custom script.

.env
BRIDGE_TOKEN=your-token
scripts/main.ts
import { bearerAuth, type Application } from '@discord-mcbe/server';
export default function main(app: Application) {
const token = process.env.BRIDGE_TOKEN;
if (!token) throw new Error('BRIDGE_TOKEN is not set');
app.minecraft.script.setAuthenticator(bearerAuth(token));
}

Set the same token in the BDS variables.json file:

variables.json
{
"BRIDGE_URL": "ws://localhost:23191",
"BRIDGE_TOKEN": "your-token"
}

For custom authentication, pass a function receiving the request to setAuthenticator. It can return a boolean or Promise<boolean>. A rejected connection never creates a world session.

scripts/main.ts
import type { Application } from '@discord-mcbe/server';
export default function main(app: Application) {
app.on('worldConnect', async (event) => {
app.logger.info('Connected:', event.world.name);
await event.world.sendMessage('§aDiscord bridge connected');
});
app.on('playerJoin', async (event) => {
const location = await event.player.getLocation();
app.logger.info(`${event.player.name} joined. Location: [${location.x}, ${location.y}, ${location.z}]`);
});
app.on('minecraftMessage', (event) => {
app.logger.info('Chat:', event.world.name, event.sender.name, event.message);
});
}

The main events are listed below. See the API reference for details.

Event Main values Emitted
startup app After the bot, bridge servers, and script have started
discordReady client After the bot logs in
discordMessage message When a user posts in the relay channel
discordSend channel, message Immediately before discord-mcbe sends to Discord
worldConnect world When a world finishes initializing
worldDisconnect world When a world session ends
minecraftMessage world, sender, message On Minecraft chat
playerJoin / playerLeave world, player When a player joins or leaves
scripts/main.ts
import type { Application } from '@discord-mcbe/server';
export default function main(app: Application) {
app.on('worldConnect', async ({ world }) => {
const result = await world.runCommand('weather clear');
const tps = await world.getTPS();
app.logger.info(world.name, result, 'TPS:', tps);
});
}

ScriptWorld provides messaging, commands, TPS, script events, player access, and scoreboards. ScriptPlayer provides direct messages, position, dimension and game-mode queries, game-mode changes, kicking, and screen display controls.

See the API reference for the full set of methods and types.

Custom scripts can use packages published on npm. Add the packages you need to the package.json in the same directory as the launcher. You can choose any package manager, including npm, pnpm, and Bun.

You can import added packages normally from files in scripts/. @discord-mcbe/server and @discord-mcbe/shared are provided by discord-mcbe, so you do not need to install them separately.