BlockHand

io.github.gjlmotea由 GitHub 帳號 gjlmotea 發布v0.1.1更新於 Oct 26, 2026

Minecraft Education Edition MCP server: Agent robot, 24 build shapes, events. No add-on needed.

已驗證STDIO僅桌面開發者工具媒體與設計

概覽

AI 產生的概覽

讓 AI 助理操控《Minecraft Education》:控制 Agent 機器人、搭建形狀、讀取方塊、比較區域並回應遊戲事件。

可以做什麼
  • 控制 Agent 機器人:召喚、移動、轉向、傳送、放置、收集、管理背包、感測方塊並執行動作序列
  • 編輯世界:設定、填充、複製、讀取與偵測方塊,比較區域、檢查對稱性、查詢目標、召喚實體、調整時間天氣與遊戲規則、儲存結構
  • 依形狀與藍圖建造:24 種幾何形狀並支援空心,可預覽方塊數量與填充批次
  • 作用於玩家並給予回饋:傳送、給予物品、遊戲模式、效果、訊息、音效與粒子
  • 訂閱方塊放置、物品合成、玩家發言等遊戲事件,並以游標輪詢
  • 在沒有專用工具時執行原始斜線指令,並查看連線狀態
適用情境
適合教學、示範或創造模式建造,讓助理在 Minecraft Education 世界中搭建、檢查或驗證建築,或對遊戲內事件作出反應。適合已在與遊戲同一台桌面上執行支援 MCP 的 AI 用戶端的使用者。
執行需求
透過 npx 以 stdio 在本機執行,執行 AI 用戶端的機器需要 Node.js 22 或更新版本。Minecraft Education 需開啟一個已啟用作弊的世界,連線玩家需有管理員權限。遊戲透過 /connect 指令連線伺服器,位址與連接埠由 MINECRAFT_EDU_WS_HOST 和 MINECRAFT_EDU_WS_PORT 設定。無需帳號或 API 金鑰。
安裝前請注意
助理可以改動世界:建造、填充、複製、將結構存到磁碟、執行擊殺或清除等玩家操作,以及送出原始斜線指令。免手動模式會讓它重新載入資源包、離開並重新進入世界、重啟遊戲並向遊戲視窗送出按鍵,可能佔用螢幕。hub 狀態檔保存存取權杖。WebSocket 協定未公開,可能隨遊戲更新變動。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 BlockHand,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

BlockHand — MCP server for Minecraft Education

English | 繁體中文

[BlockHand: an MCP server for Minecraft Education Edition]

BlockHand gives AI agents hands and eyes inside Minecraft Education Edition. Claude Code, Codex, Gemini CLI, Grok or any other Model Context Protocol client can drive the Agent robot, build structures, read blocks, compare regions and react to game events.

It talks to the game only through Minecraft Education's built-in /connect (/wsserver) WebSocket command. There is no add-on, behavior pack, mod or Script API to install in the game, nothing is injected into the game process, and no screen reading is involved. On a school computer, the only thing to install is the AI client.

  • 44 tools and 2 resources: Agent robot control, world edits, 24 build shapes, blueprints, block reading, region comparison, symmetry checks and event subscription.
  • Fast building: shapes are merged into the fewest possible /fill commands (a solid sphere of radius 8 goes from 2,000+ blocks to under 200 commands).
  • Local by default: the game WebSocket listens on 127.0.0.1 unless MINECRAFT_EDU_WS_HOST changes it, and no account or online service is involved.
  • One fixed address: every AI session on the machine shares one background hub, so the game always connects with /connect 127.0.0.1:19131.
  • Hands-off by design: the agent reloads packs, rejoins the world and restarts a hung game by itself instead of asking the player to. The player is needed only to sign in. See Hands-off operation.
  • Installers for Claude Code, Codex, Gemini CLI and Grok CLI when you run from source.

The /connect command is an official interface. The WebSocket message protocol behind it has no published stability guarantee, so behavior should be re-checked after game updates.

Contents

Quick start

Requirements:

  • Minecraft Education Edition, in a world with Cheats on. The player who connects needs operator rights. Verified on 1.26.32 (Windows desktop and macOS 14+).
  • Node.js 22 or newer on the machine that runs the AI client.

1. Register the server with your AI client

Claude Code:

bash
claude mcp add blockhand --scope user -- npx -y @gjlmotea/blockhand-mcp

