aplassard/boxoban-mcp
If you are the rightful owner of boxoban-mcp and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
The Boxoban MCP Server provides a Model Context Protocol interface for interacting with the Boxoban game, allowing users to load puzzles and perform actions using standard MCP tools.
load_game
Loads a specific game by difficulty, split, puzzle set number, and puzzle number.
get_game_state
Returns the current board state.
get_valid_moves
Lists valid moves.
take_action
Performs an action.
take_action_list
Performs a sequence of actions.
return_full_game_state
Provides a comprehensive game state.
Boxoban Game Engine
This repository provides a Python-based game engine for Boxoban, a box-pushing puzzle game inspired by Sokoban. The engine allows for loading game levels, representing the game state, identifying valid moves, and taking actions.
Installation
To use the BoxobanGame
class in your own projects, you first need to install it. Navigate to the root directory of this repository in your terminal.
It's recommended to use a virtual environment:
uv venv
source .venv/bin/activate # On Windows use `.venv\Scripts\activate`
Then, install the package. For a regular install:
uv pip install .
For an editable install (allows you to make changes to the source code and have them immediately reflected):
uv pip install -e .
After installation, you can import the game class as shown in the examples below.
Game Representation
The game is played on a grid. The following symbols are used to represent the game elements:
#
: Wall - Impassable.@
: Player - The character controlled by the user.$
: Box - An object that can be pushed by the player..
: Target - A destination square for a box.+
: Player on Target - The player is currently on a target square.*
: Box on Target - A box is currently on a target square.
The objective of the game is to push all boxes ($
) onto all target squares (.
). When a box is on a target, it is represented as *
.
BoxobanGame
Class
The core of the engine is the BoxobanGame
class, located in boxoban_mcp.game
once installed.
Initialization and Loading Games
You can load a game in several ways:
-
From a string:
from boxoban_mcp import GameLoader # For loading # from boxoban_mcp import BoxobanGame # If you need to type hint or refer to the game class directly board_string = "####\\n#@$.#\\n####" # Represents: # #### # #@$.# (Player, Box, Target) # #### game = GameLoader.load_game_from_string(board_string) # Returns a BoxobanGame instance
-
From a file: Puzzle files can contain multiple puzzles, separated by a semicolon and a puzzle number (e.g.,
0\nPuzzleData0;1\nPuzzleData1
). The game engine will automatically download and cache puzzle files if they are not found locally.from boxoban_mcp import GameLoader # The engine will attempt to load this from a local cache or download it. # Example: puzzles/medium/train/000.txt # And puzzle 0 in that file is "####\\n#@.#\\n####" game = GameLoader.load_game_from_file("medium/train/000.txt", puzzle_index=0)
If a file contains only a single puzzle string without a preceding index number, use
puzzle_index=0
. When usingload_game_from_file
, the path provided should be relative to the root of the cached puzzle structure (e.g.,difficulty/split/filename.txt
). -
From parameters: This is the recommended method for loading standard puzzles. It automatically handles downloading and caching. The game will construct the necessary paths and fetch files from an online repository if not found in the local cache (typically located in your system's temporary directory).
from boxoban_mcp import GameLoader # Loads puzzle 12 from the 'medium' difficulty, 'train' split, set '001'. # Files will be downloaded and cached if not present locally. game = GameLoader.load_game_from_params( # Corrected: GameLoader difficulty="medium", split="train", puzzle_set_num="001", # or e.g. 1 puzzle_num=12 )
Interacting with the Game
Once a game is loaded:
-
Get Game State: Returns the current board as a string, using the symbols described above (including
+
and*
).state_string = game.get_game_state() print(state_string) # Example output: # ##### # # @*# (Player is next to a Box on a Target) # #####
-
Get Valid Moves: Returns a list of valid actions the player can currently take. Actions are strings:
'up'
,'down'
,'left'
,'right'
.valid_moves = game.get_valid_moves() # e.g., ['up', 'right']
-
Take Action: Applies an action to the game state. Returns
True
if the action was legal and performed,False
otherwise.if 'right' in game.get_valid_moves(): was_legal = game.take_action('right') if was_legal: print("Moved right!") print(game.get_game_state())
The
take_action
method will update the player's position and any pushed box. If the player pushes a box into a wall or another box, the action is illegal. -
Check if Solved: Returns
True
if all boxes are on target squares,False
otherwise.if game.is_solved(): print("Puzzle solved!")
Development and Testing
This project uses uv
for package management and pytest
for testing.
-
Setup (using uv): If you plan to contribute or run tests, set up a virtual environment and install development dependencies:
uv venv source .venv/bin/activate uv pip install -e .[dev] # Installs the package in editable mode along with dev dependencies like pytest
-
Running Tests: Navigate to the root of the repository and run:
pytest
Original Dataset Information (Citation)
If you use the underlying Boxoban level dataset in your work (the game automatically downloads levels based on this dataset's structure), please cite the original authors:
Note on the local puzzles/
directory:
The puzzles/
directory included in this repository is for reference and historical purposes. The game engine now automatically downloads and caches the required puzzle files from an online source into a temporary directory on your system when load_game_from_params
(or load_game_from_file
if the file isn't in the cache) is called. Therefore, the local puzzles/
directory is no longer actively used by the game logic for loading levels and can be manually removed from your local clone of the repository if desired.
@misc{boxobanlevels,
author = {Arthur Guez and Mehdi Mirza and Karol Gregor and Rishabh Kabra and Sebastien Racaniere and Theophane Weber and David Raposo and Adam Santoro and Laurent Orseau and Tom Eccles and Greg Wayne and David Silver and Timothy Lillicrap and Victor Valdes},
title = {An investigation of Model-free planning: boxoban levels},
howpublished= {https://github.com/deepmind/boxoban-levels/},
year = "2018"
}
Questions regarding the dataset can be directed to Theophane Weber ().
This is not an official Google product.
Boxoban MCP Server
A Model Context Protocol (MCP) server for interacting with the Boxoban game is available in src/boxoban_mcp/server.py
.
This server allows loading Boxoban puzzles and interacting with them using standard MCP tools.
Running the Server
To run the MCP server locally:
python src/boxoban_mcp/server.py
This will start the server, typically on 127.0.0.1:65432
. You can then connect to it using an MCP client or development tools like mcp dev
.
Available Tools (partial list)
load_game(difficulty: str, split: str, puzzle_set_num: int, puzzle_num: int)
: Loads a specific game.get_game_state()
: Returns the current board state.get_valid_moves()
: Lists valid moves.take_action(action: str)
: Performs an action.take_action_list(actions: list[str])
: Performs a sequence of actions.return_full_game_state()
: Provides a comprehensive game state.
(Note: Tool names in the server implementation might slightly differ, e.g., get_full_game_state
for return_full_game_state
. Refer to the server code for exact names.)