332 lines
9.6 KiB
Markdown
332 lines
9.6 KiB
Markdown
# mcdosbox-x
|
|
|
|
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
|
|
- Sending keyboard/mouse input
|
|
- Capturing screenshots and screen text
|
|
- Serial port communication for BBS/terminal programs
|
|
|
|
## 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
|
|
|
|
### Installation from PyPI
|
|
|
|
```bash
|
|
# Install with uvx (recommended)
|
|
uvx mcdosbox-x
|
|
|
|
# Or install with pip
|
|
pip install mcdosbox-x
|
|
```
|
|
|
|
### Register with Claude Code
|
|
|
|
```bash
|
|
# Add to Claude Code
|
|
claude mcp add mcdosbox-x -- uvx mcdosbox-x
|
|
|
|
# Verify registration
|
|
claude mcp list
|
|
```
|
|
|
|
### Development Installation
|
|
|
|
```bash
|
|
# Clone the repository
|
|
git clone https://git.supported.systems/MCP/mcdosbox-x.git
|
|
cd mcdosbox-x
|
|
|
|
# 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
|
|
```
|
|
|
|
### Running with Docker
|
|
|
|
```bash
|
|
# Allow X11 access for Docker (Linux)
|
|
xhost +local:docker
|
|
|
|
# Start DOSBox-X with GDB server
|
|
docker compose up -d
|
|
|
|
# View logs
|
|
docker compose logs -f
|
|
```
|
|
|
|
## 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
|
|
|
|
```
|
|
mcdosbox-x/
|
|
├── src/mcdosbox_x/
|
|
│ ├── server.py # FastMCP server entry point
|
|
│ ├── gdb_client.py # GDB Remote Serial Protocol client
|
|
│ ├── dosbox.py # DOSBox-X process/container management
|
|
│ ├── fonts.py # Bundled TrueType font utilities
|
|
│ ├── resources.py # MCP resources (screenshots, screen)
|
|
│ ├── state.py # Shared global state (manager, client)
|
|
│ ├── types.py # Type definitions (Registers, Breakpoint, etc.)
|
|
│ ├── utils.py # Address parsing, format conversion
|
|
│ ├── fonts/ # Bundled IBM PC TTF fonts (CC BY-SA 4.0)
|
|
│ └── tools/ # MCP tool implementations (47 tools)
|
|
│ ├── execution.py # launch, attach, continue, step, quit, fonts_list
|
|
│ ├── breakpoints.py # breakpoint_set, list, delete
|
|
│ ├── inspection.py # registers, memory, disassemble, stack, screen
|
|
│ ├── peripheral.py # screenshot, keyboard, mouse, joystick, serial
|
|
│ ├── control.py # pause, resume, reset, savestate, loadstate
|
|
│ ├── logging.py # DOSBox logging control
|
|
│ └── network.py # port mapping, modem dial/hangup
|
|
├── tests/ # pytest test suite
|
|
├── 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=mcdosbox_x
|
|
|
|
# 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: `$<command>#<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
|