Codex:

bash
codex mcp add blockhand -- npx -y @gjlmotea/blockhand-mcp

Clients that read an mcpServers JSON config (Claude Desktop, Cursor, Gemini CLI):

json
{  "mcpServers": {    "blockhand": {      "command": "npx",      "args": ["-y", "@gjlmotea/blockhand-mcp"]    }  }}

VS Code uses a top-level servers key instead, and each server has a type:

json
{  "servers": {    "blockhand": {      "type": "stdio",      "command": "npx",      "args": ["-y", "@gjlmotea/blockhand-mcp"]    }  }}

Where each client keeps the file:

ClientConfig file
Claude DesktopmacOS: ~/Library/Application Support/Claude/claude_desktop_config.json; Windows: %APPDATA%\Claude\claude_desktop_config.json. Settings → Developer → Edit Config opens it
Cursor~/.cursor/mcp.json for every project, .cursor/mcp.json inside one project
Gemini CLI~/.gemini/settings.json (user), .gemini/settings.json (project)
VS Code.vscode/mcp.json in the workspace, or the user mcp.json that the MCP: Open User Configuration command opens

Sources: Claude Desktop, Cursor, Gemini CLI, VS Code.

Desktop apps started from Finder or the Start menu often do not see your shell's PATH. If the server fails to start with a vague "server not responding" error, replace npx with its absolute path (which npx on macOS, where npx on Windows).

Restart the AI client after registering.

2. Connect the game

The game connects to the server, not the other way round.

  1. Open a world in Minecraft Education. The main menu is not enough.

  2. Make sure Cheats are on.

  3. Type in the chat:

    /connect 127.0.0.1:19131

If your agent can send keys to the game window (see Hands-off operation), it types this itself; it reads the exact command from mc_status.

When the connection is made, a green "✔ BlockHand connected" line appears in the chat, in the game's own language: English, Traditional Chinese or Simplified Chinese, and English for any other game language. You can also ask the AI to call mc_status, which returns the exact connectCommand.

3. Ask for something

Build a hollow glass sphere with radius 6 in front of me.

Summon the Agent, walk it five blocks forward and plant a row of wheat.

Check whether the house at 0 64 0 to 20 80 20 is mirror-symmetric and show me which blocks break the symmetry.

Install from source

Use this route to work on BlockHand itself, or to use the installers and the doctor check.

bash
git clone https://github.com/gjlmotea/blockhand-mcp.gitcd blockhand-mcpcorepack pnpm install --frozen-lockfilecorepack pnpm run build

Register with one of the installers:

bash
corepack pnpm run setup:claude    # or setup:codex / setup:gemini / setup:grokcorepack pnpm run doctor          # add --client=claude etc. to check another client

The installers do more than write a config entry:

  • They fill in the absolute path of this machine's Node, so desktop apps that cannot read nvm, Homebrew or your shell PATH still start the server.
  • Before changing any setting, they run a real MCP initialize with the exact command, arguments and environment they are about to save, and check that all 44 tools are there.
  • They do nothing when the server is already registered correctly, so re-running is safe.
  • When an entry with the same name exists but differs, they stop and show the difference instead of overwriting someone else's settings.
  • They write only through each client's official mcp add / mcp remove command, never by editing config files directly.

Remove with corepack pnpm run uninstall:claude (or uninstall:codex, and so on). It refuses to remove entries it cannot identify as belonging to this checkout.

ClientWrites toThen
Codex~/.codex/config.tomlQuit and restart; desktop app, CLI and IDE share it
Claude Code~/.claude.json (user scope)Restart the session
Gemini CLI~/.gemini/settings.json (user scope)Restart the CLI
Grok CLI~/.grok/config.tomlRestart the CLI

To register by hand, point the client at <NODE> <REPO>/dist/index.js, where <NODE> is the absolute path from node -p "process.execPath" and <REPO> is the absolute path of the checkout. Claude Code and Gemini CLI place the command differently:

bash
claude mcp add blockhand --scope user -- <NODE> <REPO>/dist/index.jsgemini mcp add --scope user blockhand <NODE> <REPO>/dist/index.js

Claude Code wants -- before the command. Gemini CLI takes the command right after the name (gemini mcp add [options] <name> <commandOrUrl> [args...]); a -- there would leave it without a command. Gemini only needs -- after the command, in front of server arguments that collide with its own options, and BlockHand takes no arguments. Gemini's default scope is project, so use --scope user to make it global. Claude Code's default scope is local; --scope project writes a shareable .mcp.json, which is handy for a whole class. Sources: Claude Code, Gemini CLI.

