Skip to main content
Glama
smile-minecraft

minecraft-dev-mcp

minecraft-dev-mcp

用 Docker 在本機跑一台 Paper 或 Folia 的 Minecraft 測試伺服器(外加選用的 MCC 機器人),再由一個 MCP gateway 讓 AI agent 操作:啟停、換版本、重建世界、 RCON、管理外掛、叫機器人上線測試。容器就是隔離邊界,agent 弄壞的東西只會壞在 容器和伺服器資料夾裡。

這不是正式營運用的伺服器(見「風險與安全」)。這是開源專案(MIT),從第一個 commit 開始就當公開 repo 寫。

平台範圍

  • 只支援 macOS 上的 OrbStack(arm64)。其他平台(Linux、Docker Desktop、 Windows)不列入支援與宣稱,也不在本專案的驗收範圍內。

  • 容器內是 linux/arm64。x64 產物存在但原生執行未驗證。

風險與安全

動手之前先讀完這節:

  1. AI 拿到 RCON 就是管理員權限,可以刪世界、改設定、執行任意伺服器指令。 只在你信任的 agent 設定裡接上這個 MCP。

  2. start_fresh/switch_fresh 會直接刪除世界(<level-name>、 <level-name>_nether、..._the_end),不備份。呼叫時必須帶 confirmFreshWorlds: true,否則拒絕執行。

  3. 預設是離線模式(online-mode=false),區網裡任何人都能冒用玩家名稱登入。 預設只綁 127.0.0.1 就是為了把這個風險關在本機;開放區網前請先改成正版驗證。

  4. 容器可以上網,但碰不到 host 與私有網段:擋掉 host gateway、RFC 1918、 link-local、CGNAT,只有 compose 內部網段和 DNS 例外(macOS/OrbStack 實測)。

  5. token 和密碼只從 .env 注入,任何工具回傳、log、錯誤訊息都不會印出來。 .env 權限必須是 600,scripts/lab up 會檢查。

  6. 同一個伺服器資料夾不要用兩種方式同時啟動(例如 MCP 工具和手動 docker compose 混用)。管理程式用 .lab/RUNNING 標記執行中,up 看到標記 而容器沒跑會拒絕,請用 scripts/lab clear-marker 處理。

需求

快速開始

以下全部在本專案根目錄執行。第一次會從 PaperMC 下載伺服器本體並驗 SHA-256, 需要連網。

cp .env.example .env
npm install

開啟 .env,把 EULA 設成 true,SERVER_DIR 指到你要用的伺服器資料夾 (第一次用可以先指向一個不存在的路徑,init 會建立它)。

建一台乾淨的 Paper 測試伺服器(Folia 把 --type 換成 folia):

scripts/lab init ./test-data/my-server --type paper --version 1.21.11

把 .env 的 SERVER_DIR 設成同一個資料夾,然後一個指令把伺服器與端點帶起來 (server+gateway;MCC_SLOTS=0 時不啟動機器人):

scripts/lab up

up 要等對外端點真的回存活探測(GET /healthz)才返回。保證的只是端點就緒, 不是整棧就緒:依賴管理程式的工具在伺服器容器的控制介面綁定前仍可能短暫失敗, 遇到就重試。等不到(預設 120 秒;LAB_READY_TIMEOUT_MS 以毫秒調整,上限 10 分鐘,行程環境變數優先、其次設定檔;輪詢間隔 LAB_READY_INTERVAL_MS 預設 500 毫秒、介於 10 毫秒與 30 秒之間,來源順序相同)就明確失敗並以非零結束, 容器保持運轉以便檢查。

容器起來之後,伺服器本體還是停止的:init 建出的期望狀態就是已停止, 第一次要手動啟動。在 MCP 用戶端呼叫 start 工具(type/version 不帶, 就用上次的;init 建好的資料夾直接可用),再用 status 看到 RUNNING 才算就緒:

  • 第一次 start 會產生世界,需要幾分鐘;完成時間記在 .lab/state.json 的 worldReadyAt,之後 restart 就快了。

  • 之後啟停一律用 MCP 工具(stop 正常關閉、restart 保留世界重啟), 不要直接下 docker compose,也不要用別的方式啟動同一個資料夾。

  • scripts/lab status:看容器與執行標記狀態。

  • scripts/lab down:停止全部容器。

  • MCP 端點在 http://127.0.0.1:<GATEWAY_PORT>/mcp/server(預設埠 48230, 只綁本機),bearer token 用 .env 的 GATEWAY_TOKEN。

驗證與檢查:

npm test            # 單元測試
npm run lint && npm run typecheck && npm run build
npm run check:public  # 公開前掃描(個人路徑、token 樣式,上方顯示已遮蔽)

scripts/lab init 的完整行為(Paper/Folia 各建一台並啟動到完成載入)有整合測試 覆蓋(tests/integration/init/init.test.mjs);沒設 EULA=true 時 init 會拒絕 且不產生任何檔案。

設定

設定分三層,優先順序:行程環境變數 > .env > compose.yml 內建預設值。

檔案

誰改

內容

.env(gitignore,權限 600)

使用者

