Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

mc is a command line tool to manage and run Minecraft instances.

An instance is described by a single manifest file, mc.kdl. From that one file, mc run takes care of everything needed to bring the instance up:

  • installs a Java runtime
  • installs Minecraft for the configured version
  • installs a mod loader, when one is configured
  • downloads mods and resolves their dependencies into a lockfile
  • writes the configuration files Minecraft expects
  • launches the instance and supervises it until it stops
  • takes scheduled world backups to local storage or S3

If you have used a package manager, the workflow will feel familiar: a declarative manifest, a generated lockfile, and a small set of commands that operate on them.

mc init myserver --eula
cd myserver
mc run

Sections

Getting Started

Install mc and start your first instance.

Guides

Task-oriented guides: managing mods, configuring backups, and deploying an instance as a systemd service.

Reference

The mc.kdl manifest format, the environment variables mc reads, and the on-disk layout of an instance.

Commands

Detailed documentation for every mc command.

Getting Started

To get started with mc:

Installation

mise

mise installs the latest release binary and puts it on your PATH:

mise use -g github:afrigon/mc

Pre-built binaries

Every release publishes pre-built binaries on the GitHub releases page for:

  • Linux (x86_64, aarch64)
  • macOS (x86_64, aarch64)
  • Windows (x86_64)

Download the archive for your platform, extract it, and place the mc binary somewhere on your PATH:

tar -xzf mc-linux-x86_64.tar.gz
install -m 755 mc /usr/local/bin/mc
mc --version

Building from source

mc is written in Rust and builds with a recent stable toolchain:

git clone https://github.com/afrigon/mc
cd mc
cargo build --release

The binary is produced at target/release/mc.

First Steps with mc

This walkthrough creates a new instance and runs it.

Create an instance

Each instance lives in its own directory, with a mc.kdl manifest at its root. mc init creates both:

mc init myserver
cd myserver

The generated manifest looks like this:

name "myserver"
description "A Minecraft Server"

minecraft {
    version "..."
    loader "fabric"
}

server {
    gamemode "survival"
    difficulty "normal"
    hardcore #false

    // Setting this to true indicates YOU have read and agree to the Minecraft EULA (https://aka.ms/MinecraftEULA).
    // This agreement is between you and Mojang/Microsoft.
    eula #false
}

backups {
    enabled #true
    frequency "0 0 * * * *"
}

mods {
    modrinth {
        lithium "..."
    }
}

By default mc init uses the optimized preset, which adds a mod loader and a small set of performance mods. Pass --preset vanilla for an unmodded instance. The manifest is yours to edit; every key is documented in The Manifest Format.

Agree to the EULA

The instance will not start until you have agreed to the Minecraft EULA. Once you have read it, set:

server {
    eula #true
}

You can also pass --eula to mc init to do this at creation time.

Run it

mc run

On first run, mc downloads a Java runtime, the Minecraft binary, the mod loader, and any configured mods, then starts the instance. Subsequent runs reuse what is already installed and start immediately.

The console is attached to your terminal. Stop the instance with Ctrl-C: mc asks it to save the world and waits for it to exit cleanly.

Note that the allow list is enabled by default, so players must be on it before they can join. Add them with mc allow add. To open the instance to everyone instead, set allow-list #false in the server section.

Next steps

Guides

Task-oriented guides for operating an instance:

  • Managing Mods — add, remove, and update mods.
  • Players — the allow list, bans, and operators.
  • Backups — scheduled and manual world backups, and restoring from them.
  • Running under systemd — deploy an instance as a supervised service.
  • Tunnels — let players join from outside the local network without forwarding ports.

Managing Mods

Mods are declared in the mods block of mc.kdl, grouped by source, and installed when the instance starts. Under modrinth, each node names a mod by its identifier on the mod registry and pins the version to install:

minecraft {
    version "..."
    loader "fabric"
}

mods {
    modrinth {
        lithium "..."
    }
}

A mod loader must be configured under minecraft for mods to be installed; without one, the mods block is ignored. See The Manifest Format for the other groups, including mods fetched from a direct URL.

Adding and removing mods

mc add and mc remove edit the modrinth group for you. mc add looks the mod up on the registry and pins the latest version compatible with the configured Minecraft version and loader:

mc add sodium lithium
mc remove sodium

Updating mods

mc update re-pins mods to the latest compatible version — every mod in the manifest, or only the ones you name:

mc update
mc update lithium

Mods fetched from a direct URL have no version to compare and are skipped.

How mods are installed

Changes to mods take effect the next time the instance starts. On startup, mc resolves each entry — including its required dependencies — and records the result in the mc.lock lockfile. It then downloads any mod that is missing and deletes any mod that is no longer in the lockfile.

Two consequences of this are worth knowing:

  • You do not need to declare a mod’s dependencies; they are resolved and installed automatically.
  • The instance’s mods directory is fully managed by mc. A jar placed there by hand is removed on the next start. To install a mod that is not on the registry, declare it in the manifest under the http group instead.

Players

Who may join an instance, who is kept out, and who holds server commands are all declared in the players section of mc.kdl and written to the server when the instance starts:

players {
    allow {
        Notch
        jeb_
    }

    ban {
        Griefer reason="stole the beacon" created="2026-09-06T14:00:00Z"
    }

    op {
        Notch level=4
    }
}

See The Manifest Format for every key. The allow list is enabled by default; to open the instance to everyone, set allow-list #false in the server section. Operators may join regardless of the allow list.

Editing the lists

mc allow, mc ban, and mc op edit the section for you. Each has add, remove, and list subcommands:

mc allow add Notch jeb_
mc ban add Griefer --reason "stole the beacon" --for 7d
mc op add Notch
mc op list