Tools

Connection and fallback (6)

ToolPurpose
mc_statusBridge state, the /connect command, subscribed events, command counters. Check this first when anything fails
mc_await_connectionWait for the game to connect (up to 120 seconds per call)
mc_run_commandOne raw slash command, for anything without a dedicated tool
mc_run_commandsSeveral raw commands in order
mc_undo_controlInspect, clear or configure single-step undo (off by default)
mc_undoUndo the last protected build, after checking for conflicting changes

Agent robot (10)

ToolPurpose
mc_agent_createSummon the Agent
mc_agent_moveWalk N blocks in a direction
mc_agent_turnTurn left or right by 90 degrees
mc_agent_teleportBring a lost Agent back to the player
mc_agent_actAttack, destroy or till, optionally repeated
mc_agent_placePlace a block from an inventory slot
mc_agent_collectPick up dropped items
mc_agent_inventoryCount, free space, item detail, drop, drop all, transfer
mc_agent_senseInspect, inspect data, detect, detect redstone: the Agent's eyes
mc_agent_programSend a whole sequence of actions in one call and get a result per step

Agent directions are relative to the way the Agent is facing, not compass directions.

World (13)

mc_set_block, mc_fill, mc_clone, mc_test_block, mc_read_block, mc_verify_reading, mc_compare_regions, mc_analyze_symmetry, mc_query_target, mc_summon, mc_world_settings (time, weather, game rules, difficulty), mc_structure (save and load structures), mc_ticking_area.

mc_query_target parses the JSON that querytarget returns. It is the way to find where the player or the Agent is before building.

mc_compare_regions compares two regions with a single testforblocks. Its masked mode ignores air in the source, which is how you check that a student's build contains everything it should, whatever else is around it.

mc_analyze_symmetry checks whether a region is mirror-symmetric and, when it is not, points to the cells that differ. It works by saving the region, loading a mirrored copy into a scratch area, comparing, and restoring the scratch area afterwards. The scratch area may not overlap the region being analyzed; this is checked before any command is sent. If backing up the scratch area fails, nothing is placed.

mc_structure saves to memory by default (gone when the game closes). Use saveMode: "disk" only when the user asks to keep a structure; it writes into the world folder. The game has no command that lists saved structures, so mc_status reports the names saved during the current session.

Player and feedback (7)

mc_teleport, mc_give, mc_gamemode, mc_effect, mc_player_action (kill, clear, xp, ability), mc_message (say, tell, title, subtitle, action bar), mc_feedback (sounds and particles).

Building (4)

ToolPurpose
mc_build_previewPlan only: block count, bounding box, number of /fill batches
mc_build_shape24 geometric shapes; most support hollow
mc_blueprint_previewPreview a block-by-block blueprint
mc_build_blueprintAny shape from a list of "coordinate → block"; identical blocks are merged
GroupShapes
Solidsbox, sphere, ellipsoid, cylinder, cone, pyramid, prism
Lines and surfacesline, curve (smooth curve), disk, tube (cylinder along any direction)
Building partswedge (single slope), roof (gable or hip), arch, stairs, spiralStairs, polywall (polyline wall)
Terrain and pathsheightfield (rolling ground), ribbon (road or bridge deck)
Decorativetorus, helix, cross, star, revolution (solid of revolution)

With 24 shapes, the real risk is the AI picking the wrong one: a wrong pick does not fail, it builds something plausible but wrong. The tool description is therefore organized by what you want to build, with the most commonly confused pairs spelled out:

You wantUseNot
Slanted pillars, beams, pipestubecylinder (axis-aligned only)
Walls with sharp cornerspolywallcurve (rounds the corners)
A roof with a ridgeroofwedge (one slope only)
Stairs winding up a towerspiralStairshelix (no treads) or stairs (straight)
Towers or chimneys that tapercone / pyramid with topRadiusstacked boxes
Domes, vases, cooling towersrevolution with a profilea new shape per object
Uneven groundheightfieldmany boxes

A few parameters are easy to misread: the radius of prism and pyramid is the distance from the center to an edge, not to a corner; the ridgeAxis of roof is the direction the ridge runs, not the way the slopes face; heightfield corners are thicknesses in blocks; and arch draws the arch itself, with the opening (width 2 × radius − 1) in the middle.

