← Home
minecraft mcp self-hosting provenance chat-bridge

f004 Is Older Than My Daughter

f004 is a Minecraft survival world with about 228 hours on it, 138 deaths, 657 km walked, and three bases spread across 21 km of overworld. Nothing in it was spawned in. It predates my daughter, and somewhere in the middle of a long mining session it occurred to me that she is eventually going to be old enough to walk into it — not to be shown screenshots of it, but to load it and go somewhere I have never been.

That reframes the world from a save file into an archive. A save file lives on one laptop, in one launcher's instance directory, and its history is whatever you remember about it. On 2026-07-27 I moved f004 onto valoper, the Linux box in the house, as a vanilla dedicated server.

The reason was not performance. It was that a server has a console, and a console can have a chat bridge.

Moving it off the laptop

The install is rootless and lives entirely in ~/minecraft-server: Minecraft 26.1.2 vanilla, Temurin JRE 25 (26.1.2 is class file v69 — the system java will not run it), Aikar's flags, a fixed 6 GB heap, and a systemd user service with lingering on so it starts at boot and survives logout.

The one part worth copying is the shutdown path. The unit has SuccessExitStatus=143 and a blocking ExecStop that writes stop into a console.in FIFO and then waits for the JVM to exit. Without that, systemd SIGTERMs the process mid-save, and a 4.6 GB world that has been accumulating since before my kid can afford exactly zero rolled-back saves. A clean stop logs All dimensions are saved; anything else is a bug to fix before continuing.

Everything else in the repo — launch script, log tailer, backup script, the MCP server — is tracked in git. The world, the jar, the JDK and server.properties are not. git checkout will not recover a bad world edit, which is worth internalizing before you get clever.

server.properties wins

The first thing the migration broke was one I did not go looking for.

The single-player world was on normal. The dedicated server silently ran it on easy for a day, because a server reads difficulty from server.properties and then writes that value into level.dat on the next save. The installer's default quietly overwrote a setting the world had carried for 228 hours. I only caught it by diffing the live level.dat against the pre-migration backup, which still read difficulty = normal.

All 138 prior deaths happened on normal. Restoring it was one line, but the lesson generalizes: settings a world carried from single-player are not authoritative once it is served. If you migrate a save you care about, diff it against the original rather than assuming the world brought itself over intact.

The chat bridge

mc-chatbridge.service watches the log for chat and lets a non-op player drive server operations by typing verbs in-game:

Verb Does
!help list verbs
!tick tick health as a % of the 50 ms budget
!where your coords, dimension and chunk
!search [radius] nearby entities by type + nearest position
!backup run a snapshot now, reports completion
!pin / !unpin forceload the 3×3 chunks around you
!mark <name> record this spot in landmarks.json
!progress remaining steps to beating the game
!ask <question> advisory Claude — no tools, no console, no MCP
!note <text> append a position-stamped entry to journal.md
!notes [n] read back the last few entries

It works because the console.in FIFO runs at full permission. Which is exactly why the verb list is closed and there is deliberately no !cmd <anything> passthrough — adding one would make chat equivalent to op, and ops.json is empty on purpose.

!note and !mark are the ones that matter for the archive. Both write position-stamped records into git-tracked files, from inside the game, without alt-tabbing. Two lines currently in journal.md:

2026-07-28 05:22  (-1074, 62, -18903 overworld)
  I want to clear this mansion and then win the game
2026-07-28 21:29  (485, 63, -19397 overworld)
  the reward mechanism for the offline farming is extra incentive to login

Those are worth more than the coordinates. In twenty years the block placements will still be there and the intent behind them will not be, unless something wrote it down at the moment it existed.

The aid ceiling

Once a world has a console API and an assistant attached to it, the interesting constraint stops being technical.

The rule is: tooling may read, record and report; it may not act in the world on the player's behalf. !ask is advisory — no tools, no console access, no MCP. Agents don't play. Raising that ceiling is explicitly reserved until after the dragon is down, so the run gets finished at the level of assistance it has always had.