Names are looked up when added, so a typo fails at the command rather than at the next start, and the account’s own casing is recorded. Names are matched regardless of case afterwards.

How the lists reach the server

The server keeps its lists in JSON files inside instance/. mc regenerates them from the manifest on every start, so the manifest is the single source of truth and those files are never edited by hand. Each player’s identity is resolved once and remembered in mc.lock, so a start never waits on a lookup.

When the instance is running and its remote console is reachable, a command also applies the change to it right away, so a newly banned player is disconnected and a newly allowed one can join without a restart. The remote console is reachable when an RCON password is configured — see Environment Variables. Two kinds of change cannot be applied live and wait for the next restart: an operator level or player limit bypass, and a ban expiry. The command says so with a warning.

Changes made from inside the game, such as /ban or /op typed by an operator, live only in the server’s files and are replaced by the manifest at the next start. Put them in the manifest with the matching mc command to keep them.

Offline mode

An instance with online-mode #false in the server section does not verify accounts, and the server identifies players by name alone. mc derives the identity the server expects from the name, so no lookup happens and any name is accepted.

Backups

mc can archive the instance’s world on a schedule while it runs, and restore any archive later. Backups are coordinated with the running instance so the world is flushed to disk before it is captured — archives are always consistent, even under load.

Scheduled backups

backups {
    enabled #true
    frequency "0 0 * * * *"
}

With enabled #true, backups fire on the frequency schedule while the instance runs. Without it, or with a manifest that has no backups section, nothing is scheduled. frequency is a cron expression with six fields — seconds, minutes, hours, day of month, month, day of week. The example above backs up at the start of every hour.

Coordination with a running instance happens over RCON, Minecraft’s remote console protocol. RCON is enabled whenever an RCON password is configured; when backups are enabled and no password is set, mc generates one at startup so backups work out of the box. See MC_RCON_PASSWORD to set the password yourself.

Manual backups

A backup can be taken at any time with mc backup, even when scheduled backups are disabled — enabled only controls the schedule. It works against a stopped instance, and against a running one as long as the instance was started with an RCON password configured (always the case when backups are enabled). When the instance is running but cannot be reached, mc refuses to back up rather than capture a world that is still being written to.

Interruptions

Backups are safe to interrupt. Ctrl-C cancels a backup in progress: the partial archive is discarded and the instance’s auto-save is re-enabled before the error is reported — the same recovery runs when a backup fails on its own. Stopping an instance while a scheduled backup is running cancels the backup the same way.

A backup killed with no chance to clean up (power loss, SIGKILL) cannot re-enable auto-save. As a last line of defense, mc turns auto-save on whenever an instance starts, as soon as it accepts remote console connections.

Storage

Archives go to the storage target named in the backups section: local or s3, never both. When neither is written, archives go to the backups directory of the instance.

Local stores archives in a directory and keeps only the keep most recent automatic ones:

backups {
    keep 20
    local "/mnt/data/mc"
}

Archives appear in the directory atomically: an interrupted backup never leaves a partial archive under a backup name or damages the backup it was about to replace.

S3 uploads archives to a bucket:

backups {
    s3 "my-minecraft-backups" region="us-east-1"
}

Credentials come from the standard AWS credential chain (environment, ~/.aws, or an IAM role), and so does the region when region is omitted. The MC_BACKUPS_S3_BUCKET environment variable overrides the bucket. mc does not prune S3 backups; use a bucket lifecycle rule to expire old archives.

Give each instance its own bucket or directory. mc treats a file in the storage target as one of this instance’s backups when its name starts with the instance name and ends with .tar.gz (for example myserver_*.tar.gz); anything else is ignored — never listed and never deleted.

Keeping a backup forever

Retention only applies to automatic backups — the timestamped archives created by the schedule or a plain mc backup. A backup taken with mc backup --name is stored as {instance}_{name}.tar.gz, shows up in mc restore --list, and is never pruned, no matter the keep limit.

Renaming an archive by hand works too: any file in the storage target named like myserver_important.tar.gz — the instance name, an underscore, and a label that is not a timestamp — is treated as a named backup: listed, restorable, and exempt from pruning.

On S3, mc never deletes anything, and a bucket lifecycle rule cannot tell a named backup from an automatic one; scope the rule (for example by key prefix) if named backups must outlive it.

Notifications

mc reports backup results — along with other instance events — to a webhook when one is configured through the environment (MC_DISCORD_WEBHOOK for Discord). The notifications section of the manifest selects which events are sent; see The Manifest Format. A failed notification never fails the backup itself.

Restoring

List the available backups, then restore one:

mc restore --list
myserver_2026-07-15_15-00-00.tar.gz (latest)
myserver_2026-07-14_15-00-00.tar.gz
mc restore --backup myserver_2026-07-14_15-00-00.tar.gz

Without --backup, the most recent backup is restored. The instance must be stopped to restore. The world being replaced is set aside rather than deleted, and is put back if the restore fails. See mc restore.

Running under systemd

mc run is designed to live under a process supervisor. It does not restart the instance when it crashes; it reports the failure through its exit code and lets the supervisor decide. On Linux, systemd is the natural fit.

Unit file

Assuming an instance at /srv/minecraft/myserver, create /etc/systemd/system/myserver.service:

[Unit]
Description=myserver Minecraft instance
After=network-online.target
Wants=network-online.target

[Service]
User=minecraft
WorkingDirectory=/srv/minecraft/myserver
ExecStart=/usr/local/bin/mc run --server-logs
EnvironmentFile=/etc/minecraft/myserver.env
Restart=on-failure

[Install]
WantedBy=multi-user.target

Then enable and start it:

systemctl enable --now myserver

WorkingDirectory must be the instance root — the directory containing mc.kdl — since mc operates relative to it.

Secrets