Events (4)

mc_events_catalog, mc_events_subscribe, mc_events_unsubscribe, mc_events_poll.

Events go into a ring buffer that you read with a cursor. dropped > 0 means polling was too slow and some events were lost. Subscriptions are restored automatically after a reconnect. Known event names include PlayerMessage, BlockPlaced, BlockBroken, ItemAcquired, ItemCrafted, MobKilled, PlayerTravelled, AgentCommand and more (see mc_events_catalog). Events only fire when the thing actually happens: BlockPlaced is sent when a player places a block by hand, not for /setblock or /fill.

Resources (2)

minecraft-edu://connection (live connection state) and minecraft-edu://capabilities (what the bridge can and cannot do).

Connecting and staying connected

All AI sessions on one machine (desktop apps, CLIs, IDEs, parallel tasks) share a background hub that owns port 19131 and the single game connection. Each session's MCP server is a thin proxy to it. The first session that needs the hub starts it; every open session checks in once a minute, so port 19131 stays served while any session is open, and a hub that dies is restarted right away. The hub exits about 10 minutes after the last session and the game are both gone.

  • Switching sessions, models or AI tools does not drop the game connection.
  • /reload all, moving to another world, and going back to the main menu and into a world again do not drop it either during a normal load. At the main menu the connection stays open, but every command answers "Unknown command". The main menu and the world list have no chat bar, so /connect can only be typed inside a world.
  • You only need to type /connect again after restarting Minecraft, or after the hub side closes the connection (the chat shows "Connection closed").
  • You do not need to type /connect while connected. Doing so shows nothing at all, which looks like a hang; typing and commands keep working as usual.
  • mc_run_command can send reload all. For development packs, scripts, behavior pack JSON and custom blocks reload this way. Whether resource packs (textures, language files) also reload this way has differed between the two setups tested, cause unknown: a Windows machine reloaded changed and added language strings and changed item textures, a macOS machine did not reload a changed language file. So the agent works in this order: send reload all, wait until the game is back in the world (send nothing else meanwhile), then check (a titleraw with a translate component shows what the client resolves; look at a texture). Only if the new content is missing does it type /reload all in the game chat itself.
  • A script cannot connect the game: /connect run from a behavior pack script, whether as the player or as a dimension, is accepted but opened no connection in the setups tested, while /connect typed in the chat did. An in-game "connect" button therefore cannot replace typing it; the agent types it instead. While a load hangs, the bridge's 30-second keepalive probe keeps running, and after three unanswered probes in a row the bridge closes the connection.
  • If an old BlockHand without hub support already holds 19131, new sessions fall back to standalone mode on a random port; use the address mc_status reports. Standalone mode never takes 19131 itself.

Manual fallback, for a player working without an agent that can send keys: to reconnect quickly, press T in the game, press ↑ to recall the last command, then Enter.

Hands-off operation

BlockHand is built so that an agent can keep working without stopping to ask the player to click, type or confirm things it can do itself. Every pause costs the player's time, and a tool people have to babysit does not get used.

The agent does these itself, without asking first:

  • /reload all after changing a pack: send reload all with mc_run_command, wait until the game is back in the world, check that the new content arrived, and only if a resource pack change is missing, type /reload all in the game chat.
  • Leaving the world and entering it again.
  • Restarting Minecraft when a reload hangs on the loading screen (see Troubleshooting), or before a reload when the game process has been open for hours. The world was saved when the reload began.
  • Typing the connectCommand that mc_status reports whenever the game is not connected (check connected first; the port is not always 19131).

Only the player does:

  • Signing in. Passwords are never typed or read by the agent. If the game comes back already signed in, nothing is needed from the player at all.

Before acting, the agent checks:

  • That nobody is in the middle of playing. Look at the screen and compare mc_query_target position and rotation twice a few seconds apart; if either changed, the player is playing, so wait instead of interrupting. No change only means no movement was seen (a player in their inventory or crafting stands still too), so it is not permission by itself: reload when the person asked for it or is working with the agent right now, and ask when unsure.
  • That the right world is selected before pressing Play: never enter or test in a world that is not the one being worked on.