平常會調的值,見下表

.env.example

專案

每一項都附說明和保守預設值,可公開

compose.override.yml(gitignore,選用)

使用者

.env 表達不了的結構性調整

.env 主要項目(完整說明見 .env.example):

  • SERVER_DIR:伺服器資料夾(host 路徑)。一次只掛一個;換資料夾先 scripts/lab down,改值,再 scripts/lab up。

  • SERVER_TYPE:paper 或 folia(預設值,工具呼叫可另外指定)。

  • EULA:true 才允許 init 產生 eula.txt 與建立世界。

  • JAVA_BIND/BEDROCK_BIND:預設 127.0.0.1,只綁本機。

  • GATEWAY_PORT:預設 48230,只對本機開放。

  • GATEWAY_TOKEN、SUPERVISOR_TOKEN、MCC_MCP_AUTH_TOKEN:留空的話, scripts/lab up 第一次會自動產生隨機值寫進 .env,不印出來。 其中任一個由行程環境變數提供時,以行程的值為準,不寫回 .env。 只有未定義或空字串才算未提供;純空白視為已提供(與 compose ${VAR:-預設} 語意一致),不再另產生一把不同的值。

  • XMS_MIB/XMX_MIB:堆積大小(預設 1024/2048)。

  • MCC_SLOTS:機器人槽位數,0 表示不啟動(預設)。

  • BOT_NAMES:逗號分隔的機器人名稱,數量要等於 MCC_SLOTS。

  • LAB_MASK_PATHS:容器內要遮蔽的 host 路徑,預設只遮 .env 系列。

  • LAB_SERVER_ALIAS:選用。沒設就不接受工具的 server 參數。

  • LAB_LOCALE:en 或 zh-TW(工具回傳的說明語言,預設 en)。

  • COMPOSE_PROJECT_NAME:compose 專案名(容器與網路名稱的字首,預設 minecraft-dev-mcp)。同時跑多份隔離堆疊時才需要改;改了之後 up/down/status 都要用同一份 .env 操作,否則會管到別的堆疊。

scripts/lab up 啟動前會檢查:.env 權限 600、SERVER_DIR 存在且像一台伺服器 (有 server.properties+plugins/,且有世界或 .lab/initialized)、Docker 可用、埠沒被占用、執行標記一致。任何一項不過就拒絕啟動並說明原因。

MCP 用戶端設定

gateway 是 Streamable HTTP MCP 伺服器,只綁 127.0.0.1,agent 必須跟伺服器在 同一台機器上。兩個端點:/mcp/server(伺服器工具)、/mcp/mcc(機器人工具, MCC_SLOTS=0 時不提供)。工具名稱不帶前綴(例如 status),前綴由用戶端的 key 決定;建議用 minecraft_test_server 和 mcc 兩個 key,組出來的完整名稱就是 minecraft_test_server_status、mcc_slot1_session_status。

認證一律是 Authorization: Bearer <GATEWAY_TOKEN>(.env 的值,不要貼進公開文件)。

Claude Code(已實際連線通過)

版本 2.1.281,以專案目錄的 .mcp.json+批准連上,headers 原樣轉發(服務端見 authOk)。範例(token 換成你 .env 的值):

{
  "mcpServers": {
    "minecraft_test_server": {
      "type": "http",
      "url": "http://127.0.0.1:48230/mcp/server",
      "headers": { "Authorization": "Bearer 換成你的 GATEWAY_TOKEN" }
    },
    "mcc": {
      "type": "http",
      "url": "http://127.0.0.1:48230/mcp/mcc",
      "headers": { "Authorization": "Bearer 換成你的 GATEWAY_TOKEN" }
    }
  }
}

連上後用批准(enabledMcpjsonServers)放行,mcp get 顯示 Connected 即成功。 已知限制:工具完整名稱的組法、Code Mode 逐工具權限、tools/list_changed 不重連 更新都還沒驗(要看到完整工具名稱需實際跑一次 agent);第一次連線、或 MCC 快照更新之後,請重新連線再列工具(gateway 會送 notifications/tools/list_changed, 用戶端不一定會自動更新)。

OpenCode(已實測連上並成功呼叫工具,樣本仍少)

設定檔是專案目錄下的 opencode.json(opencode mcp add 實際寫出的形狀)。 隔離聯調已經實際連上:服務端日誌可見連線與工具數(11 個)、工具呼叫回預期結果, 手動三次成功;自動探針(tests/integration/gateway/probe-clients.mjs)首輪通過。 範例:

{
  "mcp": {
    "servers": {
      "minecraft_test_server": {
        "type": "remote",
        "url": "http://127.0.0.1:48230/mcp/server",
        "headers": { "Authorization": "Bearer 換成你的 GATEWAY_TOKEN" }
      },
      "mcc": {
        "type": "remote",
        "url": "http://127.0.0.1:48230/mcp/mcc",
        "headers": { "Authorization": "Bearer 換成你的 GATEWAY_TOKEN" }
      }
    }
  }
}

