Welcome to the Hangar Open Beta. Please report any issue you encounter on GitHub!
Avatar for Stil00000

Minecraft chat in Telegram: one long-poll connection, no leaked sockets, self-mute, several servers.

Report TgRelay?

TgRelay — Minecraft to Telegram bridge

TgRelay is a Paper plugin that connects Minecraft chat to Telegram — a group, a channel or a private chat — without leaking a network socket every second. It was written for Losos World, a survival server running since 2014, after the classic TelegramChat plugin pushed the machine into "No buffer space available" with thousands of leaked connections.

If your server needs Minecraft chat in Telegram (and Telegram messages in Minecraft), this is the drop-in replacement that will not take the box down after a week.

Why another Telegram bridge?

The old TelegramChat plugin (1.0.21, December 2022; SpigotMC page) calls getUpdates in a tight loop and leaves every socket behind: about 2.3 new connections per second, several thousand per hour. Windows eventually runs out of ephemeral ports and everything else starts failing — Bedrock players get dropped, RCON stalls, plugins lose access to Mojang.

TgRelay does it properly:

  • Long polling — a single getUpdates?timeout=25 request stays open, so one cycle costs one connection instead of hundreds.
  • One shared java.net.http.HttpClient with a bounded pool: connections are reused and closed on shutdown.
  • Outbound queue with a rate limit — a chatty server cannot flood Telegram and get the bot throttled.
  • Backoff on errors instead of a retry storm; the update offset survives restarts, so old messages are never replayed into the game.
  • Several servers on one bot — a hub/spoke bridge, so a survival world and a creative server report into the same chat, each line prefixed with its server name.
  • No third-party libraries — only the JDK and the Paper API.

Features

  • Minecraft → Telegram: chat, join, quit, deaths and advancements (each event can be disabled).
  • Telegram → Minecraft: messages are printed with tellraw, so they keep colours and are never attributed to a player.
  • Groups, channels and private chats; one bot can post to many destinations.
  • %player%, %message%, %sender%, %server% placeholders in every format string.
  • Server messages: /say from the console or RCON lands in the chat as [Losos] text — that is how "the server restarts in a minute" reaches people.
  • Technical notices for admins: server started, server stopping, and "Telegram is not answering" after repeated failures — routed to the moderation channel or a DM to operators, never to players.
  • English, Russian and Chinese locale files, overridable without a rebuild.
  • /tgrelay status shows chats, queue, offset and the moderation route; /tgrelay reload re-reads the config.
  • Nobody online is not silence: by default the bot answers in the same chat the message came from and shows the line in the game when the first player joins (delivery.when-empty: echo).

Several servers, one Telegram chat

One bot, several servers

Telegram gives a bot exactly one getUpdates reader, so installing the plugin on a second server with the same token does not work: the two pollers steal updates from each other and one server's chat randomly disappears. The usual advice is "run a second bot" — which is a second chat in every player's list.

TgRelay makes one server the hub instead. It owns the bot; every other server is a spoke that talks to it over loopback HTTP with a shared secret:

# hub — the server that owns the bot
server: { name: "Losos" }
relay:
  mode: hub
  token: "a-long-random-string"
  bind: "127.0.0.1:8765"
  spokes: ["http://127.0.0.1:8766"]
format:
  from-minecraft: "[%server%] %player%: %message%"
# spoke — any other server, same token
server: { name: "Build" }
relay:
  mode: spoke
  token: "a-long-random-string"
  bind: "127.0.0.1:8766"
  hub: "http://127.0.0.1:8765"

One chat gets both worlds, and every line says where it came from:

[Losos] Steve: hi there
[Build] Alex: testing the roof
  • The bot belongs to the hub only; a spoke needs no token of its own, so there is nothing to leak and nothing to duplicate.
  • Requests carry the shared secret in X-TgRelay-Token; the listener binds to loopback unless you change relay.bind.
  • Muted players are still routed to the moderation channel by the hub, so /tgrelay off behaves the same on every server.
  • A spoke retries three times before giving up and logs the loss; a dead spoke is reported by the hub once per five minutes.

With no relay and server sections the plugin runs exactly like a single-server install — the feature is opt-in.

Privacy: let players mute themselves

Self-mute and the moderation channel

A player can keep their own messages out of the public chats:

  • /tgrelay off — the player's messages stop going to bot.chats;
  • /tgrelay on — back to normal;
  • /tgrelay status — what their current state is.

Muted messages are not deleted. They are forwarded to a moderation channel with a [mute] prefix, so admins keep the full picture while everyone else sees nothing:

  1. moderation.chat — a separate Telegram chat the players are not in (simplest: add the bot there, paste the id, done);
  2. otherwise a DM to every operator with a linked account — operators come from ops.json, so there is no second list to maintain;
  3. otherwise the server console, so nothing disappears silently.

Linking is a one-time code (/tgrelay link), because Telegram knows user ids while Minecraft knows nicknames — a stranger cannot claim somebody else's account by typing a nickname.

Commands

Install

  1. Drop TgRelay.jar into plugins/.
  2. Start the server once, then edit plugins/TgRelay/config.yml:
bot:
  token: "123456:AA..."       # from @BotFather
  chats:
    - 123456789               # a DM with the bot
    - -1001234567890          # a group the bot is a member of
  1. Run /tgrelay reload.

For a group, add the bot to the group first — otherwise Telegram answers chat not found, which is exactly the failure that made the old plugin spin.

Commands and permissions

Command Who What
/tgrelay off / on players hide or restore your own messages
/tgrelay link / unlink players pair or unpair a Telegram account
/tgrelay status players and admins your state; admins also see the relay counters
/tgrelay reload tgrelay.admin re-read config.yml
/tgrelay testmute tgrelay.admin send a test message through the moderation route
/tgrelay chats tgrelay.admin list every chat with its Telegram name: live ones and the ones Telegram threw out

Compatibility

  • Paper and forks that keep the Paper API (Purpur, and similar) — the plugin uses AsyncChatEvent.
  • Java 21+, tested on Paper 1.21 and on a live server with Geyser, ViaVersion and Floodgate installed.
  • Can run side by side with TelegramChat, but only one plugin may hold a bot token at a time: Telegram allows a single getUpdates consumer per bot.

Open to ideas

This plugin is maintained in the open and it is shaped by the people who run it. If something is missing — a different relay target, per-world filters, a web dashboard, a locale you need — open an issue or a pull request on GitHub. Bug reports with a log excerpt are especially welcome.

Where it runs

TgRelay powers the Telegram bridge of Losos World — a survival server that has been running since 2014 without a single wipe, without private zones and without donations.

The plugin is not tied to that server in any way: any Paper server can run it with its own bot token.

TgRelay is not affiliated with Mojang or Microsoft.

Information

Category
Chat
Published
October 24, 2026
License
1Downloads
1Stars

Pinned Versions

Members

1