How it reaches the game window. BlockHand itself only talks to the game over the WebSocket. Typing in chat, picking a world and restarting the game go through the AI client's own desktop automation. Work in this order, and keep the person at the computer in control of their screen:

  1. Background. Game commands go through BlockHand. Keys for the chat bar and menus go through a tool that delivers them to the game window without bringing it forward.
  2. Foreground, only for the one step the background cannot do. Before taking the screen, tell the person which step it is, which background method was tried or checked, and what blocked it (if you cannot name all three, you do not need the foreground). Give focus back right after.
  3. The player, only for what an agent cannot do, such as signing in.

When unsure, move up this list, not down: losing the screen for a few seconds costs the person less than being interrupted to type a command themselves.

Practical notes from Windows:

  • This package ships a background key tool for Windows, blockhand-keys (npx -p @gjlmotea/blockhand-mcp blockhand-keys --help, or node scripts/game-keys.mjs --help in a source checkout). It posts keyboard messages to the game window with Win32 PostMessage (WM_KEYDOWN, WM_KEYUP, WM_CHAR), which never changes focus, and it sends no mouse input.
    • --probe finds the game window and sends nothing. With several games open, pass --pid.
    • --open-chat presses T; take a screenshot to confirm the chat bar opened, then --send "/reload all" types into it and presses Enter. --chat does both at once; use it only when the game shows no screen or menu.
    • --keys escape, --keys down,return, --keys shift+tab and so on drive the menus.
    • It prints focus_unchanged=True when the foreground window did not change. Its output says what was queued, not what the game did, so confirm on screen or through BlockHand. A second call while one is sending gets ERROR=busy; that lock covers one call, so between calls (open the chat bar, screenshot, send) another agent could still type. Let only one agent drive the game screen at a time.
    • It only targets the Education edition: the executable must report the product name Minecraft Education (regular Bedrock runs under the same process name).
  • Keyboard messages sent this way reach the chat bar, the pause menu and the world list while another app keeps the focus. Chat commands, menu navigation with the arrow keys and Enter, leaving the world and entering it again all work this way.
  • Leaving and re-entering a world with keys only: Escape opens the pause menu; Down twice selects the save-and-leave button, then Enter; the confirmation starts on Cancel, so Up, then Enter. On the play screen, Down moves the white frame to the worlds tile, then Enter. In the world list, Tab twice reaches the search box, and Down from there lands on the most recently played world. Enter opens that world's small menu; before pressing Play, check that the date and size shown under the menu belong to the intended world.
  • Mouse buttons posted the same way did not mine blocks in the setup tested, so mining or attacking cannot be done in the background with this method.
  • Git Bash rewrites an argument that starts with / into a file path, so a chat command passed through it arrives as C:/Program Files/Git/reload all; blockhand-keys detects this and refuses. Send chat commands from PowerShell, or set MSYS_NO_PATHCONV=1.

Practical notes from macOS:

  • Chat: press T, wait for the chat bar to appear (the first characters are lost if you type immediately), type, then Enter.
  • World list: mouse clicks on world tiles sent in the background can land on "New world" instead. Use the keyboard: type the world's name into the search box so only that world remains, press the right arrow to select it, Enter for its menu, Enter again for Play.
  • Restart: osascript -e 'tell application id "com.microsoft.minecraft-edu" to quit', then open -g -j -b com.microsoft.minecraft-edu starts it again in the background.
  • Right-click and attack clicks sent in the background are not received by the game, so entity interactions cannot be tested by clicking. Give the add-on a /scriptevent probe that calls the same handler the interaction event would (for example, run the before-interact gate and the interact handler for the nearest entity of a type) and another that prints the entity's state without opening it. Then the agent can test interactive mechanics end to end without the player.
  • Photos for checking a build: note the player's position, horizontal rotation and game mode, tell them with tellraw, move them with tp, take the screenshot, then put them back. Pitch cannot be read back, so say beforehand that the view will return level.

How building stays fast

Sending one setblock per block would mean tens of thousands of WebSocket round trips for a medium-sized sphere. BlockHand's pipeline is:

shape parameters → inside() test over the bounding box → set of block coordinates  → merge runs along X → merge rectangles along Z → merge boxes along Y (3-stage greedy)  → split by the 32,768-block /fill limit  → send

The merge is deterministic, and tests pin that the merged batches cover exactly the original set of blocks, no more and no less. Hollow shapes all come from the same "inside test plus shell-neighbor test", so a new shape only needs an inside() function. tests/domain/fill-efficiency.test.ts sets an upper bound on fill commands per block for every shape.