Environment variables such as MC_RCON_PASSWORD or a notification webhook are best kept out of the unit file, in an EnvironmentFile readable only by root, such as /etc/minecraft/myserver.env:

MC_RCON_PASSWORD=...
MC_DISCORD_WEBHOOK=...

See Environment Variables for everything mc reads from the environment.

Stopping and restarting

systemctl stop sends the service SIGTERM. mc catches it, asks the instance to save the world and shut down, and waits for it to exit before returning — within systemd’s default stop timeout, so the unit is not killed mid-save. The same applies to systemctl restart and to stops issued during a system shutdown.

Restart=on-failure brings the instance back up if it crashes, while a clean stop (including one requested from inside the game with /stop) stays stopped.

Logs

With --server-logs, the instance’s console output goes to standard output, which systemd captures in the journal (add --tunnel-logs to capture the tunnel agent as well):

journalctl -u myserver -f

mc’s own log verbosity is controlled by the global --verbose flag; the instance’s console log level follows it.

Tunnels

An instance normally accepts players only from its own network; letting friends in from elsewhere means forwarding a port on the router and sharing a public address. A tunnel removes both steps: a small agent runs beside the instance, keeps an outbound connection to a relay, and the relay hands out a public hostname that reaches the instance through that connection. Nothing on the network needs configuring, and the hostname is what you share.

mc supports playit.gg as the tunnel provider. It is free for a friend group and needs an account, which is created the first time an agent is claimed.

Enabling a tunnel

tunnel {
    provider "playit"
}

Adding the section is enough — a bare tunnel node also works; see tunnel for its keys.

First start

Start the instance from a terminal:

mc run
    Claiming tunnel agent, approve it at https://playit.gg/claim/... with your playit.gg account
     Claimed tunnel agent secret saved to .tunnel/playit.toml
    Creating a Minecraft tunnel for port 25565
      Tunnel players can join at quiet-fox.joinmc.link

Opening the link in a browser, signed in to the provider, approves the agent for that account. mc then stores the agent secret in .tunnel/playit.toml, readable only by the owning user, creates a Minecraft tunnel for the instance’s server port when the agent has none, and prints the public address. Players add that address to their server list as they would any other; no port is needed.

Later starts skip the claim and reuse the tunnel. The address is stable for as long as the tunnel exists with the provider. When notifications are enabled, the “started” message includes it.

Deleting .tunnel/playit.toml, or running mc tunnel claim --force, links the instance to a new agent on the next start.

While the instance runs

The agent runs for as long as the instance does and is restarted by mc if it stops on its own. Its output is written to .tunnel/playitd.log, or shown in the terminal when the instance is started with mc run --tunnel-logs. Stopping the instance stops the agent.

Traffic between players and the instance flows through the provider’s relay, so the address only works while the instance is running.

Under a service manager

The claim needs a browser, and a service has no terminal to print the link to. When no secret file exists and the instance is not started from a terminal, mc run fails with instructions instead of waiting. Claim the agent once beforehand, either by running mc run from a terminal or with mc tunnel claim, then deploy as described in Running under systemd. The secret file travels with the instance directory.

Managing the tunnel

The tunnel itself, its address, and the agent are visible in the provider’s dashboard, where a custom hostname or region can be assigned. When mc cannot create the tunnel, for example because the account has reached the provider’s limits, it prints a warning with a link to the dashboard and keeps running; a tunnel created there for the instance’s server port is picked up on the next start.

Reference

The Manifest Format

The mc.kdl manifest at the root of an instance describes everything about it. It is written in KDL. Every section except the two top-level keys is optional; omitted keys take the defaults listed below. Unknown keys, repeated keys, and stray values are errors.

name "myserver"
description "A Minecraft Server"

java {
    version "graal@25"
    min-memory 4096
    max-memory 4096
    jvm-arguments "-Djava.net.preferIPv6Addresses=true" "-XX:+AlwaysPreTouch" "-Djdk.graal.TuneInlinerExploration=1"
}

minecraft {
    version "latest"
    loader "fabric"
}

server {
    gamemode "survival"
    difficulty "normal"
    level-type "minecraft:normal"
    hardcore #false
    allow-list #true
    online-mode #true
    hide-online-players #true
    port 25565
    rcon-port 25575
    capacity 20
    view-distance 16
    simulation-distance 16
    eula #true

    properties {
        spawn-protection 0
    }
}

mods {
    modrinth {
        lithium "..."
    }
}

backups {
    enabled #true
    frequency "0 0 * * * *"
    keep 20
    local "backups"
}

notifications {
    on-lifecycle-event #true
    on-panic #true
    on-sigkill #true
    on-backup #true
    on-backup-failure #true
}

name (required)

The instance name. It names the world directory inside the instance and is used as the world’s level-name. Must be usable as a directory name.

description (required)

A short description, used as the message of the day (motd) shown in the multiplayer list.

java

The Java runtime used to launch the instance.

  • version — the runtime to install and use, as a vendor@version descriptor. Defaults to "graal@25". Run mc java list to see the available runtimes; the one marked (recommended) is the default.
  • min-memory — initial heap size in megabytes. Defaults to 4096.
  • max-memory — maximum heap size in megabytes. Defaults to 4096.
  • jvm-arguments — extra arguments passed to the JVM. Defaults to a small set of tuned flags; setting this key replaces the defaults entirely.
java {
    version "graal@25"
    min-memory 8192
    max-memory 8192
    jvm-arguments "-XX:+AlwaysPreTouch"
}

minecraft

