# minecraft-mcp MCP (Model Context Protocol) servers for AI-assisted Minecraft development. Lets tools like Claude Code interact directly with a running Minecraft server and client — viewing logs, running commands, installing plugins, taking screenshots, controlling the player, and calling arbitrary Bukkit/Paper/Minecraft API methods via reflection. --- ## Repository layout ``` minecraft-mcp/ ├── packages/ │ ├── shared/ TypeScript protocol types + WebSocket connection class │ ├── mcp-server-paper/ MCP server (stdio) ↔ Paper/Spigot plugin │ └── mcp-server-fabric/ MCP server (stdio) ↔ Fabric client mod └── minecraft/ ├── paper-plugin/ Paper/Spigot plugin (Java 21, Gradle) └── fabric-mod/ Fabric client mod for MC 26.1.2 (Java 25, Gradle 9.4, fabric-loom 1.16) ``` --- ## Architecture ``` ┌──────────────────────┐ stdio ┌────────────────────────────┐ │ Claude Code / LLM │ ◄──────────────────► │ mcp-server-paper (Node) │ └──────────────────────┘ └──────────┬─────────────────┘ │ WebSocket ┌──────────▼─────────────────┐ │ Paper plugin (Java) │ │ ws://localhost:25575 │ └────────────────────────────┘ ┌──────────────────────┐ stdio ┌────────────────────────────┐ │ Claude Code / LLM │ ◄──────────────────► │ mcp-server-fabric (Node) │ └──────────────────────┘ └──────────┬─────────────────┘ │ WebSocket ┌──────────▼─────────────────┐ │ Fabric mod (Java) │ │ ws://localhost:25576 │ └────────────────────────────┘ ``` The Minecraft side (plugin / mod) runs a local **WebSocket server**. The Node.js MCP servers connect to it as clients. Claude Code (or any MCP host) runs the Node.js processes and talks to them over stdio. --- ## Quick start ### Prerequisites | Tool | Version | |------|---------| | Node.js | ≥ 20 | | tsx | any (`npm install -g tsx`) | | Java | 21 (Paper plugin) / 25 (Fabric mod – MC 26.1.2 ships Java 25 bytecode) | | Gradle | 8.8+ for the Paper plugin wrapper. The Fabric mod has its own checked-in wrapper pinned to 9.4. | ### 1. Install Node packages ```bash npm install ``` ### 2. Build the Paper plugin ```bash cd minecraft/paper-plugin gradle wrapper --gradle-version 8.8 # once only ./gradlew shadowJar # Output: build/libs/minecraft-mcp-paper-0.1.0.jar ``` Copy the jar into your Paper server's `plugins/` directory and start the server. ### 3. Build the Fabric mod ```bash cd minecraft/fabric-mod ./gradlew build # uses the bundled wrapper (Gradle 9.4) – needs Java 25 on JAVA_HOME # Output: build/libs/minecraft-mcp-fabric-0.1.0.jar ``` Copy the jar into your Fabric client's `mods/` directory and launch Minecraft. ### 4. Configure Claude Code (`.claude/mcp.json`) ```json { "mcpServers": { "minecraft-paper": { "command": "node", "args": ["--import", "tsx/esm", "/path/to/packages/mcp-server-paper/src/index.ts"], "env": { "PAPER_WS_URL": "ws://localhost:25575" } }, "minecraft-fabric": { "command": "node", "args": ["--import", "tsx/esm", "/path/to/packages/mcp-server-fabric/src/index.ts"], "env": { "FABRIC_WS_URL": "ws://localhost:25576" } } } } ``` --- ## Available tools ### Paper / Spigot server (`mcp-server-paper`) | Tool | Description | |------|-------------| | `get_server_logs` | Tail `logs/latest.log`, optional text filter | | `subscribe_server_logs` | Push future log lines to the MCP client | | `run_console_command` | Run a console command, capture output | | `list_online_players` | List online players | | `list_plugins` | List loaded plugins | | `install_plugin` | Copy a jar into `plugins/`, optional hot-load | | `reload_plugin` | Disable + re-enable a named plugin | | `restart_server` | Restart or stop the server | | `reflect_invoke` | Call any server-side method via reflection | | `reflect_get_field` | Read a field value via reflection | | `reflect_set_field` | Set a field value via reflection | | `reflect_new_instance` | Construct a new object instance | | `get_class_info` | List declared methods and fields of a class | | `var_get / var_list / var_delete / var_clear` | Manage named variables across calls | | `search_javadocs` | Search Paper/Folia/Velocity javadoc index | | `fetch_javadoc_page` | Fetch and strip HTML from a javadoc page | ### Fabric client mod (`mcp-server-fabric`) | Tool | Description | |------|-------------| | `get_chat_log` | Recent chat HUD messages | | `send_chat_message` | Send chat text or `/command` | | `get_player_state` | Position, health, inventory, game mode | | `player_move_to` | Teleport player to coordinates | | `player_look_at` | Set yaw/pitch or look toward a world point | | `player_jump` | Trigger a jump | | `player_break_block` | Break block at coordinates | | `player_place_block` | Place held item against a block face | | `player_interact` | Right-click a block | | `get_block_at` | Block type and state at coordinates | | `get_nearby_entities` | Entities within a radius | | `take_screenshot` | Capture client view as base64 PNG | | `client_reflect_invoke` | Call any client-side method via reflection | | `client_reflect_get_field` | Read a client-side field | | `client_reflect_set_field` | Set a client-side field | | `client_get_class_info` | List methods/fields of a Minecraft class | | `client_var_get / client_var_list / client_var_delete / client_var_clear` | Variable management | --- ## Reflection & variable system The reflection tools let you call any method on any allowed class and chain results together using named variables: ``` # Get the overworld World object and store it as $overworld reflect_invoke( class_name="org.bukkit.Bukkit", method_name="getWorld", args=[{type:"java.lang.String", value:"world"}], assign_to="overworld" ) # Use $overworld to get the player list reflect_invoke( class_name="org.bukkit.World", target="$overworld", method_name="getPlayers", assign_to="players" ) # Read a field on a non-serialisable object returned as an opaque handle # (the handle ID looks like "obj_42") reflect_get_field( class_name="org.bukkit.entity.Player", field_name="exp", target="obj_42" ) ``` Non-serialisable return values are stored in an in-memory registry and returned as: ```json {"__type": "object_ref", "__id": "obj_42", "__class": "org.bukkit.World"} ``` Pass `"__id"` or `"$varName"` back as a `target` or argument `value` in subsequent calls. --- ## Configuration ### Paper plugin (`plugins/MinecraftMcp/config.yml`) ```yaml websocket: host: "0.0.0.0" port: 25575 reflection: allowed-packages: - "org.bukkit.*" - "io.papermc.*" - "net.kyori.adventure.*" - "net.minecraft.*" - "java.util.*" - "java.lang.*" blocked-packages: - "java.lang.Runtime" - "java.lang.ProcessBuilder" max-object-refs: 1000 ``` ### Fabric mod (`.minecraft/config/mcp.json`) ```json { "websocket": { "host": "127.0.0.1", "port": 25576 }, "reflection": { "allowedPackages": ["net.minecraft.*", "com.mojang.*", "net.fabricmc.*"], "blockedPackages": ["java.lang.Runtime"], "maxObjectRefs": 1000 } } ``` --- ## Security notes - The WebSocket servers bind to `127.0.0.1` by default (Fabric) and `0.0.0.0` (Paper — change to `127.0.0.1` if the MCP server runs on the same host). - Reflection is gated behind configurable package allow/block lists. - `java.lang.Runtime` and `java.lang.ProcessBuilder` are blocked by default. - The Paper plugin's command sender runs with OP-level permissions; restrict MCP bridge access on shared servers. --- ## Development ```bash # Run Paper MCP server (connects to ws://localhost:25575) npm run dev:paper # Run Fabric MCP server (connects to ws://localhost:25576) npm run dev:fabric # Override the WebSocket URL PAPER_WS_URL=ws://192.168.1.10:25575 npm run dev:paper ```