For very large terrain work, compute the coordinates yourself and send many /fill commands with mc_run_commands (200 per call), or write a .mcfunction file and run it with /function. See agents/docs/large-builds.md for the limits involved.

Reading blocks

Minecraft Education has no command that simply returns the block at a position, so reading has built-in limits:

  • mc_test_block is a yes/no question: you have to guess a block ID.
  • mc_read_block does not need a guess. It asks whether the block is air, and when the answer is no, the game's error message names the actual block. The result is the localized display name ("Dirt"), not the block ID (dirt).
  • When the message cannot be parsed, mc_read_block returns an error, never a successful response with block: null. The consumer is an AI, and an AI that sees a successful null will confidently treat the spot as empty and may build over a student's work.
  • mc_verify_reading checks that the parsing still works, with at most two read-only commands. Run it after a game update, after changing the game language (supported: Traditional Chinese, Simplified Chinese, English), or whenever mc_read_block starts failing on blocks you can see. Mutation tests make sure the probe and the parser turn red when the parsing rules are broken.

Reading a whole region block by block would need a behavior pack and the Script API, which BlockHand deliberately avoids so that school computers need no extra installs.

Undo (off by default)

Automatic undo is off by default. On Minecraft Education 1.26.32 (macOS), the native region check that undo sends before the first small build (body.version=25) never got a reply; after that, every command on the connection timed out, including what the player typed in chat, and only restarting Minecraft recovered. This was reproduced three times. Turn it on with MINECRAFT_EDU_UNDO_ENABLED=1 or mc_undo_control with configure enabled=true only if you accept that risk. Design notes: agents/docs/undo/region-undo.md.

When enabled, undo keeps one operation of up to 4,096 blocks, snapshotted in game memory with structure save ... memory (nothing is written to disk). There is no redo. It covers the overworld, absolute integer coordinates and basic static building blocks; unsupported builds are rejected before anything is changed.

Configuration

Everything has a default; no .env file is needed.

VariableDefaultMeaning
MINECRAFT_EDU_WS_HOST127.0.0.1Listen address of the game WebSocket; loopback only by default (see Safety). The hub's control port always listens on 127.0.0.1
MINECRAFT_EDU_WS_PORT19131Port the game connects to. The default uses the shared hub; any other value (such as 0) runs an isolated standalone bridge
MINECRAFT_EDU_HUBauto0 disables the hub (one bridge per session); 1 forces the hub on a custom port
MINECRAFT_EDU_HUB_PORT19132Local control port the sessions use to reach the hub; also the lock that decides which process is the hub
MINECRAFT_EDU_HUB_DIR~/.blockhandFolder for the hub's state file hub.json (holds the hub's access token) and its log hub.log; see Safety
MINECRAFT_EDU_HUB_IDLE_MS600000The hub exits after this long with no session check-ins and no game connection
MINECRAFT_EDU_HUB_ATTACH_MS8000How long a session waits for a hub it has just started to answer (500–60,000 ms); if the hub does not answer in time, the session runs a standalone bridge on a random port
MINECRAFT_EDU_CONNECT_NOTICEonShow the green "✔ BlockHand connected" line in chat, in the game language (detected with one read-only time query daytime first); 0 turns it off
MINECRAFT_EDU_WS_PORT_FALLBACK1Pick a free port when the preferred one is taken; 0 fails instead
MINECRAFT_EDU_ENCRYPTIONonWhen the game connects, try the WebSocket encryption handshake; if it is not negotiated, the connection continues in plaintext. 0 skips the handshake
MINECRAFT_EDU_COMMAND_TIMEOUT_MS10000How long to wait for the game to answer one command
MINECRAFT_EDU_KEEPALIVE_INTERVAL_MS30000Interval of the idle keepalive probe (time query daytime); three unanswered probes in a row close the connection
MINECRAFT_EDU_EVENT_BUFFER500Event ring buffer size
MINECRAFT_EDU_MAX_BUILD_BLOCKS40000000Maximum blocks per build; non-solid shapes are also capped at an 8,000,000-block scan volume
MINECRAFT_EDU_UNDO_ENABLED01 turns on automatic single-step undo (see the warning above)
MINECRAFT_EDU_UNDO_MAX_BLOCKS4096Undo budget, 1–32,768 blocks, in at most 64 regions
MINECRAFT_EDU_STEP_DELAY_MS100Default delay between Agent program steps
MINECRAFT_EDU_DEBUG_FRAMESunset1 prints every raw frame from the game to stderr

