Skip to main content
Glama

pm-minecraft

一个为 MCP 客户端提供的自包含 Minecraft 生存模式主体。

它运行 Mineflayer、Prismarine Viewer、一个本地 Web UI 和一个 Streamable HTTP MCP 服务器。

它不包含代理、模型或认知运行时。只有一些最简指令,告诉你所选的代理如何通过 MCP 使用它、查看截图,以及编写可通过 MCP 执行的自定义 TypeScript 脚本。

非常感谢 https://github.com/minedojo/voyager 和 https://github.com/Mega-Gorilla/Discovery :3

这是我这边正在进行的一项工作的一部分,目的是打造一个有趣的认知架构 AI 伴侣,可以和你一起玩 Minecraft。它也可以独立使用 ^_^

设置

要求:Windows PowerShell、Node.js 20+、通过 py 使用的 Python 3.12,以及一个可达的 Minecraft Java 1.19.x 服务器,角色处于生存模式。

Set-Location C:\workspace\pm-minecraft-mcp
.\setup.ps1

设置遵循共享的 PM 工作流:它使用 uv 创建此仓库的 Python 3.12 .venv,同步其锁文件,并安装锁定的 Node 包。scripts/setup.ps1 保留为兼容性包装脚本。

如果它不工作,告诉你的编码代理去修复它。

Related MCP server: awesome-mineflayer-mcp

Minecraft

我从 https://github.com/Mega-Gorilla/Discovery 偷来了这个设置。

我从未手动修改过 Minecraft,对我有效的方法是:

  • 下载 Prism

  • 安装 1.19.4

  • 安装 Fabric Loader 0.19.3

  • 通过 Prism 安装这些模组:

    • Fabric API

    • CompleteConfig

    • Mod Menu

    • Multiplayer Server Pause (Forge)

    • wenhao 的 item-pickup-range (/setPickupRange 5)

  • 创建生存世界,开启作弊,和平模式

  • 进入并"对局域网开放",端口 12345

创建并启动一个角色

.\scripts\init_character.ps1 `
  -Name Floppa `
  -AgentRoot C:/Temp/Floppa `
  -ArtifactRoot C:/Temp/Floppa/artifacts/minecraft

.\scripts\start_minecraft_mcp.ps1 `
  -Name Floppa `
  -MinecraftHost 127.0.0.1 `
  -MinecraftPort 12345 `
  -AgentRoot C:/Temp/Floppa `
  -ArtifactRoot C:/Temp/Floppa/artifacts/minecraft

初始化器会创建代理工作区、memory/minecraft/、drafts/、skills/、lib/minecraft.ts 和 .mcp.json。启动器会打印本地 Web UI、Prismarine viewer 和 MCP URL。对于多个角色,请使用唯一的 -WebPort、-ViewerPort 和 -McpPort 值。

