dspre
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@dspreopen heartgold.nds and give Whitney's Miltank a Choice Band"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
dspre-mcp
Edit Gen IV Pokémon DS ROMs by talking to an agent.
Point it at a .nds, say "give Whitney a Garchomp holding a Focus Sash", and the bytes change.
Diamond · Pearl · Platinum · HeartGold · SoulSilver
open_rom { romPath: "/roms/heartgold.nds" }
lookup_names { category: "trainer", query: "whitney" }
→ [{ id: 30, name: "Whitney" }, { id: 714, name: "Whitney" }]
get_trainer { trainer: 30 } → party, slot numbers, current items
set_trainer { trainer: 30, party: [{ slot: 2, species: "Garchomp", level: 40,
heldItem: "Focus Sash",
moves: ["Earthquake", "Dragon Claw",
"Crunch", "Swords Dance"] }] }
set_pokemon { species: "Pikachu", baseStats: { attack: 90, speed: 110 } }
save_rom { outPath: "/roms/heartgold-hack.nds" }Names or IDs, either works. Writes are staged, previewable with dryRun, and undoable. Nothing
touches a .nds until save_rom, and save_rom never overwrites the ROM you opened.
Install
Requirements: Node ≥ 22.18 · a legally obtained .nds of a supported game · the dsrom
binary, which the server can install for you.
claude mcp add dspre -- npx -y @webadeva/dspre-mcpAdd --scope user for every project, or --scope project to write it into the repo's .mcp.json.
{ "mcpServers": { "dspre": { "command": "npx", "args": ["-y", "@webadeva/dspre-mcp"] } } }Claude Desktop: claude_desktop_config.json (Settings → Developer → Edit Config). Cursor:
~/.cursor/mcp.json. Windsurf: ~/.codeium/windsurf/mcp_config.json.
{ "servers": { "dspre": { "command": "npx", "args": ["-y", "@webadeva/dspre-mcp"] } } }.vscode/mcp.json — note VS Code nests under servers, not mcpServers.
WSL works in three placements, including running the server in Linux against a project folder on
the Windows drive that DSPRE's GUI also opens. See docs/WSL.md.
From a clone: pnpm install && pnpm build, then open the folder in Claude Code — the committed
.mcp.json registers and builds the server for you.
Or just paste this prompt into your AI agent
Any agent that can edit files and run a shell — Claude Code, Codex, Cursor, Windsurf, Copilot, Gemini CLI, Cline, Continue — can register the server itself. Hand it this:
Set up the dspre-mcp MCP server for me. It lets you edit Gen IV Pokémon DS ROMs
(Diamond/Pearl, Platinum, HeartGold/SoulSilver) conversationally.
Repo: https://github.com/webadeva/dspre-mcp
Package: @webadeva/dspre-mcp on npm
Launch: stdio MCP server, started with `npx -y @webadeva/dspre-mcp`
Needs: Node >= 22.18
Please:
1. Check `node --version` is at least 22.18 and tell me if it is not.
2. Register the server, under the name "dspre", with whichever MCP client you are
running inside. Prefer that client's own CLI if it has one (for example
`claude mcp add`); otherwise edit its MCP config file directly. Do not guess
the path or the schema — find the config file that already exists on this
machine and match the shape it already uses. Most clients nest servers under
"mcpServers"; VS Code uses "servers" instead.
3. Show me the exact change you made, and tell me whether I need to restart or
reload the client before it will connect.
4. Once the tools are visible, call `install_dsrom`. The server shells out to an
external `dsrom` binary for ROM extract and repack, and that tool downloads
the official hash-verified release into a per-user cache. If I tell you DSPRE
is already installed, call `configure {dspreDir: "<its folder>"}` instead.
5. Verify by calling `get_docs` with no arguments — it is the one tool that works
with no ROM open — and then read the `dspre://guide` resource.
Then stop. Do not open, edit or rebuild any ROM until I ask, and remember that I
have to supply my own legally obtained .nds file.First run
open_rom needs the external dsrom binary (ds-rom, the
same CLI DSPRE shells out to). Pick one:
Call
install_dsrom— downloads the official, hash-verified v0.8.0 release for your platform into a per-user cache. Idempotent. Outside MCP:npx @webadeva/dspre-mcp install-dsrom.Already have DSPRE?
configure {dspreDir: "C:\\pokehg\\tools\\DSPRE"}— it takes the install root, theToolsfolder or an explicit binary path, validates it and remembers it.
Only open_rom and save_rom need the binary; every other tool works on an already-extracted
project folder. open_rom extracts into <rom>_DSPRE_contents beside the ROM unless you pass
projectDir — worth doing if you'd rather not have a 120 MB folder appear there.
Related MCP server: rpgmaker-mz-mcp
Why this exists
DSPRE is the reference tool for Gen IV ROM hacking, and it is a Windows WinForms app with no API, no CLI, nothing to wrap. So this project reimplements DSPRE's binary-format logic in TypeScript and exposes it over MCP. DSPRE's C# source is the format spec; a real retail ROM is the oracle.
Read this before you rely on it
HeartGold (English) is the only validated game. Diamond/Pearl and Platinum are ported from
the C# and typecheck, but no DP/Pt code path has ever run against a real ROM. Treat them as
unproven — open_rom says so when it applies.
3D and geometry are not implemented — map models, building placement, terrain. Map events (NPCs, signs, warps, triggers) are editable; the geometry they stand on is not. Those files round-trip untouched, so keep using DSPRE for them.
A rebuilt ROM boots. melonDS, full speed, reaches Professor Oak's intro with
set_textedits rendered in the game's own font. Record:docs/BOOT-TEST.md.Rebuild differs from retail in exactly 4 bytes — the two header CRC16 fields, which cannot be recomputed without the copyrighted ARM7 BIOS key table. DSPRE ships the same values. The e2e suite pins those four offsets, so a real regression still fails.
set_script: prefereditsover whole-text. The line-level path is byte-exact (443/443); the whole-listing path is byte-exact for only 154/497, because vanilla scripts share container bytes between functions and carry dead code the text form cannot express.DP/Pt egg moves go through overlay 5 and are covered by synthetic round-trips only.
What you can edit
34 tools. Every species / move / item / ability / type / trainer argument takes a name or an ID,
and every one in a reply comes back as {id, name}.
Project
Tool | Purpose |
| Extract a |
| Details of the open project, or the NDS header of any ROM without extracting it. |
| Every kind of packed data this game exposes, where it lives, whether it is present. |
| Name ↔ ID lookup across species, moves, items, abilities, types, classes, trainers, maps. |
| Get the |
Pokémon and battle data
Tool | Purpose |
| Base stats, types, abilities, EV yield, held items, gender ratio, egg data, growth rate, learnset, evolutions, egg moves, TM/HM compatibility as the moves they teach. |
| Type, damage class, power, accuracy, PP, priority, effect id and chance, target, contest data, flag bitfield as named booleans. |
| Price, hold/Pluck/Fling effects, Natural Gift, pockets, field and battle use, party-use parameters — de-aliased through the ARM9 item table. |
| Class, AI flags, battle type, held items, battle messages, and the full party: species, form, level, item, moves, gender/ability overrides, ball seal. |
Text and scripts
Tool | Purpose |
| Read and replace messages in a text archive, by index, paginated. |
| Find messages by substring — one archive, or all 829 at once (~0.2 s). |
| Disassemble a script into DSPRE-style text and write it back, as line-level |
World
Tool | Purpose |
| Wild encounter tables, every slot named and numbered so individual slots can be patched. |
| One map's NPCs, signs, warps and script triggers. Patch a record, append one, delete one. |
|
|
|
|
ROM patches and safety
Tool | Purpose |
| ARM9 expansion, matrix expansion, BDHCAM, building rotation, trainer-name expansion — and unlike DSPRE, undoable here. |
| The journal of what this server has written to the project, newest first. |
| Roll back the last N changes. Refuses if a file was edited outside the server since. |
| Undo everything ( |
| Serves the agent documentation as a tool. The one tool that works with no ROM open. |
How it's verified
Every format module is validated by round-tripping every entry of every archive in a real retail HeartGold ROM and asserting the bytes come back identical. Measured, not estimated.
Area | Result |
Text archives | 829/829 byte-exact |
Messages | 49,984/49,984 string-identical to DSPRE's own decode |
Scripts (parse → serialize) | 497/497 byte-exact |
Script line-level edits | 443/443 same-length edits keep the file's recorded layout |
Level scripts | 468/468 byte-exact, including through |
Disassembly listings | 965/965 textually identical to DSPRE's |
Personal data | 508/508 |
Learnsets | 508/508 |
Evolutions | 508/508 |
Moves | 471/471 |
Items | 514/514 |
Item → data-record table | 537/537 entries; rewriting it reproduces |
Trainers | 738/738 (properties + party archives) |
Trainer battle messages | 1,717/1,717 records and 735/735 offsets |
Map headers | 540/540 |
Headbutt encounter files | 540/540 |
Rock Smash item files | 540/540 |
Event files (NPCs, signs, warps, triggers) | 491/491 byte-exact — 1,034 spawnables, 2,667 overworlds, 1,317 warps, 195 triggers |
Matrices | 288/288 (also matching DSPRE's unpacked output), plus 5/5 synthetic resize cases |
Wild encounter files | 142/142 |
Safari Zone areas | 12/12 |
In-game trades | 13/13 |
Fly destinations | 30/30 — rewriting the table reproduces all 1,120,352 bytes of |
ROM-global tables ( | all six reproduce |
Overlay BLZ decompression | 127/127 compressed retail overlays, byte-for-byte vs ds-rom |
NARC | byte-exact round-trip; members match DSPRE's own unpacked output |
Name tables | ~3,000 names round-trip name → ID → name across all 8 categories |
331 pass / 2 skip / 0 fail (252 core + 79 MCP end-to-end), on Node 22 and 24 in CI on every
push. The MCP suite drives a real Client over an in-memory transport, so it exercises the same
path a live agent does — including a full 124 MB save_rom rebuild and the ROM-toolbox patches
applied for real.
Where DSPRE itself is lossy, we round-trip instead of reproducing the bug — DSPRE's headbutt writer expands 480 of 540 vanilla files from 4 bytes to 76, zeroes DP/Pt's fourth water encounter table, appends a stray padding word to 240 learnsets, and writes 36 bytes for a 34-byte item record. A no-op edit here changes nothing.
The safety layer
The intended operator is an LLM — the actor most likely to issue a confident, wrong, bulk edit — and the project folder is the only copy. So every write goes through one transaction layer.
Preview |
|
All-or-nothing |
|
Undo survives restart |
|
Refuses to guess | Undo refuses rather than silently discarding work if something edited the folder behind the server's back. |
Your ROM is safe |
|
Serialised | Every handler, reads included, queues behind one process-global mutex, so a read never observes a half-open transaction. |
Ambiguity and typos fail loudly. HeartGold really has two trainer entries called Whitney and 24 called Silver, so resolving that throws and lists the colliding IDs rather than editing the wrong battle and looking like it worked. "Garchmop" answers "Did you mean GARCHOMP (445)?".
For AI agents
Reading this repository as an agent? The complete, unsummarised version of this document — every install placement, every tool, every measured pass rate, every documented refusal — is
README.agents.md. Go there.
Once the server is connected it documents itself, and an agent needs nothing from this repository:
instructions, sent on connect: the workflow, the staging model, the safety net, names-vs-IDs.dspre://guide— mental model, pagination, what a write replies, what is validated versus merely ported, and the ~20 gotchas that actually bite.dspre://recipes— worked multi-step tasks with the exact calls and the shape of each reply.dspre://reference/<topic>— the field-by-field reference each tool description points at:pokemon,moves,items,trainers,text,scripts,encounters,events,world-data,rom-tables,patches,history,families,setup.dspre://project— a live summary of the open project, orno ROM open.Five prompts:
edit-trainer,edit-dialogue,rebalance-species,add-npc,safe-edit-session.get_docs {topic?}serves the same text as a tool, for clients that do not surface resources.
Every enum table, per-kind field list and slot-rate table in those documents is rendered from the
code at request time, not transcribed, so a document cannot drift from the handler it describes.
Tool descriptions are deliberately short, because tools/list is sent before an agent has done
anything and every character is paid for up front.
Under the hood
packages/dspre-core Pure data layer, zero MCP dependency. NDS ROM parse/extract/build,
NARC pack/unpack, one module per DSPRE editor (data/ for the flat
tables, world/ for map data, text.ts + script/ for text and scripts,
overlay/ for ARM9, BLZ and ROM-toolbox patches), plus names.ts and
project-data.ts.
apps/dspre-mcp Thin MCP server over @modelcontextprotocol/sdk. Schema, validation,
a call into core, a formatted reply. No format logic lives here.
packages/tsconfig Shared strict tsconfig both of the above extend.Parse and serialize are pure functions over Buffer (parseX(buf) / serializeX(x)), with file
I/O at the edges — which is what makes the round-trip tests above trivial to write and impossible
to fake.
It was ported one module per ROMFiles class under a standing rule: never invent a byte layout.
Where the C# is ambiguous the field is left out and the ambiguity recorded rather than guessed — a
plausible-but-wrong offset produces a file that looks fine and corrupts a save. Field meaning is
cross-checked against the corresponding WinForms editor, since the ROMFiles class gives offsets
and the editor gives semantics and valid ranges.
Large tables are generated, not transcribed: the text charmap from DSPRE's charmap.json, the
per-family script command tables from DSPRE's script databases, each by a committed script. The
text codec does not exist in the C# at all (DSPRE shells out to chatot.exe), so it was rederived
from the charmap and validated by the 829/829 re-encode plus agreement with DSPRE's decoded output
on all 49,984 messages.
Some things are deliberately refused rather than guessed at: growing the fly table (no length field), DP/Pt map header flag bit order (the reference contradicts itself), ground-item names in event files, editing the hidden-item table's length, removing a matrix section, and the side effects of changing a starter. A BLZ compressor was written, measured at 68/127 byte-exact, and deleted rather than shipped.
One practical note for anyone working on this: search the C# reference with grep -a. Four
files under DS_Map/ are not valid UTF-8, and plain grep -r skips them silently. That cost
real work — matrix resizing sat in the known-gaps list for a whole phase as "not in the public
source", when ResizeMatrix was at GameMatrix.cs:122 the whole time.
Further reading: docs/STATE.md is the current-state summary,
docs/PROGRESS.md the full journal of decisions and reversals,
docs/ASSESSMENT.md a deliberately unkind review of this codebase,
docs/PORTING.md the conventions, docs/WSL.md the WSL matrix.
Development
pnpm build # turbo build — tsc across the workspace
pnpm lint # turbo lint — eslint, type-checked
pnpm test # turbo test — node:test, no framework
pnpm dev # core in tsc --watch, server under node --watch
pnpm format # prettierTests that need a real ROM read from a gitignored .fixtures/ directory and t.skip() cleanly when
it is absent, so the suite passes on a machine without one. With fixtures present a full run costs
~30 s against a native dsrom and ~2.5 min against DSPRE's bundled dsrom.exe — almost all of it
the two tests that build a real 134 MB ROM.
Contributing: CONTRIBUTING.md. Releasing (maintainer): push a v* tag; the
full procedure is in README.agents.md.
Legal
Licensed AGPL-3.0-or-later — see LICENSE. That is not a preference: this project
ports DSPRE's binary-format logic, and DSPRE is AGPL-3.0, so the copyleft carries. If you run a
modified version of this server over a network, the AGPL requires you to offer its source to its
users.
This project ships no game data. You must supply your own legally obtained .nds of a game you
own; nothing here contains or distributes copyrighted Nintendo material.
Credits: DSPRE (AGPL-3.0), whose C# source is the
format spec and whose charmap.json and script databases generated the tables here; and
ds-rom (MIT, © Aetias 2025), invoked as an external binary
and not vendored. Full text in NOTICE.
Pokémon, Nintendo, Game Freak and Creatures Inc. are trademarks of their respective owners. This project is not affiliated with, endorsed by, or sponsored by any of them.
This server cannot be deployed
Maintenance
Related MCP Connectors
Build and deploy websites, Telegram and Discord bots from chat via the DreamAgent platform.
Create RF signal projects from prompts, inspect graphs, and export IQ data.
Generate and edit images, video, voice, lip-sync and 3D models from your AI agent.
Develop, manage, and debug Railway projects, services, and deployments from within agents.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables AI agents to directly manipulate RPG Maker MZ projects through natural language commands, allowing creation and modification of game assets like items, weapons, enemies, maps, and plugins without manually editing game files.3670 npm2MIT
- AlicenseCqualityDmaintenanceProvides tools for managing RPG Maker MZ game data, maps, events, and system settings through natural language, enabling AI-assisted game development.3570 npm29MIT
- AlicenseBqualityAmaintenanceEnables AI assistants to read and write RPG Maker MZ projects directly, covering database, maps, events, and system settings with 119 tools.10070 npm6MIT
- AlicenseNot gradedqualityBmaintenanceEnables Codex to control a DeSmuME WebAssembly emulator for Nintendo DS games, including state management, screenshots, and persistent scripting via stdio MCP.MIT