Safety

  • By default the game WebSocket listens on 127.0.0.1 only. MINECRAFT_EDU_WS_HOST changes that address. The game port does not authenticate connections, and a new connection replaces the current one, so any other address lets every machine that can reach it connect in place of the game. The hub's control port (MINECRAFT_EDU_HUB_PORT, 19132 by default) always listens on 127.0.0.1. BlockHand itself makes no connections to the internet.
  • The shared hub keeps two files in ~/.blockhand (or MINECRAFT_EDU_HUB_DIR). When the hub is off (MINECRAFT_EDU_HUB=0, or a custom MINECRAFT_EDU_WS_PORT without MINECRAFT_EDU_HUB=1), neither file is written.
    • hub.json holds the hub's process ID, ports, build ID, start time and a random access token. The hub creates a new token each time it starts and removes the file when it shuts down. Every request to the control port must present the token as a bearer token; sessions read it from this file to reach the hub. The folder is created with mode 0700 and the file with mode 0600. Node.js cannot set owner/group/other permissions on Windows, so these modes only take effect on macOS and Linux.
    • hub.log is the hub's timestamped log. When a new hub starts and the log is larger than 1 MiB, it is renamed to hub.log.1. With MINECRAFT_EDU_DEBUG_FRAMES=1, every raw frame from the game is logged there too.
  • Apart from those files, the server writes nothing on the host. mc_structure with saveMode: "disk" makes the game write a structure into its world folder; the tool reply says where.
  • No accounts or credentials for any online service are involved; the hub token only guards the local control port.
  • mc_run_command accepts slash commands, which only act inside the local game world. Its gate is structural rather than a keyword blocklist:
    1. One line only. Newlines and NUL are rejected, so one request cannot become two commands.
    2. Commands that would cut or redirect the bridge are refused: wsserver, connect and closewebsocket, including when wrapped in execute.
    3. Everything else is tagged read-only, world-write or wide-effect, so the MCP host can ask for confirmation based on the tool annotations.
  • Block IDs, selectors and state strings that go into a command line are checked against allow-list patterns first, so spaces cannot smuggle in extra arguments.
  • On a shared hub, only one AI session can change the world at a time. A second session's write tool is refused immediately with a clear message; read-only tools are not affected.

Troubleshooting

The player says chat stopped responding. Do not restart the game first. Check, in order:

  1. What the game screen shows (in a world, main menu, or a loading screen).
  2. mc_status: commandState: "timed-out" means the bridge's own commands are not being answered either.
  3. Subscribe to PlayerMessage and ask the player to type a line. Player chat produces a type: "chat" event. Not receiving one is not proof by itself, because a subscription is not confirmed by the game; compare with the screen.
  4. The last lines of ~/.blockhand/hub.log (every line is timestamped, rejected handshakes are logged too).

When a built-in command such as time answers "Unknown command", the tools add a hint: the game is most likely not in a world.

A reload hangs on the loading screen. In a world with development packs, /reload all (from chat or from the bridge) is a full rejoin: the game saves the world, returns to the menu and loads the world again, and camera settings are cleared. A fresh game process does this in under 10 seconds; one that has been open for hours takes 30–45 seconds, and the progress bar pauses around 25% for a while. On macOS 1.26.x it has also stopped for good at 25% or 60% (four times, each after the same game process had been open for an hour or more and had reloaded several times).

  • While it hangs, the world has in fact loaded: a process sample shows the server and the client world ticking normally while the main thread draws the loading screen. It is waiting for a signal that does not come. Escape and closing the bridge connection do not help. Once, a bar stopped at 50% did enter the world by itself after about 3 minutes.
  • Treat a bar that has not moved for about 90 seconds as stuck. Take a sample first if you want evidence (sample <pid> 5 -file <file> on macOS); waiting one or two more minutes before restarting costs little.
  • Recovery: quit Minecraft and start it again; the agent does this itself without asking (see Hands-off operation). The world was saved when the reload began. On macOS, osascript -e 'tell application id "com.microsoft.minecraft-edu" to quit' ends it within a second (it may still print "User canceled"; check that the process is gone), and open -g -j -b com.microsoft.minecraft-edu starts it again without taking the screen. Then sign in, enter the world and type /connect again.
  • Do not send bridge commands while a reload is loading; they time out. Restarting a game that has been open for a long time before a reload makes a hang less likely.

