# DOSBox-X MCP Server AI-assisted debugging of DOS binaries via the Model Context Protocol (MCP). This MCP server enables Claude to programmatically debug DOS programs running in DOSBox-X by providing tools for: - Setting breakpoints and tracing execution - Reading/writing CPU registers and memory - Disassembling code at any address - Step-by-step instruction execution ## Primary Use Case **Reverse engineering classic DOS programs** — specifically, tracing the unpublished Bezier curve algorithm in RIPTERM.EXE for the [RIPscrip graphics protocol research project](https://github.com/ryanmalloy/rpmesh). ## Quick Start ### Prerequisites - Python 3.11+ - [uv](https://github.com/astral-sh/uv) package manager - Docker and Docker Compose - X11 display (for DOSBox GUI) or use headless mode ### Installation ```bash # Clone the repository git clone https://github.com/ryanmalloy/dosbox-mcp.git cd dosbox-mcp # Install dependencies uv sync # Build Docker image (uses lokkju/dosbox-x-remotedebug fork) docker compose build # Create DOS directory for your binaries mkdir -p dos ``` ### Running ```bash # Allow X11 access for Docker (Linux) xhost +local:docker # Start DOSBox-X with GDB server docker compose up -d # Verify GDB port is listening nc -zv localhost 1234 # View logs docker compose logs -f ``` ### Register with Claude Code ```bash # Add to Claude Code claude mcp add dosbox-mcp -- uv run --directory /path/to/dosbox-mcp dosbox-mcp # Verify registration claude mcp list ``` ## Usage with Claude Once registered, Claude can debug DOS binaries: ```python # Connect to the running DOSBox-X GDB server attach("localhost", 1234) # Read current CPU state registers() # Read memory at CS:IP memory_read("CS:IP", 64) # Set a breakpoint at the boot sector breakpoint_set("0x7C00") # Continue execution until breakpoint continue_execution() # Step through instructions step(10) # Disassemble at current location disassemble("CS:IP", 20) # Disconnect when done quit() ``` ## Tools Reference ### Execution Control (6 tools) | Tool | Description | |------|-------------| | `launch` | Start DOSBox-X container with optional binary | | `attach` | Connect to GDB stub at host:port | | `continue_execution` | Run until breakpoint or signal | | `step` | Step N instructions (default: 1) | | `step_over` | Step over CALL instructions | | `quit` | Disconnect and optionally stop DOSBox-X | ### Breakpoints (3 tools) | Tool | Description | |------|-------------| | `breakpoint_set` | Set software breakpoint at address | | `breakpoint_list` | List all active breakpoints | | `breakpoint_delete` | Remove breakpoint by ID or all | ### Inspection (6 tools) | Tool | Description | |------|-------------| | `registers` | Read all CPU registers (32-bit, 16-bit, segments, flags) | | `memory_read` | Read memory in hex/ASCII/dump format | | `memory_write` | Write hex or ASCII data to memory | | `disassemble` | Disassemble instructions with opcode hints | | `stack` | Dump stack contents from SS:SP | | `status` | Get debugger connection status | ### Peripheral (2 tools — stubs) | Tool | Description | |------|-------------| | `screenshot` | Capture DOSBox-X display (not yet implemented) | | `serial_send` | Send data to serial port (not yet implemented) | ## Address Formats The server supports multiple address formats: | Format | Example | Description | |--------|---------|-------------| | Segment:offset | `1234:5678` | Standard DOS format | | Flat hex | `0x12345` or `12345` | Physical address | | Decimal | `#65536` | Decimal address | | Register-based | `CS:IP`, `DS:SI` | Uses current register values | ## Architecture ``` ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ Claude Code │────▶│ DOSBox-X MCP │────▶│ DOSBox-X │ │ │ MCP │ Server │ GDB │ Container │ └─────────────────┘ └──────────────────┘ └─────────────────┘ │ │ │ │ │ │ ▼ ▼ ▼ FastMCP 2.x GDB Remote lokkju/dosbox-x- (stdio) Protocol remotedebug fork (TCP :1234) (--enable-remotedebug) ``` ### Why lokkju/dosbox-x-remotedebug? Mainline DOSBox-X doesn't include a GDB server. The [lokkju/dosbox-x-remotedebug](https://github.com/lokkju/dosbox-x-remotedebug) fork adds: - `--enable-remotedebug` build flag - GDB server on port 1234 (configurable) - QMP server on port 4444 for machine control - Config options in `[dosbox]` section: `gdbserver=true`, `gdbserver port=1234` ## Project Structure ``` dosbox-mcp/ ├── src/dosbox_mcp/ │ ├── server.py # FastMCP server entry point │ ├── gdb_client.py # GDB Remote Serial Protocol client │ ├── dosbox.py # DOSBox-X process/container management │ ├── state.py # Shared global state (manager, client) │ ├── types.py # Type definitions (Registers, Breakpoint, etc.) │ ├── utils.py # Address parsing, format conversion │ └── tools/ # MCP tool implementations │ ├── execution.py # launch, attach, continue, step, quit │ ├── breakpoints.py # breakpoint_set, list, delete │ ├── inspection.py # registers, memory, disassemble, stack │ └── peripheral.py # screenshot, serial (stubs) ├── tests/ # pytest test suite ├── config/ │ └── dosbox.conf # DOSBox-X configuration with GDB enabled ├── dos/ # Mount point for DOS binaries ├── Dockerfile # Multi-stage build for dosbox-x-remotedebug ├── docker-compose.yml # Container orchestration └── pyproject.toml # Python package definition ``` ## Configuration ### DOSBox-X Config (`config/dosbox.conf`) ```ini [dosbox] memsize=16 gdbserver=true gdbserver port=1234 qmpserver=true qmpserver port=4444 [autoexec] MOUNT C /dos C: ``` ### Environment Variables (`.env`) ```bash GDB_PORT=1234 # Host port for GDB QMP_PORT=4444 # Host port for QMP DOS_DIR=./dos # DOS files mount point CONFIG_FILE=./config/dosbox.conf ``` ## Development ```bash # Run tests uv run pytest # Run tests with coverage uv run pytest --cov=dosbox_mcp # Lint code uv run ruff check src/ # Format code uv run ruff format src/ # Type check (optional) uv run mypy src/ ``` ## Technical Details ### GDB Remote Serial Protocol The server implements a client for the [GDB Remote Serial Protocol](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Remote-Protocol.html): | Command | Description | |---------|-------------| | `qSupported` | Capability negotiation (handshake) | | `g` / `G` | Read/write all registers | | `p` / `P` | Read/write single register | | `m` / `M` | Read/write memory | | `Z0` / `z0` | Set/clear software breakpoint | | `c` / `s` | Continue / step | | `?` | Query stop reason | Packets use format: `$#<2-digit checksum>` ### Real Mode Addressing DOS uses real mode with segment:offset addressing: ``` Physical Address = (Segment << 4) + Offset ``` This gives a 20-bit address space (1MB). The `Registers` class provides helpers like `cs_ip` and `ss_sp` for common address calculations. ## Troubleshooting ### GDB Connection Refused ```bash # Check if container is running docker ps | grep dosbox # Check if GDB port is listening docker exec dosbox-mcp nc -zv localhost 1234 # Check logs for GDB server startup docker logs dosbox-mcp 2>&1 | grep -i gdb ``` ### Container Shows "unhealthy" The healthcheck uses `nc` which may not be installed in the slim image. This is cosmetic — the GDB server still works. To fix, add `netcat-openbsd` to the Dockerfile runtime stage. ### X11 Display Issues ```bash # Allow Docker X11 access xhost +local:docker # Or use headless mode docker compose --profile headless up -d dosbox-headless ``` ## Related Projects - [RIPscrip Research (rpmesh)](https://github.com/ryanmalloy/rpmesh) — Parent project - [lokkju/dosbox-x-remotedebug](https://github.com/lokkju/dosbox-x-remotedebug) — DOSBox-X fork with GDB - [FastMCP](https://gofastmcp.com/) — MCP server framework - [GDB Remote Protocol](https://sourceware.org/gdb/current/onlinedocs/gdb.html/Remote-Protocol.html) ## License MIT License