For servers
Fern Server Link
Make your server feel at home in Fern: recognize Fern players, keep matches fair and talk to players, with a few small JSON messages over plugin channels.
Know who plays Fern
A tiny handshake tells your plugin which players use Fern, only when they allow it.
Fair matches
Switch off and lock specific Fern features on your server, with a reason players can read.
Notifications
Short, rate-limited toasts for announcements, rewards or game events.
On-screen timers
Countdowns at the top of the screen for game starts, events and cooldowns.
How it works
Fern listens on a few plugin-message channels that all start with fern:. Every message is a small UTF-8 JSON object (max 8 KB).
The server always starts the conversation: Fern never announces itself on servers that don't ask.
Player joins
server ──► fern:welcome {"protocol": 1}
client ──► fern:hello {"client": "fern", "version": "0.1.0", ...} (only if the player allows it)
server ──► fern:rules / fern:notify / fern:timer (any time)
Player leaves → everything your server set is undone on the clientPlayers who don't use Fern simply ignore these channels — sending them is always safe.
Channels
| Channel | Direction | What it does |
fern:welcome | server → client | "This server supports Fern Server Link." Starts the handshake. |
fern:hello | client → server | Fern's answer: version, mod loader, enabled Fern mods. |
fern:rules | server → client | Turn off and lock Fern mods on your server. |
fern:notify | server → client | Show a notification (toast). |
fern:timer | server → client | Show, update or remove a countdown at the top of the screen. |
fern:waypoint | server → client | Planned: markers in the world. |
fern:presence | server → client | Planned: what the player's Discord status says while on your server. |
fern:welcome
{ "protocol": 1 }Send it once, shortly after the player joined (for example 1 tick after PlayerJoinEvent, so the client has registered its channels).
fern:hello (from the player)
{
"protocol": 1,
"client": "fern",
"version": "0.1.0",
"loader": "fabric",
"minecraft": "26.3",
"modules": ["fps", "zoom", "keystrokes"]
}Players can turn this off (Features → Server Features → Tell servers I use Fern). If you never receive a hello, treat the player as a normal player.
fern:rules
{ "disable": ["zoom", "fullbright"], "reason": "Not allowed in ranked matches" }- The listed mods are switched off and locked until the player leaves your server. The player sees the reason when they try to turn one back on.
- Rules only restrict. You can't turn mods on, change settings or unlock anything.
- Rules apply even when the player turned *Server Features* off — fair play comes first.
- Send
fern:rulesagain to lock more mods. Max 64 ids per message; unknown ids are ignored.
fern:notify
{ "title": "Welcome to Mossy Network", "body": "Season 3 starts today!" }titlemax 48 characters,bodymax 160. Formatting codes (§) are removed.- Max 5 notifications per 10 seconds per player; extra ones are dropped. Players can turn notifications off.
fern:timer
{ "id": "start", "label": "Game starts in", "seconds": 10, "color": "#4ADE80" }- Shows a countdown at the top centre of the screen, e.g. Game starts in 10s.
- Same
idagain = update it."seconds": 0= remove it. Max 3 timers, max 3600 seconds. coloris optional (hex). Players can turn timers off.
Module ids
| Id | Fern mod | Id | Fern mod |
fps | FPS | zoom | Zoom |
ping | Ping | toggle_sprint | Toggle Sprint |
coordinates | Coordinates | toggle_sneak | Toggle Sneak |
clock | Clock | fullbright | Fullbright |
keystrokes | Keystrokes | crosshair | Custom Crosshair |
cps | CPS | armor_status | Armor Status |
potion_effects | Potion Effects | direction | Direction |
memory | Memory |
New Fern mods get new ids; unknown ids are always ignored, so your rules keep working.
Example: Paper plugin
public final class FernLinkExample extends JavaPlugin implements Listener, PluginMessageListener {
@Override
public void onEnable() {
var messenger = getServer().getMessenger();
for (String ch : List.of("fern:welcome", "fern:rules", "fern:notify", "fern:timer")) {
messenger.registerOutgoingPluginChannel(this, ch);
}
messenger.registerIncomingPluginChannel(this, "fern:hello", this);
getServer().getPluginManager().registerEvents(this, this);
}
@EventHandler
public void onJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
// One tick later, so the client has told the server which channels it listens on.
getServer().getScheduler().runTaskLater(this, () -> send(player, "fern:welcome", "{\"protocol\":1}"), 1L);
}
@Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
// Read and validate the JSON before trusting it — it comes from the player.
String hello = readString(message);
getLogger().info(player.getName() + " uses Fern: " + hello);
send(player, "fern:rules", "{\"disable\":[\"zoom\"],\"reason\":\"No zoom in ranked\"}");
send(player, "fern:notify", "{\"title\":\"Fern detected\",\"body\":\"Have fun!\"}");
}
private void send(Player player, String channel, String json) {
player.sendPluginMessage(this, channel, writeString(json));
}
// Minecraft strings: VarInt length + UTF-8 bytes.
private static byte[] writeString(String s) {
byte[] utf8 = s.getBytes(StandardCharsets.UTF_8);
var out = new ByteArrayOutputStream();
int len = utf8.length;
while ((len & ~0x7F) != 0) { out.write((len & 0x7F) | 0x80); len >>>= 7; }
out.write(len);
out.writeBytes(utf8);
return out.toByteArray();
}
private static String readString(byte[] data) {
int len = 0, shift = 0, i = 0, b;
do { b = data[i++]; len |= (b & 0x7F) << shift; shift += 7; } while ((b & 0x80) != 0 && shift < 35);
return new String(data, i, Math.min(len, data.length - i), StandardCharsets.UTF_8);
}
}Rules for servers
- Don't trust `fern:hello` for security decisions. Any client can claim to be Fern. Use it for comfort features only, never for anti-cheat or permissions.
- Use rules for fair play, not to punish Fern players. Fern players should never be at a disadvantage compared to vanilla players.
- Keep notifications useful and rare; players who find them spammy will turn them off.
- Respect the Minecraft EULA and Usage Guidelines.
Privacy
fern:hello only contains the Fern version, mod loader, Minecraft version and enabled Fern mod ids — no account data, hardware or files. Players can turn it off. Servers receive nothing from Fern unless they send fern:welcome first.
Changelog
| Protocol | Fern | Changes |
| 1 | 0.1 | welcome, hello, rules, notify, timer |