The Minecraft version and mod loader.

  • version — the Minecraft version to run. Defaults to "latest", the latest release. "latest-snapshot" selects the latest snapshot, and any exact version id (see mc minecraft list) pins that version. Aliases are resolved every start, so an instance on "latest" upgrades itself when a new release comes out — pin an exact version if that is not what you want.
  • loader — the mod loader, as a name or name@version descriptor (for example "fabric", which resolves to the latest loader version for the configured Minecraft version). When omitted, the instance runs without a loader and the mods block is ignored. Run mc minecraft list-loaders to see loader versions.

tunnel

Exposes the instance to players outside the local network through a tunnel provider; see the Tunnels guide. The section is opt-in: when it is absent, no tunnel agent is installed or started. A bare tunnel node enables it with the defaults.

  • provider — the tunnel provider, as a name or name@version descriptor. playit is the accepted provider. Defaults to "playit", which resolves to the latest agent version on every start; pin an exact version, such as "playit@1.0.10", to hold it. Run mc tunnel list to see the available versions.
tunnel {
    provider "playit"
}

server

Settings mc manages for the server. Each maps to a server.properties key, listed in parentheses; because these are managed here, they cannot be set through properties.

  • gamemode"survival", "creative", "adventure", or "spectator". Defaults to "survival". (gamemode)
  • difficulty"peaceful", "easy", "normal", or "hard". Defaults to "normal". (difficulty)
  • level-type"minecraft:normal", "minecraft:flat", "minecraft:large_biomes", "minecraft:amplified", or "minecraft:single_biome_surface". Defaults to "minecraft:normal". (level-type)
  • hardcore — defaults to #false. (hardcore)
  • allow-list — whether players must be on the allow list before they can join. Defaults to #true. (white-list) Enabling it also sets enforce-whitelist, so a player removed from the list is kicked at once; disabling it clears both. enforce-whitelist is not managed, so an entry for it in properties overrides that half on its own.
  • online-mode — whether the server verifies accounts with Mojang. Defaults to #true. (online-mode) See Offline mode for how it changes the way players are identified.
  • hide-online-players — whether the server list ping leaves out the names of the players online. The player count stays visible. Defaults to #true. (hide-online-players)
  • seed — the world seed, as an integer or a string. Random when omitted. (level-seed)
  • eula — indicates that YOU have read and agree to the Minecraft EULA. The instance refuses to start until this is #true. Defaults to #false.
  • ip — the address to bind. When omitted, the server binds all addresses, IPv6 included. (server-ip)
  • port — the game port. Defaults to 25565. (server-port)
  • rcon-port — the remote console port. Defaults to 25575. (rcon.port)
  • capacity — the maximum number of players. Defaults to 20. (max-players)
  • view-distance — in chunks. Defaults to 16. (view-distance)
  • simulation-distance — in chunks. Defaults to 16. (simulation-distance)

properties

A block inside server holding overrides for any other server.properties key. mc generates the file on every start — hand edits do not survive — so this block is the way to reach settings that have no server field:

server {
    properties {
        spawn-protection 16
        enforce-whitelist #false
        "query.port" 25565
    }
}

Values may be strings, integers, floats, or booleans. Keys containing a dot must be quoted, as above; a nested block spells the same key, so rcon { broadcast "yes" } sets rcon.broadcast.

Any key is accepted, since mods read their own settings from the same file, but mc run prints a warning for each key in this block that is not a known server property, so a typo does not go unnoticed.

Keys managed by mc are rejected: an entry for a key that a server field or the top-level name and description already drive is an error naming the field to use instead. Every managed entry is reported in the same error, so one pass fixes them all. enable-rcon is rejected too — RCON is enabled exactly when an RCON password is configured (see Environment Variables).

Every key not written here takes the vanilla default as of Minecraft 26.3, listed on the server.properties wiki page, with three exceptions:

  • enforce-whitelist — follows allow-list, so #true by default.
  • server-ip"::", all addresses, IPv6 included; driven by ip.
  • spawn-protection0.

mods

The mods to install, grouped by where they come from. Inside a group, each node is named after the mod and carries where to fetch it:

mods {
    // mods from the registry, pinned to a version identifier
    modrinth {
        lithium "..."
        carpet "..."
    }

    // jars fetched from a URL, for mods not on the registry
    http {
        my-mod "https://example.com/my-mod.jar"
    }
}

modrinth maps a mod’s identifier (slug) on the registry to the version identifier to install. http maps a name of your choosing to the URL of a jar. A name may appear in only one group; it becomes the jar’s filename.

mc add, mc remove, and mc update edit the modrinth group for you and pin compatible versions. Required dependencies are resolved automatically when the instance starts and recorded in the mc.lock lockfile — see Managing Mods.

backups

Scheduled world backups, taken while the instance runs.

  • enabled — whether backups run on the frequency schedule while the instance runs. Defaults to #false, so a manifest without this field, or without a backups section at all, never schedules a backup. Manual mc backup works regardless.
  • frequency — a cron expression with six fields: seconds, minutes, hours, day of month, month, day of week. Defaults to "0 0 * * * *" (hourly).
  • keep — the number of most-recent automatic archives to keep in local storage; older ones are pruned. Defaults to 20. S3 storage is never pruned.
  • local — the directory archives are stored in. This is the default storage, under backups, when neither local nor s3 is written.
  • s3 — the bucket archives are uploaded to, with an optional region property. Credentials come from the standard AWS credential chain, and MC_BACKUPS_S3_BUCKET overrides the bucket. Without region, the region also comes from the credential chain.

Write at most one of local and s3.

backups {
    enabled #true
    frequency "0 0 * * * *"
    keep 20
    local "/mnt/data/mc"
}
backups {
    enabled #true
    s3 "my-minecraft-backups" region="us-east-1"
}

See the Backups guide for the full picture.

players

Who may join, who is kept out, and who holds server commands. Each group lists players as nodes named after them; a name that starts with a digit must be quoted. Options ride on the node as properties.

