#
tokens: 2963/50000 5/5 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .gitignore
├── .python-version
├── pyproject.toml
├── rcon.py
├── README.md
└── uv.lock
```

# Files

--------------------------------------------------------------------------------
/.python-version:
--------------------------------------------------------------------------------

```
3.12

```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# Python-generated files
__pycache__/
*.py[oc]
build/
dist/
wheels/
*.egg-info

# Virtual environments
.venv

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
#   For a library or package, you might want to ignore these files since the code is
#   intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
#   However, in case of collaboration, if having platform-specific dependencies or dependencies
#   having no cross-platform support, pipenv may install dependencies that don't work, or not
#   install all needed dependencies.
#Pipfile.lock

# UV
#   Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
#   This is especially recommended for binary packages to ensure reproducibility, and is more
#   commonly ignored for libraries.
#uv.lock

# poetry
#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
#   This is especially recommended for binary packages to ensure reproducibility, and is more
#   commonly ignored for libraries.
#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
#   in version control.
#   https://pdm.fming.dev/latest/usage/project/#working-with-version-control
.pdm.toml
.pdm-python
.pdm-build/

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can
#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
#  and can be added to the global gitignore or merged into this file.  For a more nuclear
#  option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Ruff stuff:
.ruff_cache/

# PyPI configuration file
.pypirc

```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# Minecraft Docker MCP

An MCP server for Minecraft-in-Docker that enables AI interactions with a running Minecraft server using itzg's docker-minecraft-server container.

* Expose server administration to AI clients like Claude Desktop, Cursor, and Zed.
* Allow models to programmatically create minecraft builds in game

LLMs have largely been trained on `rcon` commands, so there's a wide breadth of ability inherent in just exposing `rcon` to the model.

If you're already using the `itzg/minecraft-server` docker image, this MCP server will allow you to interact with your server via clients like Claude Desktop, Cursor, and Zed. The only requirement is that `mc` is the name of the container.

## Prerequisites

- A running Minecraft server in a Docker container named `mc`
- RCON enabled and properly configured

```bash
docker run -d --name mc -p 25565:25565 -e EULA=TRUE itzg/minecraft-server
```

To ensure you're able to use this server, try running an `rcon` command to see if you get a response.

```bash
docker exec -it mc rcon "list"
```

If you get a response, you're all set! If you don't, please refer to the [itzg/docker-minecraft-server](https://github.com/itzg/docker-minecraft-server) repository for troubleshooting.

## MCP Integration

This MCP server leverages itzg's docker-minecraft-server container's built-in RCON functionality to interact with the Minecraft server. The container provides the `rcon` command within the running container, making it an ideal target for MCP interactions.

### Connecting to Claude Desktop

Clone this repository and install the `rcon.py` tool using the MCP CLI.

```
mcp install rcon.py
```
```

--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------

```toml
[project]
name = "minecraft-docker-mcp"
version = "0.1.0"
description = "Model Context Protocol Server for Minecraft Administration"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
    "httpx>=0.28.1",
    "mcp[cli]>=1.2.1",
]

```

--------------------------------------------------------------------------------
/rcon.py:
--------------------------------------------------------------------------------

```python
# server.py
import subprocess
from typing import Optional
# from enum import Enum
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Minecraft Admin")