A reload ends on "Couldn't connect to the world … Invalid tenant ID". The Education sign-in has expired (seen on macOS 1.26.x from about 3.5 hours after signing in). Pressing OK saves the world and returns to the menu, but starting any world from the menu shows the same error. Only a restart and a fresh sign-in fix it: quit and start Minecraft as above, the player signs in, then enter the world and type /connect again. In long sessions, do the important checks first, or restart before a reload when the game has been signed in for several hours.

mc_status shows a port other than 19131. Another process holds 19131. Find it with lsof -nP -iTCP:19131 -sTCP:LISTEN (macOS) and check whether the hub is running with ls ~/.blockhand.

Windows, Microsoft Store (UWP) version. Windows app isolation blocks loopback connections. Grant an exemption with CheckNetIsolation LoopbackExempt.

A large build gets cut off. MCP clients usually time out requests after about 60 seconds, while the tool keeps sending fills. Check fillBatches with mc_build_preview first and split large builds.

Known limitations

  • Text from the game stays in the game's language. Tool descriptions, server instructions and error messages are in English, but what the game itself returns (statusMessage, and the block names from mc_read_block) comes back in the game language.
  • The world must have Cheats on; otherwise the game rejects every command.
  • The Agent exists only in Education Edition.
  • Event names and the agent subcommands are not formally documented by Mojang; they come from public observation and may change with game updates. mc_events_subscribe accepts names outside the known list but marks them unverified.
  • @s does not always resolve for commands sent over WebSocket, so mc_query_target defaults to @p.
  • Commands sent over WebSocket are parsed with an older command version: execute as @e … at @s run … is a syntax error, use the legacy form execute @e[...] ~ ~ ~ <command>; in Education 1.26.x summon also rejects the rotation arguments, so summon first and turn the entity with tp. Add-on scripts calling runCommand are a different path; prefer the script API there instead of relying on either syntax.
  • Some responses arrive with a request ID that matches no request. When exactly one request is pending and no timeout has happened on the connection, the bridge may attribute the response by inference and logs it; after any timeout it only accepts exact matches. Modifying commands are never resent automatically.
  • Commands are sent one at a time with a queue of at most 64; anything beyond that is refused with command-queue-full, and queued commands that outlive their own timeout are dropped and reported as not sent.
  • After rebuilding, the running hub keeps the old version until it restarts; a hub restart drops the game connection.

Development

bash
corepack pnpm run verify   # typecheck, tests, build, stdio smoke, shared-hub smokecorepack pnpm run live     # end-to-end check against a running game (prints the /connect to type)

live walks through connect, read player position, chat, set time, summon the Agent, sense, walk an L-shaped path, preview and build a hollow glass sphere, verify the blocks, merge a blueprint, receive events, test the command gate and clean up. Add --keep to node scripts/live-check.mjs to keep the demo build.

src/  domain/          pure logic, no MCP, ws or Node dependencies    commands.ts            slash command builders and injection allow-lists    command-policy.ts      structural gate for raw commands    build/shapes.ts        the 24 shapes: inside() plus shell-neighbor test    build/fill-planner.ts  3-stage greedy merge and batch splitting    build/undo-plan.ts     undo regions, budgets and native region checks  adapters/ws-minecraft-connection.ts   WebSocket server, request matching, events, reconnects  application/     services: Agent programs, querytarget parsing, building, undo  hub/             shared hub, session proxy, cross-session write lock  server/          MCP server, schemas and the tools  composition.ts   wiring; accepts a fake connection for tests  index.ts         stdio entry point

The domain layer knows nothing about WebSockets, so the whole MCP tool pipeline is tested with in-memory fakes, without a running game.

License and trademarks

MIT.

NOT AN OFFICIAL MINECRAFT PRODUCT. NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT. Minecraft and Minecraft Education are trademarks of Mojang Studios and Microsoft. BlockHand is an independent open-source project.

來源:README.md,提交 8c8ec83

工具

0
SourceWeft 尚未在沙箱中啟動過該軟體包,因此其工具未知。

版本歷史

2
  1. v0.1.1最新Oct 19, 2026
  2. v0.1.0Oct 18, 2026

評分

已滿足適用檢查項的 50%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分

    請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。

  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分