Atari Hacker MCP
by pdavis68
README.md
# AtariHackerMCP
A local MCP server for reverse-engineering Atari 8-bit binaries and ATR disk images. Supports multi-pass disassembly analysis, code/data separation, segment-aware output, ATR file injection, batch scripting, and a comprehensive Atari hardware symbol table.
## Requirements
- .NET SDK 10.0+
- Linux, macOS, or Windows
## Build
Restore packages and compile:
```bash
dotnet build
```
Publish a release build if needed:
```bash
dotnet publish -c Release -o publish
```
## Run
This server uses MCP stdio transport, so it is normally launched by an MCP client rather than run interactively.
For local testing:
```bash
dotnet run --no-build
```
Or run the published executable:
```bash
./publish/AtariHackerMCP
```
## MCP Client Configuration
Example stdio server entry:
```json
{
"mcpServers": {
"atari-hacker": {
"command": "dotnet",
"args": [
"run",
"--project",
"/absolute/path/to/AtariHackerMCP/AtariHackerMCP.csproj",
"--no-build"
]
}
}
}
```
If you prefer using a published build:
```json
{
"mcpServers": {
"atari-hacker": {
"command": "/absolute/path/to/AtariHackerMCP/publish/AtariHackerMCP",
"args": []
}
}
}
```
## Available Tools
### File and disk tools
- `load_rom` — Load a ROM/XEX binary into the current session
- `rom_info` — Display structural info about the loaded binary
- `atr_info` — Display structural info about an ATR disk image
- `atr_header` — Display the ATR header fields for a disk image
- `load_atr_file` — Extract a file from an ATR and load it into the session
- `load_atr_boot` — Extract boot sectors from an ATR and load them at $0700
- `list_atr_directory` — List the DOS directory of an ATR disk image
- `analyze_boot_sector` — Decode the boot sector header from an ATR
- `sector_dump` — Hex dump sectors from an ATR by logical sector number
- `search_boot_sector` — Scan boot sectors across multiple ATRs for patterns/differences
- `extract_atr_file` — Extract a file from an ATR and save it to disk
- `inject_atr_file` — Inject a file into an ATR (copy-on-write)
- `create_atr` — Create a new ATR disk image from scratch
- `write_atr_sector` — Write raw data to a specific sector of an ATR
- `write_atr_file` — Write a file to an ATR with directory entry creation
- `define_filesystem` — Define a custom filesystem layout for non-DOS ATRs
### Inspection and disassembly
- `hex_dump` — Produce a hex dump with file offsets, memory addresses, and ASCII
- `disassemble` — Disassemble 6502 code with optional multi-pass analysis (`analyze=true`)
- Supports formats: `listing`, `ca65`, `atasm`, `mac65`
- When `analyze=true`: generates meaningful labels (`sub_XXXX`, `data_XXXX`, `jmp_XXXX`), code/data separation, segment-aware `.segment`/`.proc`/`.endproc` output, ATASCII string formatting, procedure header comments
- `analyze_disassembly` — Multi-pass analysis building a reference graph and identifying code/data regions
- Formats: `summary`, `graph`, `labels`, `full`
- `define_segment` — Define a memory segment by type (code, data, graphics, text, zero_page)
- `remove_segment` — Remove a defined segment by name
- `list_segments` — List all defined memory segments (shows gaps)
- `clear_segments` — Clear all defined segments
- `generate_linker_config` — Generate a cc65 linker configuration from current segments
### Analysis tools
- `x_ref` — Find cross-references to an address in the ROM
- `find_pattern` — Search for a byte pattern with wildcards
- `find_strings` — Search for runs of printable ASCII or ATASCII characters
- `trace_control_flow` — Statically trace execution from a starting address
- `probe_data` — Analyze a memory range to identify data type (text, graphics, table, charset, display list, sprite data, map data) with confidence scoring
- `generate_callgraph` — Generate a call graph showing subroutine relationships (Mermaid or text format)
- `analyze_coverage` — Analyze code coverage: which bytes are executed vs. data
- `diff_roms` — Compare two ROM or ATR files (summary, verbose, or hex diff format)
### Symbol and zero-page tools
- `define_symbol` — Add or update a named label for a memory address
- `remove_symbol` — Remove a user-defined symbol
- `lookup_symbol` — Look up the symbol entry for an address
- `list_symbols` — List symbols in the symbol table
- `set_symbols` — Enable/disable symbol groups (hardware, OS variables, OS ROM, user labels) to control which names appear in disassembly
- `load_labels` — Load labels and segments from a sidecar file
- `save_labels` — Save current labels and segments to a sidecar file
- `annotate_zero_page` — Add or update a zero-page annotation
- `show_zero_page_map` — Display current zero-page annotations
### Scripting tools
- `run_script` — Execute a sequence of commands from a script file (supports 33 commands)
### Utility tools
- `calculate` — Evaluate mathematical expressions with hex literals (`$` prefix)
- `hex_to_decimal` — Convert hex to decimal
- `decimal_to_hex` — Convert decimal to hex
## Multi-Pass Disassembly
When `analyze=true` is passed to `disassemble`, the engine performs three passes:
1. **Pass 1 — Reference Collection**: Scans all instruction boundaries across the ROM, recording JSR targets, JMP targets, branch targets, indirect jump targets, and absolute/indirect data references into a `ReferenceGraph`.
2. **Pass 2 — Code Region Tracing**: Starting from each code entry point, traces execution flow (following JSR, JMP, branches, stopping at RTS/RTI/BRK) to mark bytes as code or data.
3. **Pass 3 — Label Generation**: Produces meaningful labels (`sub_XXXX`, `jmp_XXXX`, `data_XXXX`, `L_XXXX`) with proper priority ordering (user > subroutine > data > hardware > OS > branch).
### Example
```ca65
; --------------------------------------------------
; Generated by Atari Hacker MCP v4
; --------------------------------------------------
.segment "MAIN_CODE"
.org $0C00
; --------------------------------------------------
; Subroutine: game_init
; Calls: load_ag_obj, load_ag_dat, main_loop
; --------------------------------------------------
.proc game_init
LDA #$00
STA $D400 ; DMACTL
...
.endproc
; String table at $1712
credits_text:
.byte "Scholastic", $9B ; $9B = ATASCII EOL
.byte "Wizware", $9B
.byte $00
```
## Atari Hardware Symbol Table
The built-in symbol table covers over 200 entries across all major Atari components:
| Group | Range | Entries |
|-------|-------|---------|
| **GTIA** | $D000–$D01F | 22 registers (player/missile graphics, color, control) |
| **POKEY** | $D200–$D21F | 32 registers (sound, I/O, reserved, read/write aliasing) |
| **PIA** | $D300–$D303 | 4 registers (parallel I/O) |
| **ANTIC** | $D400–$D41F | 20 registers (DMA, display list, NMI, reserved) |
| **OS ROM** | $C000–$FFFF | 13 entry points (SIO, CIO, vectors) |
| **Zero page OS** | $00–$FF | ~220 variables (timers, I/O control, floating point, screen, paddles, joysticks) |
Symbol groups can be toggled with `set_symbols` to avoid conflicts when user code overlaps OS address ranges.
## ATR Write Operations
The ATR write subsystem provides copy-on-write disk image modification:
| Operation | Description |
|-----------|-------------|
| `extract_atr_file` | Extract a DOS file from an ATR to the host filesystem |
| `inject_atr_file` | Replace a file entry's data in an ATR (creates `.modified` copy) |
| `create_atr` | Create a blank ATR with specified sector count and density |
| `write_atr_sector` | Write raw binary data to a specific sector |
| `write_atr_file` | Create a new DOS file entry with sector allocation |
| `define_filesystem` | Describe a non-DOS filesystem layout for custom-format disks |
## Batch Scripting
The `run_script` tool executes sequences of commands from text files:
```bash
# disassemble_all.txt
load_rom filePath=game.xex
define_symbol address=$1540 label=game_init
define_segment name=boot_loader start=$0700 end=$087F type=code
define_segment name=main_code start=$0C00 end=$1CFF type=code
disassemble offset=$0700 numBytes=384 format=ca65 analyze=true
generate_linker_config output=game.cfg
save_labels filePath=game.annotations.json
```
## Data Probing
`probe_data` uses 7 heuristics to identify data types in memory ranges:
- **String detection** — ATASCII/ASCII printable runs, `$9B`-terminated, null-terminated
- **Padding detection** — Runs of `$00`, `$FF`, `$1A` (ATASCII EOL)
- **Character set detection** — 1024-byte (128×8) and 512-byte (64×8) blocks
- **Table detection** — 2-byte address tables, 1-byte lookup tables
- **Display list detection** — ANTIC display list opcodes with LMS extraction
- **Sprite data detection** — 8/16/32-byte aligned blocks with byte variety analysis
- **Map data detection** — 2D grid patterns with consistent row lengths
Each result includes a confidence level (High/Medium/Low) and supporting details.
## Typical Workflow
### Basic exploration
1. Load a file with `load_rom`, `load_atr_file`, or `load_atr_boot`.
2. Inspect structure with `rom_info` or `atr_info`.
3. Use `hex_dump` to examine raw bytes, `find_strings` to locate text.
4. Disassemble with `disassemble` (basic mode).
### Analysis-driven disassembly
1. `load_rom` → Load the binary.
2. `analyze_disassembly format=summary` → Get code/data overview.
3. `analyze_disassembly format=labels` → View all auto-generated labels.
4. `probe_data start=$1712 end=$1AD4` → Identify data regions.
5. `define_segment name=main_code start=$0C00 end=$1CFF type=code`
6. `define_segment name=game_data start=$1D00 end=$BBA4 type=data`
7. `disassemble offset=$0C00 numBytes=5376 format=ca65 analyze=true` → Segment-aware output.
8. `generate_callgraph start=$1540 depth=5 format=mermaid` → Visualize structure.
9. Iterate: `define_symbol` → `disassemble analyze=true` → review.
### Iterative refinement workflow
1. `load_rom` → initial disassembly with auto-labels.
2. `analyze_disassembly` → identify code/data regions.
3. `define_symbol` → annotate key addresses.
4. `define_segment` → mark code/data regions.
5. `save_labels` → persist annotations.
6. `disassemble analyze=true` → re-disassemble with annotations.
7. Review, repeat steps 3-6 as needed.
### ATR modification workflow
1. `create_atr output=build/disk.atr sectors=720 density=sd` → blank disk.
2. `write_atr_sector filePath=build/disk.atr sector=1 input=boot.bin` → write boot sector.
3. `write_atr_file filePath=build/disk.atr name=AGENT.OBJ input=build/AGENT.OBJ` → add file.
4. `extract_atr_file filePath=game.atr name=AGENT.OBJ output=extracted/AGENT.OBJ` → extract file.
5. `inject_atr_file filePath=game.atr name=AGENT.OBJ input=build/AGENT.OBJ` → replace file.
## Persistence
User-defined symbols, zero-page annotations, and segment definitions are saved automatically to a sidecar JSON file next to the loaded target:
```text
<rom-or-synthetic-path>.atarihacker.json
```
The v4 sidecar format includes:
- Version field for forward compatibility
- SHA-256 ROM hash for integrity checking
- Segments (name, type, start, end, comment)
- Custom filesystem definitions
v3 sidecar files (without version field) are read transparently and upgraded on save.
## Example MCP Smoke Test
This sends `initialize` and `tools/list` directly over stdio:
```bash
(
printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test-client","version":"1.0"}}}\n'
sleep 0.2
printf '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}\n'
sleep 1
) | dotnet run --no-build
```
## Notes
- Logs are written to stderr so stdout remains clean for MCP JSON-RPC traffic.
- The `disassemble` tool with `analyze=false` (default) behaves exactly as in v3 — full backward compatibility.
- Self-modifying code and jump table dispatch (`JMP (table,X)`) cannot be resolved statically; use `define_segment` to mark those regions manually.
- For full design details, see [`docs/version4-design.md`](docs/version4-design.md) and the [v4 specification](docs/version4-spec.md).
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues