跳到正文

MCP-rogal

作者:Roga1

Drive Minecraft from an AI assistant while you build mods and datapacks: real command results, searchable live logs, keyboard and mouse control, sandboxed datapack files, and fake players for testing multiplayer rules.

收藏

截图

介绍

中文介绍正在准备中,下面暂时显示原文。

MCP-rogal

An MCP server for building Minecraft mods and datapacks.

Point an AI assistant at your running game and it can write a datapack, reload it, run it, read
the error the game actually produced, and fix it — without you relaying anything by hand.

26 tools, Fabric, Minecraft 26.2.


The idea

Most of the time lost writing a datapack goes to one thing: something did not work and the game
would not say why. A macro missing one $(key) aborts the whole function. /reload reports
success while the pack it just tried to load failed. A trigger that was never armed looks exactly
like a button that does nothing.

So every command comes back with what really happened:

time set day                            → success=true    result=1000
setblock ~ ~ ~ minecraft:not_a_block    → errorType=parse  cursor=15
execute if block ~ ~ ~ bedrock run say  → success=false    error=null

Three different outcomes, told apart: it worked and returned 1000; it never parsed, and here is
the character where parsing stopped; it ran fine and did nothing at all.

That last line is the one that matters. It is what a silent failure looks like, and it is now
visible instead of indistinguishable from success.


What it can do

Commands and timing

  • execute_commands — real status, return value, parse errors with a cursor position.
    run_as: {player, permission_level} runs at a chosen permission level: execute as X rebinds
    @s but keeps your permissions, so an operator-gated path looks fine until a real player
    hits it. This tests the path a real player takes.
  • advance_ticks, and a wait_ticks argument — state written this tick is not visible to a
    read until the next one, so a read/write pair issued together silently sees stale values.
  • validate_command — parse without running; also returns the completions available at the
    cursor, which is how you discover what an argument accepts.

Logs

  • get_logs — cursor-based. The response carries nextId; pass it back and you get only
    what arrived since. Reports missed when the buffer overflowed past your cursor, so a gap is
    visible rather than silent. Covers both the log file and in-game chat, which never reaches it.
  • wait_for_log — blocks until a pattern appears. Trigger something, then wait for the line
    that tells you whether it worked, instead of polling.
  • get_crash_reports — for when the game died along with the buffer.

Datapacks

  • files — read, write, list, inside an allow-listed set of directories.
  • reload_datapacks — runs /reload and returns the log it produced, because /reload
    succeeds even when a pack fails to load.
  • get_world_info — save folder, datapack folder, and the pack formats this build
    expects
    . A wrong pack_format gets the pack rejected with nothing but a vague "Error reading
    pack metadata", while every function inside it quietly does nothing.
  • list_ids, describe_block_state — valid ids by registry, and the exact properties a
    block accepts in [brackets] with their allowed values and defaults. No more guessing whether
    a door needs half=upper or part=head.

Fake players

fake_players — real ServerPlayers in the player list, for testing rules that only exist
with more than one player. @a selects them, scoreboards score them, their UUID is derived from
their name so scores survive death, kill respawns them rather than leaving them dead, despawn
fires a genuine leave event, and /tp moves them between dimensions.

Nothing in game logic checks "is this one fake, skip it" — a test against special-cased code
proves nothing about the real thing.

What they cannot do: press a button in a dialog. That needs a client.

Client control

  • press_key, type_text, send_keybind, mouse — input goes through the same
    entry points real input does, so it behaves identically in the world, in menus and in text
    fields.
  • get_open_screen — every widget with its rendered text and rectangle. Inspect a menu
    without reading a screenshot; missing translations show up immediately, because an untranslated
    widget renders its raw key.
  • click_widget — click by the button’s visible label. An ambiguous match clicks nothing and
    returns the candidates. Labels like "Delete World" are refused without explicit permission.
  • open_screen, options — jump straight to a screen, or change a setting without
    dragging a slider.
  • reload_resources — F3+T, which has no command.
  • rejoin_world — dynamic registries (dialog/, enchantment/, worldgen/) are only read
    when a world loads. /reload leaves the old definitions in place, which looks exactly like
    your edit having no effect.

Setup

Requires: Minecraft 26.2 · Fabric Loader 0.19.3+ · Fabric API · Java 25+

  1. Install Fabric Loader for 26.2
  2. Put Fabric API in mods/
  3. Put this mod’s jar there too
  4. Start the game

The server starts on its own and logs:

HTTP MCP Server started on http://localhost:8080/mcp with 26 tools

Works on a client and on a dedicated server. On a dedicated server the tools that need a screen
are simply not registered.

Connecting an assistant

Claude Code:

claude mcp add --transport http minecraft http://localhost:8080/mcp

Cursor, Windsurf, VS Code — in your MCP config:

{
  "mcpServers": {
    "minecraft": {
      "url": "http://localhost:8080/mcp"
    }
  }
}

A world has to be loaded. Without one the tools say so plainly.


In practice

The whole datapack loop, without leaving the game:

Write a function that gives every hunter a compass, put it in a datapack, reload it, and tell
me whether it loaded.

get_world_info for the folder and pack format → files write → reload_datapacks → read the
log. A pack that failed to load is reported, not assumed away.

Testing the non-operator path:

Check that /dialog show is refused for an ordinary player but works through /trigger.

execute_commands with run_as: {permission_level: 0}.

A multiplayer rule:

Spawn two fake players, assign roles, and check each hunter gets their own compass.

Menu navigation:

Open the video settings and tell me what they are set to.

open_screen, then get_open_screen returns the text of every widget.


Configuration

config/mcp.json, created on first run:

{
  "server": { "port": 8080, "host": "localhost", "requestTimeoutMs": 30000 },
  "input":  { "enabled": true, "allowDestructiveUi": false,
              "preventPauseOnLostFocus": true },
  "logs":   { "bufferSize": 5000, "maxWaitMs": 60000, "maxBodyLogChars": 2000 },
  "files":  { "enabled": true, "allowDelete": false,
              "allowedRoots": ["saves","config","datapacks","resourcepacks",
                               "logs","crash-reports"] },
  "fakePlayers": { "enabled": true, "maxCount": 8 },
  "auth":   { "token": null }
}

preventPauseOnLostFocus — singleplayer normally pauses the moment you click into another
window, and the pause menu covers the view. Every screenshot and every screen read would then
report the pause menu instead of the game. This is off by default here; Escape still pauses.


Security

This endpoint runs commands, injects input and writes files. Treat it accordingly.

  • auth.token — when set, requires an Authorization: Bearer <token> header.
  • The server refuses to start on a non-loopback host without a token.
  • Files — confined to the allow list; paths resolving outside it, through .. or a symlink,
    are refused. Deleting is off by default.
  • Destructive buttons — clicking "Delete World" and the like needs both a config flag and an
    explicit argument.
  • Commands still pass a configurable safety validator.

Technical notes

  • Input goes through the private KeyboardHandler and MouseHandler callbacks via mixin
    invokers rather than KeyMapping, which is why it works in menus and text fields and not only
    in the world.
  • Commands run on the server thread through CommandSourceStack.withCallback, with parse errors
    separated from runtime errors. In singleplayer that means the integrated server, so results are
    real rather than inferred from chat.
  • Logs are captured by a Log4j appender attached programmatically, with a reentrancy guard.
  • Tools live in a registry — adding one is a single class.
  • Everything touching the loader sits behind a Platform interface, so a NeoForge port is the
    entry point, the tick subscription and the mixin config; the rest is plain Minecraft API.

Troubleshooting

It will not connect — look for HTTP MCP Server started in the log. Port 8080 may be taken;
change server.port.

"No server is running" — no world is loaded.

A command returns success=false with no error — it ran and did nothing. Usually a condition
that did not match, or a function that returned early. Not a tool failure.

/function is always success=false — vanilla behaviour: a function returns 0 unless it
ends with /return. Check the world state, or add a /return.

A datapack is not picked up — check pack_format against get_world_info.

An edit does nothing after /reload — if it is under dialog/, enchantment/ or
worldgen/, use rejoin_world.

A click did not register — screens that fade out switch a few ticks later. Raise
settle_ticks or read get_open_screen again.


Credits and license

Built on top of mcp-server-mod by cuspymd, which
provided the original HTTP MCP bridge, the command safety validator and the block scanner.

Released under CC0-1.0, the same as the original — public domain, no strings.

Full tool reference: TOOLS.md · Русское описание: DESCRIPTION.ru.md

常见问题

MCP-rogal 支持哪些 Minecraft 版本?

MCP-rogal 支持 Minecraft Java 版 26.2,可用的加载器:Fabric。下载时注意选择和你游戏版本一致的文件。

MCP-rogal 怎么安装?

先用 PCL2 或 HMCL 启动器安装对应版本的 Fabric,再把下载的 .jar 文件放进游戏目录的 mods 文件夹,重新启动游戏即可。开启了版本隔离的,mods 文件夹在 versions/版本名 下面。

评论

登录后评论和评分

Roga1 的其他作品

查看全部 →