@mcp.tool()
def rcon(command: str) -> str:
    """Issue commands to the Minecraft server via RCON. Best practices and common patterns include:

## Player Location & Building
1. ALWAYS get player coordinates first before building:
   - `data get entity player_name Pos`
   - This returns coordinates in format: [X.XXd, Y.XXd, Z.XXd]
   - Store these coordinates and use them as the base for building

2. Building Commands:
   - Direct placement: `setblock x y z block_type`
   - Fill command: `fill x1 y1 z1 x2 y2 z2 block_type [replace|keep|outline|hollow]`
   - Clone command: `clone x1 y1 z1 x2 y2 z2 dest_x dest_y dest_z`

3. Entity Commands:
   - Summon entities: `summon <entity_type> <x> <y> <z>`
   - Teleport entities: `tp @e[type=<entity_type>] <x> <y> <z>`
   - Execute as entities: `execute as @e[type=<entity_type>] at @s run <command>`

4. View/Perspective Commands:
   - Teleport to location: `tp @p x y z`
   - Spectate entity: `spectate <target> [player]`
   - Execute from position: `execute positioned x y z run <command>`

## Common Command Patterns
Item Commands:
- give rgbkrk coal 12
- give rgbkrk iron_axe[enchantments={levels:{"minecraft:sharpness":5,"minecraft:efficiency":5,"minecraft:fortune":5}}] 1 
- give @a iron_pickaxe[unbreakable={}] 

Effect Commands:
- effect give @a speed 300 2 
- effect give LoganTheParrot minecraft:night_vision 1000 1 
- effect give rgbkrk water_breathing infinite 1 true

Potion Commands:
- Basic item: give rgbkrk potion[minecraft:potion_contents={potion:"minecraft:fire_resistance"}]
- Multiple items: give rgbkrk potion[minecraft:potion_contents={potion:"minecraft:strength"}] 5
- Splash/lingering variants: give rgbkrk splash_potion[minecraft:potion_contents={potion:"minecraft:poison"}]

## Targeting Players
- Use `@a` for all players
- Use a player name to target a specific player (e.g. rgbkrk)
- Can get specific player coordinates: `data get entity player_name Pos`
- Position returns format: [X.XXd, Y.XXd, Z.XXd]

## Block Placement Best Practices
1. Get player coordinates first
2. Calculate relative positions from stored coordinates
3. Build structures using absolute coordinates
4. Test for block type existence before using (some modded blocks may not exist)

## Block States
- Use square brackets for block states: `block_type[property=value]`
- Example: `lantern[hanging=true]`
- Multiple properties use comma separation

## Relative vs Absolute Coordinates
- Absolute: Uses exact coordinates (x y z)
- Relative to player: Uses tilde notation (~)
  - `~` means current position
  - `~1` means one block offset
  - `~-1` means one block negative offset

## Common Gotchas
- NEVER build large structures relative to the player's current position. GET the location needed first.
- RCON needs player context for certain commands like `locate`
- Block placement might need block states specified
- Fill commands include both start and end coordinates
- Coordinates are exclusive (e.g., ~0 to ~15 creates a 16-block span)
- Test for block existence before using modded or unusual blocks
    
    """
    return subprocess.check_output(["docker", "exec", "mc", "rcon-cli", command]).decode("utf-8")


@mcp.tool()
def list_players() -> str:
    """List all currently connected players on the Minecraft server."""
    return rcon("list")


@mcp.tool()
def help(command: Optional[str] = None) -> str:
    """Get help for Minecraft commands."""
    return rcon(f"help {command}" if command else "help")


# class WeatherType(Enum):
#     CLEAR = "clear"
#     RAIN = "rain"
#     THUNDER = "thunder"

# @mcp.tool()
# def weather(type: WeatherType = WeatherType.CLEAR) -> str:
#     """Set the weather in the Minecraft world.
    
#     Args:
#         type: Weather type (clear, rain, thunder)
#     """
#     return rcon(f"weather {type.value}")


@mcp.tool()
def server_stats() -> str:
    """Get server statistics including CPU, memory usage, and uptime."""
    try:
        stats = subprocess.check_output(
            ["docker", "stats", "mc", "--no-stream", "--format", "{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"]
        ).decode("utf-8").strip()
        return f"Server Stats:\n{stats}"
    except subprocess.CalledProcessError as e:
        return f"Error getting server stats: {str(e)}"

@mcp.tool()
def server_logs(lines: int = 10) -> str:
    """Get recent server logs.
    
    Args:
        lines: Number of recent log lines to fetch (default: 10)
    """
    try:
        logs = subprocess.check_output(
            ["docker", "logs", "--tail", str(lines), "mc"]
        ).decode("utf-8")
        return logs
    except subprocess.CalledProcessError as e:
        return f"Error fetching logs: {str(e)}"

@mcp.tool()
def check_server_status() -> str:
    """Check if the Minecraft server is running and responsive."""
    try:
        status = subprocess.check_output(
            ["docker", "inspect", "-f", "{{.State.Status}}", "mc"]
        ).decode("utf-8").strip()
        
        if status == "running":
            # Try to execute a simple rcon command to verify server is responsive
            try:
                response = rcon("list")
                return f"Server is running and responsive.\nStatus: {status}\n{response}"
            except Exception as _:
                return f"Server is running but may not be fully initialized.\nStatus: {status}"
        else:
            return f"Server is not running. Status: {status}"
    except subprocess.CalledProcessError as e:
        return f"Error checking server status: {str(e)}"
```