players {
    allow {
        Notch
        "123abc"
    }

    ban {
        Griefer reason="stole the beacon" created="2026-09-06T14:00:00Z" expires="2026-10-01T00:00:00Z"
    }

    ban-ip {
        "203.0.113.7" reason="bot traffic"
    }

    op {
        Notch level=4 bypasses-player-limit=#true
        jeb_
    }
}
  • allow — players permitted to join while allow-list in server is #true, which it is by default. Entries take no properties.
  • ban — players refused by the server. reason is shown to the player and defaults to the server’s own wording; created records when the ban was issued; expires lifts the ban at that time. Both dates are RFC 3339 timestamps. A player cannot be in both allow and ban.
  • ban-ip — addresses refused by the server, with the same properties as ban. Node names are IP addresses and must be quoted.
  • op — operators. level is the permission level from 1 to 4 and defaults to the server’s op-permission-level property; bypasses-player-limit lets the operator join when the server is full and defaults to #false. Operators may join regardless of the allow list.

mc allow, mc ban, and mc op edit these groups for you and look names up as they go. The lists are written to the instance on every start — see Players.

notifications

Webhook notifications about the instance. A provider is activated by setting its webhook environment variable (MC_DISCORD_WEBHOOK for Discord) — the URL is a secret and is never read from the manifest, and without one no notifications are sent. This block selects which events are reported; every key defaults to #true:

  • on-lifecycle-event — the instance started or stopped. When a tunnel is configured, the started message includes the address to join at.
  • on-panic — the instance crashed.
  • on-sigkill — the instance was forced down without a clean save, because it did not stop within the grace period or a second stop signal arrived.
  • on-backup — a backup completed.
  • on-backup-failure — a backup failed.
notifications {
    on-lifecycle-event #false
    on-backup #false
}

Environment Variables

The environment acts as an override layer on top of mc.kdl. Secrets are deliberately kept out of the manifest so it can be committed and shared safely: mc reads them from the environment, or from files it generates readable only by the owning user (see Instance Layout).

MC_RCON_PASSWORD

The password for RCON, the remote console protocol used to coordinate backups with a running instance. The environment is the only place it is read from: a "rcon.password" entry in the properties block of the server section is rejected, so the secret never lands in the manifest.

RCON is enabled exactly when a password is configured. When backups are enabled and no password is set anywhere, mc generates one at each start so backups work out of the box; set this variable when other tooling needs to reach the remote console with a known password.

MC_BACKUPS_S3_BUCKET

The S3 bucket that receives backup archives when the backups section names an s3 target. It takes precedence over the bucket written in the manifest.

S3 credentials are not read through mc-specific variables; they come from the standard AWS credential chain — AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY, the ~/.aws configuration files, or an attached IAM role.

MC_DISCORD_WEBHOOK

The Discord webhook URL that notifications are posted to. Setting it is what turns notifications on; without it none are sent. The notifications section of the manifest selects which events are reported — instance lifecycle, crashes, forced shutdowns, and backup results are all on by default.

Instance Layout

An instance is a directory with mc.kdl at its root. All mc commands run from that directory, and everything the instance needs lives under it:

myserver/
├── mc.kdl
├── mc.lock
├── .java/
├── .minecraft/
├── .tunnel/
│   ├── playit.toml
│   └── playitd.log
├── backups/
├── instance/
│   ├── eula.txt
│   ├── server.properties
│   ├── mods/
│   └── myserver/
└── temp/

Only one running server is allowed per instance directory; a second mc run in the same directory refuses to start.

mc.kdl

The manifest describing the instance — the only file you author. See The Manifest Format.

mc.lock

The lockfile, written in KDL. It holds the mods resolved from the manifest, including their required dependencies, and the identity resolved for every player named in the manifest. The mod entries are rewritten from the manifest’s pinned versions on every start; the player entries are added by the player commands and by a start that meets a name not yet recorded.

.java/ and .minecraft/

Installed Java runtimes and Minecraft binaries, keyed by version, shared by every start of this instance. Safe to delete while the instance is stopped; whatever is missing is downloaded again on the next start.

.tunnel/

Present when the manifest has a tunnel section. Holds the installed tunnel agents, keyed by version like .java/, the agent’s log in playitd.log when its output is not shown in the terminal, and playit.toml, the secret that links the agent to a tunnel provider account. The secret file is created readable only by the owning user when the agent is first claimed, and mc refuses to start if its permissions have been loosened. Deleting it makes the next start claim a new agent; mc tunnel claim --force does the same on demand. See Tunnels.

Instances created before tunnels existed have no /.tunnel entry in their .gitignore; add one before committing.

backups/

The default destination for backup archives when local storage is used. The directory is dedicated to this instance’s backups; see Backups.

instance/

The live working directory of the Minecraft process. Notable contents:

  • eula.txt — generated from the eula key in the manifest.
  • server.properties — generated from the manifest on every start; manual edits are overwritten. Use the properties block of the server section in mc.kdl instead. When the file holds secrets, such as an RCON password, mc creates it readable only by the owning user and refuses to start if its permissions have been loosened.
  • mods/ — the installed mods. This directory is fully managed: mc adds and removes jars to match the lockfile, so a jar placed here by hand is deleted on the next start. Declare URL mods in the manifest instead.
  • whitelist.json, banned-players.json, banned-ips.json, ops.json — the player lists, generated from the players section of the manifest on every start. Changes the server writes to them on its own are replaced at the next start; use mc allow, mc ban, and mc op instead.
  • myserver/ — the world, named after the instance’s name. Everything else Minecraft writes at runtime (logs, player data, and so on) also lives here and is left untouched by mc.

temp/

Scratch space for in-flight downloads and archives. Cleared when the instance starts; safe to delete while nothing is running.