已知注意事項:

  • 該用戶端以環境變數 PWD(而非行程工作目錄)解析專案目錄:啟動時的 cwd 與 env.PWD 都要指向專案目錄,否則讀不到 opencode.json、服務端零請求 (先前的失敗根因,已實證)。

  • opencode mcp add --header 必須用 key=value 形式 (Authorization=Bearer …);用 key: value 會被當成本地命令。

  • 以下仍未驗證:headers 能不能用環境變數展開、工具完整名稱組法、 Code Mode 逐工具權限、list_changed 不重連更新;改完設定先假設要重連。

端點與工具一覽

所有工具回傳統一信封:ok、summary、data;失敗多帶機器可判斷的 code 和 具體的 nextAction。schema 一律 strict,不認得的欄位直接拒絕。

/mcp/server(節錄):health、status、versions、download、start、 stop、restart、start_fresh、switch_fresh、rcon、console、 plugins_list、plugin_archive、plugin_restore、plugin_install、 config_read、config_write,以及 MCC_SLOTS > 0 時的 bots_status、 bots_start、bots_stop、bots_restart。

/mcp/mcc:每個 MCC 實例的工具展開成 slot<N>_ 加上去掉上游 mcc_ 前綴的基名 (例如上游 mcc_session_status → slot1_session_status),schema 與結果原封不動。 工具清單來自執行期快照(.lab/mcc/tools.json),所以機器人離線時工具也看得到, 呼叫時回 isError 並附 nextAction;尚無快照時回空清單。

給 agent 的使用規則

  1. plugins/ 可以直接改,但伺服器運轉中不要直接開外掛的資料庫檔案 (SQLite、H2 等)。檔案鎖跨 VM 邊界不可靠,同時開可能把資料庫弄壞; 要查資料就先 stop,或是用 rcon 走外掛自己的指令。

  2. 換了外掛 jar 就要 restart。Folia 不支援熱重載;Paper 的 /reload 也不要用。

  3. 換下來的 jar 用 plugin_archive,不要在 plugins/ 裡留 .backup-* 這類檔案。

  4. 從外部裝外掛用 plugin_install,讓來源記錄進 lock.json。

  5. 伺服器層的設定檔用 config_read/config_write,不要直接編輯; 世界資料夾不要從 host 動。

  6. 啟停一律用 MCP 工具,不要直接下 docker compose,也不要用其他方式啟動 同一個資料夾。

授權

  • 本專案:MIT(見 LICENSE)。

  • Paper/Folia:GPL-3.0。執行時才從 PaperMC 下載,不隨本專案散布。

  • MCC:CDDL-1.0。由使用者 build 時從上游下載;以後若推 build 好的映像檔, 映像檔裡要附 MCC 的授權和來源連結。

  • MCC 固定版本 MCC-2.0-early-access-build-9(prerelease,MCP 為 plugin 形式), 以 digest 鎖定。

效能(F6,同種子同範圍量測)

條件:paper 1.20.1-18、Chunky 1.5.3、種子 mdev-f6、Chunky center 0 0+ radius 400、XMS 1024/XMX 2048、view-distance 5、simulation-distance 3、 0 玩家、開機後靜置 15 秒。host 用 Homebrew Java 25,容器用產品映像內建 Java 25。 兩邊各跑一次(原始記錄見 docs/FINDINGS.md 第 13.6 節)。

項目

host 直跑

容器(產品映像)

冷啟動到完成載入

約 12 秒

約 15 秒

Chunky 預生成(radius 400)

約 35 秒

約 72 秒

預生成後 TPS(1m/5m/15m)

20.0/20.0/20.0

20.0/20.0/20.0

限制(以下如實列出,沒有隱瞞):

  • MSPT 未驗證:spark 的 bukkit 構件在核准的登錄拿不到可用版本, 不以不明二進位代替。

  • 單次量測、同一台機器先後跑(host 先、容器後);行程排程與 OrbStack 檔案系統 快取可能影響數字。時間精度只到秒級(狀態輪詢判定)。

  • 玩家在線、更大預生成範圍、大型外掛組合都沒量過。

已知限制與未驗證項目

以下都沒有當成通過,後續階段補驗時才會拿掉:

  • H2 資料庫(只驗過 SQLite+區域檔類比)。

  • 外接磁碟使用中拔除。

  • Docker/整台主機層級的重啟演練(依決定不主動演練,以免連帶重啟機器上其他容器)。

  • 崩潰+容器重啟的真實容器層級組合。

  • 每刻平均時間(MSPT,見上節)。

  • 雙用戶端的工具完整名稱組法、headers 環境變數展開、逐工具權限、 list_changed 不重連更新(OpenCode 連線與工具呼叫本身已通過,樣本仍少)。 (平台相關:只支援 macOS/OrbStack,見「平台範圍」,不在此列。)

文件

  • 企劃書:docs/PLAN.md(第 2 節決策已定案,第 12 節是待問事項)。

  • 架構:docs/ARCHITECTURE.md。

  • 實測收斂與證據:docs/FINDINGS.md(原始證據在 docs/findings/)。

  • 公開前檢查清單:docs/PUBLISH_CHECKLIST.md。

  • 接手實作前先讀 AGENTS.md。

Related MCP Connectors