!search is the deliberate exception, and it's the useful one to think about. It reports entities within a radius — type, count, and the nearest one's coordinates. That is information the game hides behind walls. It is mob ESP. It only reads, so it sits inside the letter of the ceiling, but unlike !where it is a genuine survival advantage in a cave. It went in knowingly, after being flagged and asked about.

That's the precedent worth keeping: read-only is not automatically harmless. The permission model and the integrity model are different things, and a tool can be perfectly safe for the server while being corrosive to the run.

Fifteen tools, and the ones left out

Minecraft 1.21.9 added a Server Management Protocol — a JSON-RPC/WebSocket admin API. This build reports API 2.0.0 and 85 methods (68 callable, 17 notifications), dumped from a live rpc.discover so the capability list is the server's own answer rather than documentation that may describe a different revision.

There's an MCP server over it exposing 15 curated tools — status, players, allowlist, operators, bans, gamerules, settings, recent events, plus say/save/kick/allowlist-edit/gamerule-set. It reads config live from server.properties, so the management secret exists in exactly one place and is never copied into a registration file.

The omissions are the design:

The API also has no method for chat or deaths — every one of its 17 notifications is administrative. Chat and dying are gameplay and have no RPC surface at all, so a log watcher tails latest.log and merges synthesized events into the same ring buffer, each tagged rpc or log.

Death detection there is a deny-list, not an allow-list: a line is a death if it starts with a known player name and is not one of the small, closed set of known non-death formats (joined, left, lost connection, moved too quickly, issued server command, advancements). Vanilla has 100+ death strings and they change between versions. Allow-listing death verbs silently misses new ones; inverting it means a death message introduced in a future update is caught automatically, and the failure mode is a spurious death rather than a missing one.

BridgeTon separates roof traffic from portal traffic

The three bases sit at Village (X 874, Z 375, near world origin), BridgeTon (X 486, Z −19394), and SeaPort (X 878, Z −21578) — the latter two roughly 19.4 km and 21.5 km north.

Nether coordinates are overworld ÷ 8, and that ratio is the whole argument for where to settle:

Leg Overworld Nether
Village ↔ BridgeTon 19,773 2,471
BridgeTon ↔ SeaPort 2,219 277
Village ↔ SeaPort 21,953 2,744

BridgeTon has two portals, and they carry different kinds of traffic. One links to SeaPort — a 277-block nether hop, which is why those two pair naturally and why the settlement grew as a pair rather than as one site. The other goes up to the nether ceiling, where a roof route runs the full 2,471 blocks back to Village. (The ceiling access came from the ender-pearl-through-portal trick, not from breaking bedrock.)

Keeping those separate is what makes BridgeTon a hub rather than a junction. Roof travel is long-haul and uninterrupted — no ghasts, no terrain, no piglins. Normal portal traffic is short-haul and local. Routing them through one portal means every trip to SeaPort dumps you into the highway network and vice versa; splitting them means each portal has one job, and BridgeTon physically sits between the two. That's the ideal shape for a settlement: not the prettiest spot, the one where two transport regimes meet and neither has to compromise.

Portal pairing stays fragile regardless. A new portal lit within 128 nether blocks of an existing one can link to it instead of creating its own, so a misbehaving link usually means a competing portal, not a broken game.

The name is not a metaphor. BridgeTon is a literal bridge, and the same separate-the-traffic instinct runs vertically through it. Villagers work the deck during the day — that's where the melon farm and the trading are — and go below to bunk for the night. Day shift on top, beds underneath.

Which is mostly a mob-mechanics argument dressed up as town planning. Villagers need beds they can path to and a workstation they can claim, and at sea level in the far north the surface at night is a spawning surface. Putting the sleeping quarters under the deck means the population is enclosed by the structure it works on, without walling off the working level or breaking line of sight along the span. The bridge is the roof.

It also means the settlement has a shape rather than a footprint. Village sprawls the way an original base does — built outward from wherever the first chest went. BridgeTon has a deck, an underside, and two portals with one job each, because every part of it was placed after the traffic pattern was already understood.

The world ticks when nobody is watching

The biggest change to how the game actually plays is two settings.

pause-when-empty-seconds=0 keeps the tick loop running with zero players online. Then 36 forceloaded chunks — a 3×3 block at each of the four sites — keep those specific chunks loaded and simulating. Village, BridgeTon, SeaPort, and mansion-farm, an outpost about 108 blocks from the woodland mansion.

The melon farm on the BridgeTon deck is the clearest beneficiary, and it's the economic engine of the whole site — melons are the main source of emerald grinding, and the emeralds are what pay for the lower nether side of the bridge. The farm, the villagers who buy from it, and the beds they sleep in are all one structure, which is why the whole thing is worth pinning as a unit.

Melons are slow: stem growth, then fruit, then the same again after harvest, all gated on random tick. Single-player, that clock only advances while you're standing there, so a melon farm is really a measure of how long you were willing to stand around — and an emerald economy built on one is capped by the same thing. Server-side with the chunk pinned, it runs on wall-clock time. Log off on Tuesday, come back Thursday, and the farm has been producing the entire time.

That's what makes the lower nether construction tractable. Bridging in the nether is a materials problem before it's a building problem, and the trading loop that funds it is no longer rate-limited by how long I'm willing to stand in a field.

What surprised me is which direction that pushed. I expected offline production to make logging in less necessary — the farm handles it, so why show up. It did the opposite, and my own journal caught it in the moment: "the reward mechanism for the offline farming is extra incentive to login."

Production became continuous while harvest stayed discrete, and that gap is the whole effect. World state now advances as a function of time rather than of observation, so logging in is collection rather than initiation, and the payoff scales with how long I've been away. Short sessions became worth having — which is the actual constraint on playing a survival world with a kid in the house. Sitting down for fifteen minutes used to be pointless because fifteen minutes of standing in a field is nothing. Now fifteen minutes is a harvest.

Steady CPU with nobody online is therefore expected, not a hung process — a thing worth writing down before it looks like a bug at 2 a.m.

Iron, because tools last longer

The second-order effect took longer to notice and is the more interesting one.

Once the world stopped being scarce in melons, tools stopped being disposable. Repairing and combining gear rather than re-crafting it means running everything through an anvil — and anvils are consumable. Each use has a chance to degrade one stage, and three stages in it breaks outright. An anvil is 31 iron ingots. Keeping a pickaxe alive across hundreds of hours quietly converts into a standing iron demand, forever, at a rate set by how much I care about the tools.

So a melon farm produced a bridge, and tool longevity produced an iron problem. Neither was designed; both fell out of removing one rate limit and letting the consequences propagate.

That's the thing I actually got out of moving the world to a server. The meta-game became visible — not "mine ore, build things," but the specific supply chains that gate progress and how each one throttles the next. Iron gates anvils, anvils gate tool lifetime, tool lifetime gates how far out I'm willing to operate, and how far out I'm willing to operate is the entire remaining problem, because eyes of ender are a travel problem before they're a combat one.

For the first time in 228 hours I can see the shape of the whole run. I think I can beat it.

Phase 1

None of this is allowed to make survival easier, because the world isn't finished. Nether, fortress and blaze rods are done. Eyes of ender, entering the End, and the dragon are not.

That ordering is the standing constraint on every decision above — it's why ops.json is empty, why the chat bridge has a closed verb list, why the world-editing options are ranked by what they cost in integrity rather than by what they can do, and why the difficulty drift got treated as a bug instead of left alone.

Phase 2 starts when the dragon is down: Paper or Fabric, WorldEdit, larger automation, and — the part I'm actually interested in — writing mods for this server rather than only installing them. The aid ceiling lifts then too. It's deferred, not rejected, and the sequencing is the whole point. Building tools for a world you're still trying to beat is a good way to end up with excellent tools and an unfinished world.

What I want at the end isn't a finished world. It's a world with a legible history — landmarks with names and coordinates, a journal with intent attached to positions, backups that go back further than my memory does. Then when my daughter loads f004, BridgeTon is a place someone decided to build, for reasons that are still on the record, and not just a bridge that happens to be there.

×

Follow on Mastodon