Commands

General Commands

mc

mc [OPTIONS] <COMMAND>

The mc binary is a collection of subcommands; run one of the commands documented in this chapter. Every command operates on the instance in the current working directory — the directory containing mc.kdl.

Global options

These options are accepted by every command.

  • -v, --verbose — more detailed output. Repeat for more: -v prints informational messages, -vv debug, -vvv trace. The instance’s console log level follows this setting.
  • -q, --quiet — do not print mc log messages.
  • --color <WHEN> — control colored output: auto (the default), always, or never.
  • -h, --help — print help.
  • -V, --version — print the mc version.

Exit status

mc exits with 0 on success and a non-zero code on failure. mc run propagates the instance’s own exit code when the instance ends abnormally.

mc help

mc help [COMMAND]

Prints help for mc or for the given command. Equivalent to passing --help:

mc help init
mc init --help

The top-level help, mc help or mc --help, ends with a link to this book.

mc completions

mc completions <SHELL>

Prints a completion script for the given shell to standard output. Accepted shells: bash, elvish, fish, powershell, zsh.

Install it wherever the shell loads completions from. For example:

mc completions fish > ~/.config/fish/completions/mc.fish
mc completions bash > ~/.local/share/bash-completion/completions/mc
mc completions zsh > ~/.zfunc/_mc

The script describes the commands and options of the binary that generated it; regenerate it after upgrading mc.

Examples

mc completions fish > ~/.config/fish/completions/mc.fish

Manifest Commands

Commands that create or edit mc.kdl:

  • mc init — create a new instance.
  • mc add — add mods to the manifest.
  • mc remove — remove mods from the manifest.
  • mc update — update pinned mod versions.
  • mc allow — manage the allow list.
  • mc ban — manage the ban list.
  • mc op — manage the operators.

mc init

mc init [OPTIONS] [PATH]

Creates a new instance: a mc.kdl manifest and a .gitignore. PATH defaults to the current directory and is created if it does not exist. The command refuses to run where a mc.kdl already exists.

The generated .gitignore excludes runtime state — the installed JDKs and Minecraft binaries, the live server directory, scratch space, and run-time lock files — so an instance can be versioned with git. The manifest and the mc.lock lockfile are not excluded: commit them to make the instance reproducible. An existing .gitignore is left untouched; a warning lists any of these entries it lacks.

Options

  • --name <NAME> — the instance name. Defaults to the directory name.
  • --eula — record your agreement to the Minecraft EULA in the generated manifest. Without it, the manifest is created with eula #false and the instance will not start until you edit it.
  • --preset <PRESET> — the shape of the generated manifest:
    • vanilla — no mod loader and no mods.
    • optimized — a mod loader plus performance mods. This is the default.
    • technical — a mod loader plus performance mods and tools for technical play.

Presets pin the latest Minecraft release and compatible mod versions at the time the command runs; the generated manifest is a starting point to edit, not a fixed template.

Examples

mc init myserver
mc init --preset technical --eula
mc init myserver --name "smp" --preset vanilla

mc add

mc add [OPTIONS] <MOD_SLUG>...

Adds mods to the modrinth group of the manifest’s mods block. Each MOD_SLUG is the mod’s identifier on the mod registry. The latest version compatible with the configured Minecraft version and loader is looked up and pinned; the command fails if a mod cannot be found for that combination.

A mod loader must be configured under minecraft before mods can be added.

Changes take effect the next time the instance starts, which also installs any required dependencies — see Managing Mods.

Options

  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

Examples

mc add lithium
mc add carpet servux

mc remove

mc remove [OPTIONS] <MOD_SLUG>...

Removes mods from the manifest’s mods block, whichever group lists them. A slug that is not in the manifest is reported and skipped.

The jars are uninstalled the next time the instance starts. A removed mod’s dependencies are not kept: anything no longer required disappears from the lockfile and is uninstalled along with it.

Options

  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

Examples

mc remove carpet

mc update

mc update [OPTIONS] [MOD_SLUG]...

Re-pins mods in the manifest to the latest version compatible with the configured Minecraft version and loader. With no arguments every mod is updated; otherwise only the named ones. Mods already at their latest version, and mods fetched from a URL (which carry no version), are skipped.

The new versions are installed the next time the instance starts.

Options

  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

Examples

mc update
mc update lithium carpet

mc allow

Manage the allow list: the players permitted to join when the allow list is enabled, which it is by default. See the Players guide for how the lists reach the server.

mc allow add

mc allow add [OPTIONS] <NAME>...

Adds players to the allow group of the manifest’s players section. Each NAME is looked up to make sure the account exists and is recorded with the account’s own casing. A player who is already allowed is skipped with a warning; a player who is banned is refused until the ban is lifted.

When the instance is running and its remote console is reachable, the change is applied to it immediately. Otherwise it takes effect the next time the instance starts.

The list is still edited when allow-list in the server section is #false, but a warning points out that anyone can join until it is turned back on.

mc allow add Notch jeb_

Options

  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

mc allow remove

mc allow remove [OPTIONS] <NAME>...

Removes players from the allow list. Fails if a player is not on it. On a running instance, a removed player who is online is disconnected.

mc allow remove Notch

Options

  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

mc allow list

mc allow list [OPTIONS]

Prints the allowed players, one per line.

Options

  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

mc ban

Manage the ban list: players and addresses refused by the server. See the Players guide for how the lists reach the server.

mc ban add

mc ban add [OPTIONS] <NAME>...
mc ban add [OPTIONS] --ip <ADDRESS>...

Bans players, or with --ip, addresses. Player names are looked up to make sure the account exists and are recorded with the account’s own casing. A player who is already banned is an error. A player on the allow list is removed from it, with a warning.