每个 deploy/drafts/*.ts 示例都会被复制到工作区的 drafts/ 中,并列入其 AGENTS.md。它们可以通过 minecraft_execute_typescript 原样运行,因此代理可以直接执行其中一个,或者将其守卫与验证模式复制到新的草稿中。向 deploy/drafts/ 添加一个示例,即可让它随每个新角色一起发布。

代理在编写新行为之前可以调用 minecraft_list_capabilities。如果没有合适的能力,代理会根据通用主体动作编写一个 TypeScript 草稿。代理使用确定性的后置条件运行该草稿。成功运行后,minecraft_promote_skill 会将草稿复制到 skills/ 中。提升记录包含源哈希、执行 ID 和后置条件。

实体观察包含稳定的运行时 ID,只要每个实体保持加载状态。通用的 attack_entity 动作会对观察到的 ID 执行一次普通的生存攻击。对于击杀目标,代理必须验证生存结果,例如物品栏增加。一个技能可以将观察、移动、装备、攻击和验证组合成诸如狩猎之类的行为。

停止一个实例:

.\scripts\stop_minecraft_mcp.ps1 -ArtifactRoot C:/Temp/Floppa/artifacts/minecraft

然后从工作区使用它:

Set-Location C:/Temp/Floppa
codex

Codex 会读取 .mcp.json。提示它使用 minecraft 服务器;状态日志和截图位于 ./artifacts/minecraft 下。

感知与查看器模式

minecraft_find_block 默认使用 require_visible: true。这是正常的生存设置:它只返回从角色头部有畅通射线的方块。当代理无法看到目标时,它必须探索、移动到更好的视角,或使用不同的观察方式。对于远距离规划,设置 require_visible: false;结果只是已加载世界中的一个位置,在挖掘之前仍然必须到达并目视验证。

磁盘日志记录

所有内容都写入角色的工件根目录(artifacts/minecraft/)下:

  • states/ — 每个快照一个原始完整状态文件(<timestamp>-mcstate-<id>.yaml)。每个状态只存储该状态中首次出现的聊天消息,因此每条聊天消息在整个树中恰好存在一次;按顺序遍历文件即可重建对话记录。每个状态都链接到其截图;它从不包含图像字节或重复的截图元数据。current_state.yaml 是一个指针文件,只包含最近状态的相对路径。

  • screenshots/ — 图片唯一存放的地方(.png 加上每帧一个小的元数据伴生文件)。状态和动作只链接到这些文件。

  • actions/ — 每个 MCP 工具调用一个扁平的 yaml 文件,命名为 <timestamp>_<tool>.yaml,实时写入(调用开始时立即出现一个包含工具和输入的开始文件,前后状态 + 截图链接在快照发生时被追加,原始美化打印的工具输出、持续时间和任何异常则落在最终重写中)。字段:tool、tool_input、tool_output(均为美化 JSON 块标量)、四个链接 before_state_path / before_screenshot_path / after_state_path / after_screenshot_path(当工具未产生状态时为空,对于像 minecraft_observe 这样只产生一个状态的工具则仅包含 before),以及查找头,如技能的 execution_id / skill_path。成功或失败直接从 tool_output 中的返回数据读取;异常落在 error: 块中。

  • mcp-server.log — 每个捕获的主体/网络错误和每个未处理的异常(带回溯)都记录在这里。

工具结果返回相同的链接(beforeStatePath / afterStatePath / beforeScreenshotPath / afterScreenshotPath),而不是内联整个状态,因此模型在需要细节时跟随文件。

截图会被捕获并写入 artifacts/minecraft/screenshots,针对每个状态 — 每次动作前后、每次 minecraft_observe 调用时 — 无论 include_image 如何,只要服务器以启用图像捕获的方式启动(默认;使用 --no-images 禁用)。这为后续分析提供了完整、无缝的磁盘视觉历史,即使代理从未查看过的状态也是如此。

include_image 只控制像素字节是否也附加到该特定工具调用的响应中,以便代理现在就能看到它们;minecraft_observe 默认 include_image=true(所有其他工具默认 include_image=false,以保持常规动作在上下文中成本低廉)。向 minecraft_observe 传递 include_image=false 可在只需要状态时跳过将图像放入响应 — 无论哪种方式,截图仍然会被捕获并保存到磁盘。请求但未能捕获的截图(查看器/机器人未就绪、未找到受支持的浏览器)会报告为 screenshot: {"error": ..., "message": ...},与 screenshot: null(通过 --no-images 在服务器范围内禁用图像捕获)不同。

导航(仅步行)

minecraft_walk_to 只步行。它可以爬上 1 格台阶并走下 1 格,但不会挖掘、放置脚手架、搭柱、跑酷或开门。它瞄准水平位置(GoalNearXZ,因此地形高度自动选择),使用以起点为中心、范围为 chunk_limit 个区块(默认 3,受服务器配置的最大值限制)的静态目标。如果目标在该范围之外、附近没有可站立的底面、或没有步行可达的路径,调用会快速失败,而不是原地等待。

tolerance 默认为 1.5。搜索 A* 预算(walkSearchTimeoutMs,默认 1000)限制了寻路在因"靠近一点"消息而失败之前可以花费的时间。

隧道挖掘与远距离导航

  • minecraft_mine_block 通常需要头部视线,这在 1 格宽的竖井内对相邻的脚部高度方块是不可能的。现在,对于 --mine-visibility-ignore-distance 个方块(默认 3,向启动脚本传递 -MineVisibilityIgnoreDistance)内的目标,它会跳过该门槛,因此你可以从 1 格宽的隧道中直线向前挖掘。

  • minecraft_walk_to 接受最大为 --max-chunk-limit(默认 8)的 chunk_limit。更大的请求会被拒绝,并返回 error: requested chunk limit (N) greater than allowed (M)。

  • 当手持物品不是可放置方块时,minecraft_pillar_up 会报告明确的 pillar_up_needs_placeable_block 错误,并说明必须先清理落点头部空间;dig_up 会逐跳清理头部空间。

  • 随每个角色发布的草稿(自动部署到 drafts/):

    • dig_staircase(height, distance, stop) — 可步行的 2 格高下行坡道。

    • clear_room(width, depth, height) — 将 1 格宽的隧道扩展为房间。

    • dig_up(targetY) / descend_to_depth(targetY, stopOnOre) — 危险安全的单跳上升/下降,在挖掘前检查熔岩/水。

    • tunnel_forward / tunnel_iron / branch_mine_safe_iron — 隧道挖掘与矿石开采,全部有危险防护(在挖入水/熔岩前停止)。

    • place_crafting_table / place_block / climb_pillar / find_village(远距离巡逻,看到村民时报告)。

暂停的运行、超时与防停滞守卫

  • minecraft_stop 会停止活动的 Mineflayer 命令并终止任何正在运行的 TypeScript 技能进程(两者都终止)。minecraft_kill_command 只停止当前的物理命令;minecraft_kill_skill 只终止正在运行的技能进程。

  • 协作取消:技能在每次 API 调用/睡眠时检查终止信号标记,并在被停止时干净地跳出(SkillCancelledError),因此 minecraft_stop/kill_skill(以及客户端断开连接)能快速停止技能并让它写入结果 — 只有在忽略标记时运行器才会被硬性终止。

  • 可配置的技能超时:minecraft_set_skill_timeout(seconds)(1..3600)设置 minecraft_execute_typescript 和 minecraft_collect_blocks 的最大持续时间(默认 90;启动时默认值通过 -SkillTimeoutSeconds / --skill-timeout-seconds 设置)。长时间运行的技能在单独的子进程中运行,并在该超时时间由服务器端终止。

  • 匹配你的客户端窗口:代理的 .mcp.json requestTimeoutMs(角色默认 200000)必须保持在服务器技能超时之上,否则长时间技能会在完成前被客户端截断。经验法则:将 minecraft_set_skill_timeout 设置为 requestTimeoutMs - 10s。

  • 重复无收益的断路器默认禁用。它是旧版较弱模型的遗留物,这些模型会循环重试相同的无收益操作;它绑定到单个"相关物品",错误地阻止了无关的技能操作。当你明确需要时,可以通过 --enable-anti-stall-guard MCP 参数(启动脚本上的 -EnableAntiStallGuard)重新启用它。

状态透明性

  • 每个状态(完整和增量)始终携带玩家 position、health、food 和 foodSaturation,每个结果始终报告当前的 heldItem,因此代理永远不必从差异中推断自己的生命值或手持工具。

  • minecraft_collect_blocks 会预先装备能收获目标方块的最便宜工具(而不是在运行中途因 unharvestable 拒绝而死亡),并且主体不再交换手持物品,除非 collect_blocks 需要不同的工具。

来自实际测试的提示(代理人体工程学)

这些来自与编码代理的真实游戏会话,值得编码到你的代理的 AGENTS.md 或技能提示中:

  • 坐标在包装工具上是扁平的:minecraft_walk_to(x,y,z,…) / minecraft_mine_block(x,y,z,…) 接受独立的数字,而不是 position/block 对象。对于嵌套的动作模式,请使用 minecraft_call 配合 minecraft_info 中的形状(例如 {"action":"place_block","parameters":{"referenceBlock":{…}}})。

  • 先探测再挖掘:在挖掘隧道前,先读取 hazards(水/岩浆)并 inspect 下一个格子。运输草稿会在遇到危险时停止;直接对水/岩浆执行 mine_block 会让机器人搁浅。

  • 手持工具漂移:一次攀爬式的 mine_block 或 pillar_up 可能会让手中 留下一个可放置方块(泥土/圆石)而不是工具。在任何攀爬式挖掘后重新装备并 检查;工具也会因耐久度而损坏,所以请备一把备用镐。

  • 挖宽,不要挖 1 格宽:1 格宽的隧道只能暴露正面,会错过侧壁的矿石。 使用 clear_room/branch_mine_safe_iron(3 格宽)来暴露矿石,并将 find_block 的视线(防透视)结果视为“去看看 / 挖开以揭示它”。

  • 长途地面旅行可行,借助动态区块流式加载行走;将每次 walk_to 保持在 你的客户端窗口内,它能覆盖比单区块跳跃远得多的距离。

  • 超时:将 minecraft_set_skill_timeout 保持在 requestTimeoutMs - 10s, 这样长技能能完成而不是被截断。minecraft_info 会报告当前值;每当文档 有出入时重新读取它。

  • 优先选择许多小的可逆技能,而不是一个巨大的不可逆技能;每个都需要 确定性的后置条件。minecraft_observe + minecraft_stop 让你能够跟踪并 停止任何失控的运行。

酷炫内容

这是 WebUI,你可以在这里手动控制角色,或查看编码代理如何使用 MCP。

这是 Codex 描述我的角色皮肤。Prismarine 只渲染默认的 Steve :(

开发

npm test
npm run build
.\.venv\Scripts\python.exe -m compileall mcp

以编程方式使用(pip install)

pm-minecraft 可以直接嵌入到另一个 Python 项目中——例如一个在守护线程中 保持 Minecraft 角色存活的认知架构。没有 ps1 脚本,没有对启动器的 subprocess.Popen,也没有任何分离的子进程:每个 Node 进程都通过一个 stdin 生命周期管道附加到其 Python 父进程。当父进程死亡——无论是优雅 退出还是被强制杀死——操作系统都会关闭管道,Node 看到 EOF,然后干净地 关闭。在 Windows 和 Linux 上语义相同。

安装

pip install git+https://github.com/flamingrickpat/pm-minecraft.git

目标机器的要求:

  • Python 3.12,以及 PATH 上的 Node.js 20+(node 和 npm)。

  • 角色首次在 Python 环境中启动时,该包会一次性将其 Node 依赖树安装到 <venv>/pm-minecraft-runtime/<version>/(在文件锁下运行 npm ci; 一次性操作,需要几分钟)。之后每次启动都是即时的。可以用 pm_minecraft_mcp.ensure_node_runtime() 预热。

  • 一个可达的 Minecraft Java 1.19.x 服务器,角色处于生存模式 (与独立设置相同)。

入口点

一切都是一个类型化配置对象加上设计为在守护线程中运行的阻塞函数:

  • pm_minecraft_mcp.ServerConfig(...) — 所有设置:Minecraft 主机/端口、 用户名、代理主目录、工件根目录、web/查看器/MCP 主机+端口、启动超时、 图像捕获、技能限制、视距。

  • pm_minecraft_mcp.execute_node_main_loop(config) — 运行 Minecraft 身体 (一个 Node 进程)并阻塞直到其退出。

  • pm_minecraft_mcp.execute_python_main_loop(config, manage_body=True) — 运行 MCP 服务器并在其服务期间阻塞。使用默认的 manage_body=True 时, 它还会自行启动并拥有身体(一个线程就足够了);使用 manage_body=False 时,它期望身体由配套的 execute_node_main_loop 线程管理,并等待其就绪。

  • pm_minecraft_mcp.init_character(name, agent_root, artifact_root, ...) — scripts/init_character.ps1 的 Python 移植版:创建代理工作区 (AGENTS.md、.mcp.json、lib/minecraft.ts、drafts/、skills/、 memory/minecraft/)。拒绝非空的代理根目录。

  • pm_minecraft_mcp.check_prerequisites(config) — 快速失败检查,也会在 任何进程生成前自动运行:代理主目录已初始化、Minecraft 服务器可通过 TCP 访问、本地服务端口空闲、node 在 PATH 上。每次失败都会立即抛出带有 具体消息的异常。身体加入后,协商的版本必须是 1.19.x 且游戏模式为生存, 否则入口点会抛出异常。

示例

examples/main.py 在两个守护线程中启动一个角色,并在 Ctrl-D 时关闭:

import threading
from pathlib import Path

from pm_minecraft_mcp import (
    ServerConfig,
    execute_node_main_loop,
    execute_python_main_loop,
    init_character,
)

AGENT_ROOT = Path.home() / "characters" / "Floppa"

if not (AGENT_ROOT / "AGENTS.md").exists():
    init_character(
        name="Floppa",
        agent_root=AGENT_ROOT,
        artifact_root=AGENT_ROOT / "artifacts" / "minecraft",
        minecraft_host="127.0.0.1",
        minecraft_port=12345,
        web_port=3000,
        viewer_port=3007,
        mcp_port=8765,
    )

config = ServerConfig(
    minecraft_host="127.0.0.1",
    minecraft_port=12345,
    username="Floppa",
    agent_home=AGENT_ROOT,
    artifact_root=AGENT_ROOT / "artifacts" / "minecraft",
    web_host="127.0.0.1",
    web_port=3000,
    viewer_port=3007,
    mcp_host="127.0.0.1",
    mcp_port=8765,
    startup_timeout_seconds=90,
    capture_images=True,
    max_skill_characters=50000,
    viewer_scale=1,
    viewer_fov=80,
    view_distance=24,
)

threading.Thread(target=execute_node_main_loop, args=(config,), daemon=True).start()
threading.Thread(
    target=execute_python_main_loop, args=(config,), kwargs={"manage_body": False}, daemon=True
).start()

try:
    while True:
        input()  # Ctrl-D (EOF) ends the process; children follow via stdin EOF
except (EOFError, KeyboardInterrupt):
    pass

单线程变体也可以:一个在 execute_python_main_loop(config) 上的守护线程 同时启动身体和 MCP。

多个角色

每个角色使用一个配置(唯一用户名 + 唯一的 web/查看器/MCP 端口),并为每个 角色提供一对守护线程。Node 运行时在所有同一 Python 环境中的角色之间以 只读方式共享。

代理端行为不变

从 MCP 客户端的角度来看,没有任何变化:相同的工具名称、模式、.mcp.json 布局以及 minecraft_execute_typescript 契约。代理仍然可以将其任意的 TypeScript 草稿写入工作区并针对服务器执行;草稿通过该包的 tsx 运行时运行, 使用角色主目录中的 lib/minecraft.ts。

生命周期保证

  • 身体是一个 Node 进程(没有 npm/tsx 包装进程);技能运行也是每个一个 进程。没有需要追踪的进程树。

  • 子进程永远不会获得 CREATE_NEW_PROCESS_GROUP,也永远不会被 taskkill。关闭时首先使用 stdin-EOF,最后才使用普通的 kill()。

  • 在任何时刻杀死嵌入进程(包括 taskkill /F 或 kill -9)都不会使身体 成为孤儿:生命周期管道会断开,Node 会在几秒钟内退出。

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables controlling a semi-autonomous Minecraft bot via MCP, supporting tasks like movement, combat, farming, and chatting.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    A production-ready MCP server that gives an LLM agent standalone-equivalent control over a Mineflayer Minecraft bot — movement, mining, crafting, inventory, combat, containers, chat, and much more — exposed as 110 strongly-typed tools across 23 groups, with full bot lifecycle management and dual (poll + push) event streaming.
    141 npm
    6
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP-capable AI clients to control a Minecraft bot in a Java world, providing tools for movement, observation, inventory, chat, crafting, mining, and placing.
    4
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to control Mineflayer bots over Streamable HTTP, allowing them to join Minecraft servers, run commands, interact with GUIs, and verify server behavior.
    MIT