When the instance is running and its remote console is reachable, the ban is applied to it immediately and an online player is disconnected. A ban expiry cannot be applied live: the player stays banned until the next restart, when the expiry takes effect. Anything not applied live is reported with a warning.

Every player and address named in one command shares the same reason and expiry.

mc ban add Griefer --reason "stole the beacon"
mc ban add Griefer1 Griefer2 --for 7d
mc ban add --ip 203.0.113.7 --ip 203.0.113.8 --until 2026-12-31T00:00:00Z

Options

  • --ip <ADDRESS> — ban addresses instead of players. May be repeated.
  • --reason <TEXT> — the reason shown to the banned player. Defaults to the server’s own wording.
  • --until <DATE> — lift the ban at an RFC 3339 date.
  • --for <DURATION> — lift the ban after a duration such as 7d, 12h, or 30m. Cannot be combined with --until.
  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

mc ban remove

mc ban remove [OPTIONS] <NAME>...
mc ban remove [OPTIONS] --ip <ADDRESS>...

Lifts bans on players, or with --ip, addresses. A player or address that is not banned is skipped with a warning.

mc ban remove Griefer1 Griefer2
mc ban remove --ip 203.0.113.7

Options

  • --ip <ADDRESS> — unban addresses instead of players. May be repeated.
  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

mc ban list

mc ban list [OPTIONS]

Prints the banned players, then the banned addresses, one per line with the reason, when the ban was issued, and when it expires.

Options

  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

mc op

Manage the operators: players granted server commands. Operators may join regardless of the allow list. See the Players guide for how the lists reach the server.

mc op add

mc op add [OPTIONS] <NAME>...

Makes players operators, or changes the settings of players who already are, with a warning. Player names are looked up to make sure the account exists and are recorded with the account’s own casing.

When the instance is running and its remote console is reachable, a new operator with the default settings is applied immediately. A custom level or the player limit bypass cannot be applied live and takes effect at the next restart, which is reported with a warning.

Every player named in one command gets the same settings.

mc op add Notch
mc op add jeb_ Dinnerbone --level 2 --bypass-player-limit

Options

  • --level <LEVEL> — the permission level, from 1 to 4. Defaults to the server’s op-permission-level property, which is 4 unless set in the properties block of the server section.
  • --bypass-player-limit — let the operator join when the server is full.
  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

mc op remove

mc op remove [OPTIONS] <NAME>...

Removes operators. A player who is not an operator is skipped with a warning.

mc op remove Notch

Options

  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

mc op list

mc op list [OPTIONS]

Prints the operators, one per line with their effective permission level.

Options

  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.

Instance Commands

Commands that operate on the instance itself:

mc run

mc run [OPTIONS]

Brings the instance in line with the manifest, then starts it. Anything missing or out of date is installed first: the Java runtime, the Minecraft binary, the mod loader, the mods (added, updated, and removed to match the manifest), and the tunnel agent when a tunnel is configured. The generated configuration files and player lists are rewritten from the manifest on every start. A warning is printed for every key in the manifest’s properties block that is not a known server property.

Only one running server is allowed per instance directory; a second mc run refuses to start.

While the instance runs, mc supervises it, and scheduled backups fire when enabled — see Backups. The instance’s console output is hidden unless --server-logs is passed; it is always written to instance/logs/ by the server itself. The console is not interactive; use the remote console (RCON) for live administration.

With a tunnel section, the tunnel agent starts beside the instance and is restarted if it stops on its own; the public address is printed at startup. The agent’s output is hidden unless --tunnel-logs is passed, and goes to .tunnel/playitd.log otherwise. The first start from a terminal prints a claim link to approve in a browser and saves the resulting secret under .tunnel/. Without a terminal and without a secret, mc run fails with instructions rather than waiting — see Tunnels.

Stopping

Ctrl-C (or SIGTERM, e.g. from a service manager, or SIGHUP, e.g. when the terminal that started the instance closes) asks the instance to save the world and shut down, and waits for it to exit before returning. If the instance hangs past a grace period, or a second signal arrives, it is forced down immediately.

A scheduled backup caught in flight is cancelled: it discards its partial archive and never damages stored backups — see Backups.

mc does not restart a crashed instance; run it under a supervisor for that — see Running under systemd.

Exit status

When the instance ends abnormally, mc run fails and propagates the instance’s exit code.

Options

  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.
  • --lockfile-path <PATH> — path to mc.lock. Defaults to ./mc.lock.
  • --server-logs — show the instance’s console output in the terminal.
  • --tunnel-logs — show the tunnel agent’s output in the terminal.

mc backup

mc backup [OPTIONS]

Archives the world and stores it in the storage target configured in the backups section — see Backups. Works whether or not scheduled backups are enabled.

The instance may be stopped or running. A running instance is reached over its remote console so the world is flushed to disk before it is archived; if the instance is running but the remote console is not available, the command refuses rather than capture a world that is still being written to. Only one backup can run at a time.

Named backups

By default the archive is named after the instance and a timestamp, and is subject to the storage’s retention limit. With --name, the archive is stored under the given name instead — for example myserver_pre-update.tar.gz — and is kept forever: named backups never count toward the retention limit and are never pruned. They appear in mc restore --list alongside automatic backups.

Names may contain ASCII letters, digits, - and _. If a backup with the same name already exists, mc asks before overwriting it (and refuses when it cannot ask, such as in a script).

Cancelling

Ctrl-C cancels a backup in progress: the partial archive is discarded, the instance’s auto-save is re-enabled, and the command fails with a non-zero exit status. Stored backups are never affected by a cancelled run.

Options

  • --name <NAME> — store the backup under a name and keep it forever instead of timestamping it and rotating it out.
  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.

Examples

mc backup
mc backup --name pre-update

mc restore

mc restore [OPTIONS]

Replaces the world with one restored from a backup. The instance must be stopped.

The world being replaced is moved aside rather than deleted; if the restore fails or is cancelled with Ctrl-C, the partially extracted world is removed, the original is put back, and the command reports the failure. One set-aside world is kept until the next restore replaces it.

A restore killed with no chance to clean up (power loss, SIGKILL) can leave no world in place while the set-aside copy still exists. mc run refuses to start in that state — instead of silently generating a fresh world — and explains how to recover: run mc restore again, or mc restore --undo to put the previous world back.

Undoing a restore

--undo puts the world set aside by the last restore back in place. When a world is currently present the two are swapped — nothing is deleted, and undoing again swaps back.

Options

  • --list — list the available backups instead of restoring. Shows both automatic (timestamped) and named backups; (latest) marks the newest automatic one.
  • --backup <BACKUP> — the backup to restore, by the filename shown by --list. Defaults to the most recent automatic backup; named backups are only restored when passed explicitly.
  • --undo — put the world set aside by the last restore back in place, swapping it with the current world.
  • --manifest-path <PATH> — path to mc.kdl. Defaults to ./mc.kdl.

Examples

mc restore --list
myserver_pre-update.tar.gz
myserver_2026-07-15_15-00-00.tar.gz (latest)
myserver_2026-07-14_15-00-00.tar.gz
mc restore
mc restore --backup myserver_pre-update.tar.gz
mc restore --undo

Installation Commands

Commands to inspect available versions and pre-install components. mc run installs everything it needs automatically, so these are mostly useful for exploring what is available and for provisioning ahead of time:

mc java

Manage Java runtimes.

mc java list

mc java list

Lists the runtimes mc can install, as vendor@version descriptors. The one marked (recommended) is the default used when the manifest does not configure version under java.

mc java list
graal@25 (recommended)
graal@21
...

mc java install

mc java install [OPTIONS] <VERSION>

Downloads a runtime into the instance’s .java directory. VERSION is a descriptor from mc java list; the version half may be omitted to take the vendor’s recommended version. Fails if the runtime is already installed.

mc run installs the configured runtime automatically; this command exists to provision one ahead of time.

Options

  • -p, --platform <PLATFORM> — install for a specific operating system instead of the current one.
  • -a, --architecture <ARCHITECTURE> — install for a specific CPU architecture instead of the current one.

Examples

mc java install graal@25
mc java install corretto@21

mc minecraft

Manage Minecraft versions and mod loaders.

mc minecraft list

mc minecraft list [OPTIONS]

Lists Minecraft versions, most recent first. By default only the ten most recent releases are shown, with the latest release and latest snapshot tagged.

Options

  • --all — show every version instead of the ten most recent.
  • -s, --snapshots — include snapshot versions.
  • -b, --betas — include beta versions.
  • -a, --alphas — include alpha versions.

mc minecraft list-loaders

mc minecraft list-loaders [OPTIONS]

Lists mod loader versions compatible with a Minecraft version, most recent first.

Options

  • -l, --loader <LOADER> — the loader to list versions for. Defaults to fabric.
  • -m, --minecraft-version <VERSION> — the Minecraft version to list loader versions for. Defaults to latest.
  • --limit <LIMIT> — the number of results. Defaults to 10.

mc minecraft install

mc minecraft install [OPTIONS] [VERSION]

Downloads a Minecraft binary into the instance’s .minecraft directory. VERSION accepts the same values as version under minecraft in the manifest (latest, latest-snapshot, or an exact version id) and defaults to latest. Fails if that version is already installed.

mc run installs the configured version automatically; this command exists to provision one ahead of time.

Options

  • -l, --loader <LOADER> — install the binary for a mod loader instead of the vanilla one, as a name or name@version descriptor (for example fabric).

Examples

mc minecraft install
mc minecraft install --loader fabric

mc tunnel

Manage the tunnel agent that makes an instance reachable from outside the local network. See the Tunnels guide for the full picture.

mc tunnel list

mc tunnel list [OPTIONS]

Lists the tunnel agent versions mc can install, most recent first. The one marked (latest) is what provider under tunnel resolves to when its version half is omitted or set to latest.

mc tunnel list
1.0.10 (latest)
1.0.9
...

Options

  • --limit <LIMIT> — the number of results. Defaults to 10.

mc tunnel install

mc tunnel install [OPTIONS] [PROVIDER]

Downloads a tunnel agent into the instance’s .tunnel directory. PROVIDER accepts the same values as provider under tunnel in the manifest, a name or name@version descriptor, and defaults to playit. Fails if that version is already installed.

mc run installs the configured agent automatically; this command exists to provision one ahead of time.

Options

  • -p, --platform <PLATFORM> — install for a specific operating system instead of the current one.
  • -a, --architecture <ARCHITECTURE> — install for a specific CPU architecture instead of the current one.

Examples

mc tunnel install
mc tunnel install playit@1.0.9

mc tunnel claim

mc tunnel claim [OPTIONS]

Links the instance’s tunnel agent to an account with the tunnel provider. The command prints a link; opening it in a browser while signed in to the provider approves the agent, after which the agent secret is saved to .tunnel/playit.toml, readable only by the owning user. The link expires after a few minutes.

mc run performs the same claim on its own when the instance starts from a terminal without a secret file, so this command is only needed to claim ahead of time, for example before deploying under a service manager, or to replace an existing secret.

Options

  • -f, --force — replace an existing secret with a fresh claim. The previous agent stays registered with the provider until it is removed there.

Examples

mc tunnel claim
    Claiming tunnel agent, approve it at https://playit.gg/claim/... with your playit.gg account
     Claimed tunnel agent secret saved to .tunnel/playit.toml