rpgmaker-mz-mcp
This MCP server provides 128 tools that let an AI assistant directly read, author, validate, preview, render, playtest, and export an RPG Maker MZ project without using the editor.
Target a project and inspect/update its game title.
CRUD database records: actors, classes, skills, items, weapons, armors, states, enemies, troops, and common events.
Search, list, get, and batch-create database records in single writes.
Delete records or reset tables with dangling-reference checks.
Manage maps: create, delete, resize, update, map tree, encounters, dimensions, and tile regions.
Paint tiles with autotiling, fill areas, place multi-tile objects, and edit passability/terrain flags.
Use semantic tile catalogs and find tiles by name.
Create/edit map events, pages, NPCs, chests, transfers, and move routes.
Build event-command sequences for dialogue, choices, branches, switches/variables, gold/items/party changes, transfers, audio, screen effects, pictures, animations, battles, shops, name input, and actor changes.
Insert built commands into map events, common events, or troop battle pages.
Work with troop battle events and plugin commands.
List assets and validate asset references.
Validate event structure, project-wide references, and inputs; preview writes with dry-run diffs.
Manage switches/variables: allocate IDs, name them, and inspect usage.
Configure system data: title screen, starting position, party, terms, types, and currency.
Export a pruned HTML5 web build for static hosting or itch.io.
Headless render maps and run scripted playtests with screenshots, dialogue, choices, walking, battles, and error reporting.
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., "@rpgmaker-mz-mcp Add a town under the world map, paint it with grass, and drop in a shopkeeper who sells potions"
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.
RPG Maker MZ MCP Server
128 tools that let an AI assistant read and write an RPG Maker MZ project directly — actors, classes, skills, items, equipment, states, enemies, troops, common events, maps, tiles, tilesets, events, and system settings — instead of hand-editing everything in the editor.
"Add a town under the world map, paint it with grass, and drop in a shopkeeper who sells potions" → done, in-project, no editor clicks.
Quick start
Claude Code (recommended) — installs the server and the authoring skills as one plugin:
claude plugin marketplace add Redseb/rpgmaker-mz-mcp
claude plugin install rpgmaker-mz@rpgmaker-mz-mcpYou'll be prompted for your RPG Maker MZ project directory (optional — you can also just ask Claude to set_project later).
Any other MCP client — the server is on npm; no clone or build needed:
{
"mcpServers": {
"rpgmaker-mz": {
"command": "npx",
"args": ["-y", "rpgmaker-mz-mcp@latest"],
"env": { "RPGMAKER_PROJECT_PATH": "/path/to/your/rpgmaker/project" }
}
}
}Claude Desktop — either the JSON config above, or download the one-click rpgmaker-mz-mcp.mcpb bundle from Releases and open it with Claude Desktop.
New here? Read SETUP.md for the full walkthrough and EXAMPLES.md for end-to-end recipes.
Related MCP server: RPG Maker MZ MCP Server
Contents
Capabilities
Database CRUD — actors, classes (with learnings & param curves), skills (full-control + simplified damage/heal/buff/state helpers), items, weapons, armors, states, enemies, and troops. Only a
nameis required to create; everything else falls back to the editor's true "New X" template.Maps & the map tree — create/delete maps, batch-reparent/reorder/rename with a cycle guard, and edit map properties. New maps register in
MapInfos.jsonexactly as the editor expects.Tile painting (with automatic autotiling) —
paint_tiles/fill_areaset tiles on any of the six map layers and recompute autotile shapes (and their neighbours') from same-kind adjacency, so a filled region borders itself correctly.paint_blueprintpaints a whole area from ASCII rows + a legend in one call (multi-layer cells, catalog names, A4 wall faces derived automatically) and returns a passability overview.place_objectstamps multi-tile B/C objects (houses, trees) and reports their passability footprint.Semantic tile catalog —
find_tile "grass"→ a paintable tile id. Built-in catalogs for every default tileset (Overworld, Outside, Inside, Dungeon, SF), sourced from RPG Maker's own English name sidecars. A bundled vision-bootstrap skill catalogs custom tilesets.Passability & terrain — read a tile's flags or a map cell's layered passability (
get_tile_flags/check_passability), and edit passability/terrain-tag/behaviour flags (set_tile_flags).Event-command builders — high-level, read-only builders that emit the exact
EventCommandsequences the editor writes (including tricky recursive branch blocks and continuation rows), landed on a page viainsert_event_commands. Covers dialogue & flow, game-state changes, presentation/transitions, and scene processing.Event & NPC ergonomics —
create_npcplaces a complete talking NPC in one call;set_event_pagemerges a page's graphic + behavior in place.Asset awareness —
list_assetsenumerates valid character/face/tileset/audio names so events never reference a missing file.See and play the build —
render_mapscreenshots a map exactly as the engine draws it (whole map or a game-screen view) andrun_playtestdrives a scripted headless session (load a state, trigger events, read dialogue, pick choices, walk, auto-battle, screenshot), both reporting console errors and missing assets. Validators prove structure; these show what the player sees.Correctness layer — Zod-validated inputs, throw-by-default event validation (a structurally invalid write is refused, not saved-and-warned-about), a cross-file reference linter (
validate_references), and a dry-run/diff preview on every write.
How it fits together
Installation
Pick one:
Claude Code plugin (recommended) —
claude plugin marketplace add Redseb/rpgmaker-mz-mcp, thenclaude plugin install rpgmaker-mz@rpgmaker-mz-mcp. This bundles the MCP server (run via npx from the npm package) together with the two authoring skills (rpgmaker-authoring,tileset-catalog) — the skills carry the judgment the tools don't enforce, so this is the full experience.npm package — configure your MCP client to run
npx -y rpgmaker-mz-mcp@latest(see Quick start). Tools only, no skills.MCPB bundle (Claude Desktop) — download
rpgmaker-mz-mcp.mcpbfrom Releases, open it with Claude Desktop, and pick your project folder in the install dialog.From source (development):
npm install
npm run buildConfiguration
Set the RPG Maker MZ project path as an environment variable:
# macOS/Linux
export RPGMAKER_PROJECT_PATH=/path/to/your/rpgmaker/project
# Windows
set RPGMAKER_PROJECT_PATH=C:\path\to\your\rpgmaker\projectThe path must point to a directory containing game.rmmzproject and a data/ directory with System.json.
The environment variable is only the startup default: the set_project tool can retarget a running server at a different project (and get_project reports the current one), so switching games doesn't require editing config or restarting.
Usage
Running the server
npm start # or: node dist/index.jsConfiguring in Claude Desktop
The easiest path is the .mcpb bundle from Releases — open it with Claude Desktop and pick your project folder. To configure by hand instead, add to your Claude Desktop configuration file (%APPDATA%\Claude\claude_desktop_config.json on Windows, ~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"rpgmaker-mz": {
"command": "npx",
"args": ["-y", "rpgmaker-mz-mcp@latest"],
"env": {
"RPGMAKER_PROJECT_PATH": "/path/to/your/rpgmaker/project"
}
}
}
}(For a from-source checkout, use "command": "node" with "args": ["/path/to/rpgmaker-mz-mcp/dist/index.js"] instead.)
Available tools
All 128 tools, grouped by area. Tools that write to the project accept an optional dryRun argument (see Dry-run preview); those that can refuse a structurally invalid write also accept force (see Event validation).
Project targeting
get_project— the project the server is operating on: path, validity, game titleset_project— retarget the server at another project directory for the rest of the session (no restart; overridesRPGMAKER_PROJECT_PATH)
Actors
create_actor,update_actor,search_actors
Classes
create_class,update_classadd_class_learning— attach a skill learned at a level (validates the skill, keeps learnings level-sorted)set_class_param_curve— replace one of the 8 parameter growth rows
Skills
create_skill(full control — every Skills.json field incl.occasion,hitType,speed,repeats,successRate,tpGain, required weapon types,message2,note;hitTypedefaults to magical for Magic skills, physical for other damage, certain for heals/ally scopes),update_skill,search_skillscreate_damage_skill,create_healing_skill,create_buff_skill,create_state_skill— natural-language-friendly helpers for common skill types
Items & equipment
create_item,update_item,search_itemscreate_weapon,update_weaponcreate_armor,update_armor
States
create_state,update_state
Enemies & troops
create_enemy,update_enemy,search_enemiescreate_troop,update_troop,search_troops—create_troopvalidates that every member references an existing enemybuild_troop_page— build a battle-event page{ conditions, list, span }from a compact trigger (when:turn [a, b],enemyHpBelow [slot, pct],actorHpBelow [actorId, pct],switch,turnEnd— ANDed) and aspan(battle/turn/moment), no hand-built 12-field conditions object. Read-onlyadd_troop_page— append (or insert atposition) one page to a troop without re-sending the others; warns on an HP condition pointing past the troop's members
Common events
create_common_event,update_common_eventcall_common_event— builds the code-117 call command and validates the target exists
Maps & the map tree
get_map(passincludeData: falseto omit the tile array on a big map),get_map_infos,get_map_dimensions,update_mapget_map_region— read a window of tile ids (x, y, width, height, layer) instead of the whole mapcreate_map— allocates the next id, writes a blank map, and registers it in the treedelete_map— removes a map and reparents its children onto its parentupdate_map_tree— batch reparent/reorder/rename/expand with an up-front existence check and cycle guard
Map events
get_map_events,get_map_event,search_map_eventscreate_map_event,update_map_event,delete_map_eventadd_event_command— append a single command to an event pageset_map_tile— set a single raw tile id at (x, y) on a z-layer (no autotiling)
Event & NPC ergonomics
create_npc— one-shot "talking NPC": graphic + trigger + a talk list fromtext(optionally auto word-wrapped withwrap) or explicitcommandscreate_chest— one-shot treasure chest: the two-page self-switch idiom (give item/weapon/armor/gold, then never again)create_transfer— one-shot map transfer, in either working idiom: face a solid landmark (action_button) or step on a doormat (player_touch)set_event_page— merge a page's graphic + behavior (sprite, trigger, priority, movement, flags) in place
Event-command builders
Read-only builders that return editor-faithful EventCommand sequences; land them on a command list with insert_event_commands.
Dialogue & flow:
build_show_text(101/401),build_show_choices(102/402–404),build_conditional_branch(111/411/412),build_flow_command(wait/exit/label/jump)Game state:
build_control_switch(121/123),build_control_variable(122),build_change_gold(125),build_change_items(126–128),build_change_party_member(129)Presentation & transitions:
build_transfer_player(201),build_play_audio(BGM/BGS/ME/SE),build_screen_effect(fade/tint/flash/shake),build_picture(show/erase),build_character_effect(animation/balloon)Scenes:
build_battle_processing(301),build_shop_processing(302/605),build_name_input(303),build_change_actor(HP/MP/state/recover/EXP/level, 311–316)Battle (troop pages):
build_battle_command— enemy appear (335, reveal a hidden member), change enemy state (333, one slot or the whole troop), abort battle (340)Insertion:
insert_event_commands— splice a built sequence into a map event page (the defaulttarget), a common event body, or a troop battle-event page, then validate
Move routes
create_move_route— build aMoveRoutefrom a named pattern (patrol/approach/flee/wander/custom)set_movement_route— insert a forced Set Movement Route (code 205 + 505 continuation rows)
Plugin commands
scan_plugins— discover the plugin commands this project actually has, by parsingjs/plugins/*.jsannotations (+ enabled state fromjs/plugins.js)list_plugin_commands— view the known plugin commands (the project scan merged over a built-in allowlist)create_plugin_command— build a code-357 plugin command with normalized args
Tiles, catalog & painting
describe_tile— decode a raw tile id (sheet, autotile kind/shape, geometry)get_tile_catalog,find_tile— resolve human names ↔ paintable tile ids (find_tilecan widen the search to a custom sheet's catalog descriptions withsearchDescriptions)paint_tiles,fill_area— paint with automatic autotilingpaint_blueprint— paint a whole area from an ASCII blueprint + legend in one write:[layer, tile]pairs per glyph, catalog names instead of ids,{ wall: { top } }entries whose vertical runs get their bottom cell turned into the wall-side (face) kind (top + 8 kinds), stale upper layers cleared; returns per-layer counts and a#/.passability mapplace_object— stamp a multi-tile B/C object and report its passability footprint
Tileset flags (passability / terrain)
get_tile_flags— decode a tile's passability/star/ladder/bush/counter/damage/terrain-tagcheck_passability— the map-aware, layered answer for a cellset_tile_flags— edit a tile's flags (non-destructive merge; auto-applies to all 48 shape slots of an autotile kind)
Assets
list_assets— enumerate available asset basenames (characters, faces, tilesets, pictures, audio, …)
Web export
export_web— build a pruned HTML5 deployment for itch.io or any static host:index.html,js/,css/,fonts/,icon/anddata/*.json, plus only theimg//audio//movies/files something references (every string in the data files, string literals in the core engine scripts and plugins, plugin@defaults;img/system/is always kept, and every.ogg/.m4avariant of a kept track). Effekseer effects are pruned the same way: aneffects/*.efkefcis kept only if its name is a real effect reference (an animation'seffectName, a Plugin Command argument in an event, or a plugin parameter/string — not other data strings, so a state or animation namedPoisondoesn't pull inPoison.efkefc), together with the textures/models it lists inside the file; if a kept effect can't be parsed, all ofeffects/' textures and models are kept. When nothing references an effect, noeffects/folder is exported. Writes the folder tooutDirand, withzip(default),<outDir>.zipwithindex.htmlat the archive root. Returns file/byte counts, kept/dropped asset counts and paths (effects included), the screen size fromSystem.advanced(use it as the itch embed size), and warnings past itch's 1000-file / 200 MB-per-file limits.prune: falsecopies every asset — use it if a plugin builds asset names at runtime. Writes nothing inside the project;outDircan't be the project or sit inside a folder it copies, and an existing non-emptyoutDiris only replaced if it's a previousexport_weboutput.
Headless render & playtest
Boots the project's own index.html in a headless Chromium to check what validators can't: how a map looks and how it plays. Read-only — nothing is written into the project; PNGs go to <os tmpdir>/rpgmaker-mz-mcp/renders/ unless you pass out. Pass inline: true to also get the PNG(s) back as image content in the tool response.
render_map— screenshot one map. By default it renders the whole map in one image (the canvas is resized towidth×height×48px, the player is hidden, autorun/parallel events are frozen so a cutscene can't cover the map, and the map-name banner is off). Passx+yto get a normal 816×624 game-screen view centred on that tile instead (the player is shown).showEvents: falsedraws bare tiles;switchesturns switches on first to see a later story state;runEvents: truelets events run. Returns the PNG path andproblems: console errors, page errors, and HTTP 404s (a missing image is drawn blank and listed there instead of stopping the engine on its load-error screen). Maps over 4800 px on a side need thex/yview.run_playtest— run a script of steps in one browser session. Each step returnsokplus details, and the run stops at the first failing step:load{mapId, x, y, direction?, party?, level?, gold?, switches?, variables?, selfSwitches?, items?, equip?, encounters?}starts a new game at that spot with that state. Random encounters stay off unlessencounters: true.startEvent{eventId}triggers a map event and lets it run until it shows text or goes idle. If the event transfers the player, the step waits for the new map and reports it astransferredTo{mapId, x, y}.advanceText{maxMs?}presses OK until the event goes idle. It stops early at an open choice list or a battle, and returns the message lines shown (with speaker names) and any open choices. Text shown during a battle comes back separately asbattleLines, so it isn't mixed into the map event's dialogue.choose{index}picks a 0-based choice.walk{direction, steps?}walks tile by tile and reports the tile it ended on (to). If a tile refused entry, it reports both the player's tile (stoppedAt) and the tile that refused (blockedTile), which is how you find invisible walls. It stops early when a touch event fires; if that event is a door, it waits for the transfer to finish, sotoandtransferredToare on the new map.eventRunning/messageOpensay the event is still going (follow up withadvanceText).press{button, times?}andwait{ms}.autoBattle{troopId?, canEscape?, canLose?, maxMs?}fights a battle that has already started, or startstroopId, on auto AI, giving up aftermaxMs(default 60 s). It reportsvictory/defeat/escaped, the final HP of both sides, and the battle's messagelines(troop battle events, victory text). Battles are fast-forwarded: the engine runs 20 frames for every frame it draws, so the fight plays out exactly as it would (same logic, same odds), only faster. A 10-turn boss fight takes about 5 s instead of 80 s. Passrealtime: trueon the run to watch battles at normal speed, and raisemaxMsto match. Only battles are sped up; the map, walking and dialogue run at normal speed.screenshot{name?}saves a PNG.eval{script}returns the value of a JS expression evaluated in the game page, such as"$gameSwitches.value(3)".
Reported text (
lines,battleLines,choices, speaker names) reads the way the message window shows it.\V[n],\N[n],\P[n]and\Gare filled in from the game state at the time, and control codes such as\C[n],\I[n],\{,\.and\|are removed, so victory text comes back as92 EXP received!.The response ends with
finalState(scene, map, position, gold, party) andproblems.startEventandautoBattlerefuse to start while an event or message is still running (for example, a map's autorun cutscene right afterload) and tell you toadvanceTextfirst.
Requirements. Both tools need playwright-core. It's an optional dependency, so a failed install never breaks the other tools; these two just return an error that tells you how to fix it. They also need a Chromium. No browser is downloaded: the server uses the newest chrome-headless-shell (or full Chromium) in the Playwright cache (~/Library/Caches/ms-playwright, ~/.cache/ms-playwright, %LOCALAPPDATA%\ms-playwright, or PLAYWRIGHT_BROWSERS_PATH). If you don't have one, run npx playwright install chromium-headless-shell, or set RPGMAKER_MCP_CHROMIUM to any Chrome/Chromium executable. Each call takes about 1–2 s to boot, plus however long the script runs.
Long runs. A run_playtest script with long cutscenes or realtime battles can take a minute or more, which is longer than many MCP clients wait by default (the TypeScript SDK gives up after 60 s with -32001 Request timed out). If the client sends a progressToken, the server sends a progress notification for each step and every 5 s during long ones, so a client using resetTimeoutOnProgress (or a longer timeout) keeps waiting. If your client can do neither, split the script into several shorter runs.
System & vocabulary
get_system,get_game_title,update_game_titleget_title_screen,update_title_screen— background layers, BGM, and the "draw game title" toggleget_variables,set_variable_name,get_switches,set_switch_nameget_starting_position,update_starting_positionget_party,set_party— the starting party (set_partyvalidates every actor id)get_terms,set_term— menu vocabularyget_types,set_type_name— element/skill/weapon/armor/equip type-name listsset_currency_unit
Batch creation
batch_create— create many records of one type (actors, items, weapons, armors, skills, enemies, states, classes) in a single call and a single file write; ids allocate sequentially, so a record can reference a sibling made earlier in the same batch; record fields the matchingcreate_*tool doesn't accept come back as warnings instead of vanishing silently
Deleting records
delete_record— delete one database record (actor, class, skill, item, weapon, armor, enemy, troop, state, common event) by nulling its slot, so no other id shifts; reports every reference the deletion would leave dangling and refuses when there are any unlessforce: truereset_table— clear a whole table except the ids inkeep(e.g.reset_table('skill', { keep: [1, 2] })wipes the RTP skills but keeps Attack/Guard); kept records stay at their own id, trailing empty slots are trimmed, and it refuses on dangling references the same way
Index & validation
list_names— cheap{ id, name }index for a table (actors, items, skills, maps, enemies, …)get_database— full records from one table (actors, classes, items, weapons, armors, skills, enemies, troops, states, common_events), or a single record byidvalidate_event,validate_project— event-command-shape validation (read-only)validate_references— cross-file id-integrity audit (party→actor, transfer→map, effect→state/skill/common-event, drops→item, Change Items/Shop/Battle Processing→item/troop, encounters→troop, map-tree cycles, …)
ID allocation
list_allocated_ids— which switch / variable / common-event IDs are already spoken for, derived from the project's own JSON; withid, every place that one is referencednext_free_id— reserve the next unallocated ID(s) instead of picking one by hand
Input validation
Every tool declares its arguments as a Zod schema. The server (built on the MCP SDK's high-level McpServer) validates incoming arguments against that schema before a handler runs, so malformed calls are rejected with a clear Input validation error naming the offending field instead of writing garbage to disk.
Event validation (throw-by-default)
Event command lists are checked against a table of known RPG Maker MZ command codes (101 Show Text, 201 Transfer Player, 122 Control Variables, …), and against the block structure those commands form. Findings come in two tiers, and the tier decides what happens to the write:
Structural — a wrong parameter count for a known command (including the counts that depend on a Conditional Branch's condition type or a Control Variables operand type), a list not terminated by the code-
0end marker, a non-arrayparameters, a broken block (a Show Choices/Conditional Branch/Loop that is never closed, a branch or closer row orphaned or written at the wrong indent, a choice with noWhenbranch), or an action-button event stranded on an impassable tile. These are almost always bugs, so the event-writing tools validate the would-be result before committing and refuse the write: the tool errors and nothing reaches disk. Passforce: trueto write anyway (the argument is advertised on exactly the tools that can refuse).Advisory — an unrecognized command code (which may simply be a plugin command), an over-long text line, an unknown asset filename, a choice block whose Cancel routing and
When Cancelbranch disagree (dead code, not corruption). These are legitimately possible, so they never block; they ride along aswarningson the normal response.
Because the check runs before the commit, a dryRun of a write that would be refused fails too, rather than previewing a write that could never happen.
validate_event / validate_project remain read-only audits: they report both tiers (each finding carries a severity) without changing anything.
Text width: teaching it your font
The over-long-text-line warning is measured in characters by default — 55 per line, 38 when a face graphic is shown — which suits the stock RTP font and needs no setup. If your project ships a different font, that estimate goes wrong in one of two directions: a narrower font makes it warn on lines that fit comfortably, and a wider or larger one makes it stay quiet on lines that really are cut off (38 characters of a 24px glyph is 912px in a 616px window). No single character limit fixes both, because glyph widths in a proportional font span a wide range — a full stop can be a third the width of a capital.
Drop a .rpgmaker-mcp.json in the project root to replace the estimate with a real measurement:
{
"text": {
"lineBudget": { "noFace": 784, "withFace": 616 },
"nameBudgetChars": 8,
"charWidths": { "_default": 13, "a": 11.38, ".": 4.88, " ": 8.12 }
}
}lineBudget— the message window's usable width, without and with a face graphic. In pixels if you givecharWidths, otherwise in characters (a barelineBudgetis just a character-limit override).charWidths— per-character advance;_defaultcovers anything unlisted. Get these from the engine itself:Window_Base.textWidth(c.repeat(40)) / 40in a running game is exact.nameBudgetChars— how wide to assume\N[3]/\P[1]renders. A name is typed by the player at runtime, so budget the Name InputmaxLength(usually 8) rather than the default name, or a long name overflows a line that fitted while you were testing. Defaults to0, which ignores name escapes as before.
Everything fails soft: no file, bad JSON, or a malformed text section leaves the built-in estimate in place, so a broken config is never worse than no config. The file is re-read when its mtime changes, and warnings then report real widths (Show Text line is 650px but the message window fits 616px with a face shown).
Auto-wrap. Rather than fixing overflowing lines by hand, pass wrap: true to build_show_text or create_npc and write whole paragraphs: the text is word-wrapped to exactly the width the warning checks (the default estimate or your .rpgmaker-mcp.json metrics; escape codes like \C[n] never count or get split) and split into as many 4-line message boxes as needed, each with the same face/speaker. wrap: true (or "soft") reflows every entry as one paragraph; "hard" keeps each entry and \n as a forced line break and only wraps lines that are too long.
Reference linting
validate_references performs a cross-file id-integrity audit — orthogonal to the command-shape check above. It walks the whole database and flags references that point at something that doesn't exist: a starting party member with no matching actor, a Transfer Player targeting a missing map, a skill effect that adds a non-existent state, an enemy dropping an unknown item, a cyclic map-tree parent, and more. Every check is warn-by-default and guarded against false positives on partially-loaded projects.
Deleting records and resetting tables
A new MZ project ships RTP-flavoured database rows whose icons, animations and battlers point at RTP art. When you replace the art wholesale, the natural workflow is "clear the database, then author my own" — reset_table is that first step, and delete_record removes a single row.
Database arrays are index = id, so both tools null the slot rather than splice: nothing is renumbered, and no surviving reference silently starts pointing at a different record. reset_table keeps each keep id at its own index and trims trailing empty slots (a table with nothing kept becomes [null]); new records from create_* / batch_create then allocate from the highest live id.
Before writing, both tools work out which references the removal would leave dangling, by running the validate_references audit with and without the removed rows and keeping only the findings the removal introduces (references that were already broken aren't blamed on it). Removing skill 1 (Attack), skill 2 (Guard) or state 1 (Knockout) is always reported too, since the engine hard-codes those ids. If anything would dangle, the write is refused and nothing reaches disk — pass force: true to go ahead anyway, or dryRun: true to preview what disappears and what would break (a dry-run reports requiresForce instead of throwing). The scan covers what validate_references covers and says so in a coverage field: traits, actor starting equipment, event page conditions, Conditional Branch operands, and Script/plugin commands are not scanned.
reset_table({ type: 'skill', keep: [1, 2], dryRun: true }) // what goes, what breaks
reset_table({ type: 'skill', keep: [1, 2], force: true }) // do it
batch_create({ type: 'skill', records: [...] }) // author the replacementsID allocation
Switches, variables and common-event IDs are one global namespace, and nothing in RPG Maker stops a later edit from claiming an ID an earlier one already used. The failure is silent — no crash, no validator hit, just a door that is inexplicably already open hours into a playtest.
list_allocated_ids answers "what's taken?" from the project files themselves — never a hand-maintained list, which would drift the moment someone edited in the RPG Maker editor. An ID counts as allocated if it is declared (a System.json label, a CommonEvents row) or referenced anywhere: event page conditions and command lists, common events, troop pages, and Common Event skill/item effects. Both halves matter — a named-but-unused switch is a claim someone staked, and a used-but-unnamed one is a claim nobody wrote down. Pass id to ask the narrower question: where is switch 23 actually used, before I touch it?
next_free_id hands back the next unallocated ID(s), strictly above everything already taken. Holes below the highest ID are left alone by default (a hole is often an ID claimed in notes but not yet written); reuseGaps: true fills them when you're compacting deliberately. It's read-only — it suggests IDs, it doesn't write them, so name what you take with set_switch_name / set_variable_name to make the claim visible to whoever edits next. Those two grow the System.json name list when the ID is past the end, so an ID from next_free_id can always be labelled without opening the editor.
Like the command validator, the usage scan is curated, not exhaustive: it covers the commands that carry switch/variable IDs (Control Switches/Variables, Conditional Branch, the "designation by variable" forms of Transfer Player, Change Gold/Items, Change HP/MP/EXP/Level, …), and every report states the command codes it scanned. An ID used only from a Script (355) or a plugin command (357) will read as free.
Dry-run preview
Every tool that writes to the project accepts an optional dryRun argument. When dryRun: true, the tool computes what it would write and returns a diff instead of touching any files:
{
"dryRun": true,
"wouldChange": [
{
"file": "System.json",
"changed": true,
"diff": {
"changes": [{ "path": "gameTitle", "from": "Old Title", "to": "New Title" }],
"truncated": false
}
}
],
"wouldReturn": { "...": "what the tool would have returned, warnings included" }
}wouldReturn carries the response the tool would have produced, so a dry-run also previews the validation warnings a write would have reported — not just the diff.
All writes go through a single choke point that skips no-op writes and keeps the on-disk JSON in the editor's compact single-line format. File deletions (e.g. delete_map) share the same dry-run machinery.
Quiet write echoes
A write tool that echoes the whole record back costs the one caller that always pays for it — an AI assistant, whose context is the scarce resource. So the tools that would otherwise replay a command list or a map's events return a summary by default:
tool | echoes |
| the map without its tile |
| event identity + per-page |
|
|
| identity, trigger wiring, |
| identity, members, per-page |
The rule: keep what you would assert on, drop what you would only re-read. Command codes stay, because they are how you verify a splice landed where you asked (is the 302 still after the two 101s); command parameters go, because they are what you just wrote.
Pass verbose: true on any of those calls for the old full record, or read it back with get_map / get_map_event / get_database. warnings always survive summarization, and a dry-run's wouldReturn is summarized the same way so a preview and the real call report the same shape.
Measured on six calls from one real authoring session: 115,080 → 3,672 characters (-97%). A single update_map that set a map's BGM was echoing 46,846 characters of dialogue back at the caller.
Custom-tileset catalog skill
The default tilesets are cataloged out of the box. A non-default sheet that ships an RPG Maker .txt name sidecar next to it (img/tilesets/<Sheet>.txt, one Name|日本語名 line per tile — commercial DLC packs include these) is cataloged automatically too: its names come back with source: 'sidecar', no catalog files needed. Precedence per tile: a human-verified (manual) data/tilecatalog/ entry > the sidecar > a vision draft. For a custom (non-RTP) tileset with no sidecar, a bundled Claude skill under .claude/skills/tileset-catalog/ slices each sheet into labelled samples, has Claude vision-name them, and writes a versioned, project-scoped catalog to data/tilecatalog/ — after which find_tile/get_tile_catalog resolve names for that sheet too. Those drafts also record what each tile looks like, so find_tile with searchDescriptions: true can match that text when a machine-drafted name is too terse to search by. The skill ships a dependency-free PNG codec and engine-exact tile geometry, so it runs anywhere Node does.
Example prompts
Once configured, drive your project in natural language:
"Create a fire skill 'Fireball' costing 15 MP that deals
a.mat * 4 - b.mdf * 2to one enemy.""Add a new town map under the world map, 30×25, using the Outside tileset."
"Paint grass in a 10×8 rectangle at (4, 4) on map 3 and let it auto-border."
"Place a talking NPC named 'Guard' at (8, 5) on map 2 who says 'Halt! Who goes there?'"
"Make the water tiles on tileset 1 impassable and tag them terrain 1."
"Check my project for broken references before I ship."
Development
npm run build # Compile TypeScript to dist/
npm run typecheck # Type-check without emitting (tsc --noEmit)
npm run dev # Compile in watch mode
npm run lint # ESLint
npm run lint:fix # ESLint with autofix
npm run format # Format with Prettier
npm run format:check # Check formatting (used in CI)
npm test # Vitest
npm run sync:tools # Re-stamp the tool count into the README + SVGs (see below)
npm run sync:version # Re-stamp package.json's version into the packaging manifests
npm run bundle:mcpb # Build the one-click Claude Desktop bundle (rpgmaker-mz-mcp.mcpb)During development you can skip the build entirely by running the server from source with tsx: point your MCP client's command at node_modules/.bin/tsx with src/index.ts as the argument. Since tsx doesn't type-check, run npm run typecheck alongside lint and tests before committing.
CI runs lint, format check, tool-count sync check, tests, and build on every push and pull request (see .github/workflows/ci.yml).
Keeping the tool count in sync
The advertised tool count lives in a few human-facing spots — the README prose and badge, and the two SVGs in assets/. npm run sync:tools counts the real tools from src/tools/ and re-stamps all of them, so bumping the number after adding a tool is one command. npm run sync:tools:check (run in CI) fails if any spot is stale.
Releasing
package.json is the source of truth for the version; npm run sync:version stamps it into the plugin manifest (.claude-plugin/plugin.json), the MCP-registry metadata (server.json), and the MCPB manifest (mcpb/manifest.json). CI and prepublishOnly fail if they drift. A release is:
npm version minor --no-git-tag-version # or patch/major — bumps package.json only
npm run sync:version # stamp it into the other three manifests
git commit -am vX.Y.Z # one commit, with every manifest already correct
git tag vX.Y.Z # tag it afterwards, so nothing rewrites it
git push && git push origin vX.Y.Z
npm publish # publish to npm (runs the full gate via prepublishOnly)
mcp-publisher publish # update the MCP registry listing (server.json; login: mcp-publisher login github)
npm run bundle:mcpb # build rpgmaker-mz-mcp.mcpb
gh release create vX.Y.Z rpgmaker-mz-mcp.mcpb --title vX.Y.Z --notes "..." # publish the GitHub release + attach the bundleThe Claude Code plugin needs no separate publish — users' installs update from this repo (the plugin runs the npm package via npx rpgmaker-mz-mcp@latest, so bumping npm is what ships new tools).
Tag last, and never amend a tagged commit. npm version on its own commits and tags before sync:version has stamped the other manifests, so the old recipe amended afterwards — which left the tag pointing at the pre-amend commit, with stale manifests and off the branch entirely. --no-git-tag-version avoids the whole problem: one commit, then the tag. Push the tag by name (--follow-tags is easy to get wrong here), and don't skip gh release create — nothing before it creates the GitHub release.
Project structure
rpgmaker-mz-mcp/
├── src/
│ ├── index.ts # McpServer bootstrap: registers every tool, dispatch + dry-run
│ ├── registry.ts # ToolDefinition shape + shared dryRun schema
│ ├── tools/ # One module per area (actors, items, skills, maps, battle,
│ │ # classes, states, common events, moves, plugins, tiles,
│ │ # catalog, paint, objects, tilesets, system, assets,
│ │ # event-command builders, event pages, list, validation)
│ ├── events/ # Pure event-command builders (no I/O)
│ ├── tiles/ # Tile subsystem: codec, autotile solver, paint core,
│ │ # flag codec, and the semantic catalog
│ ├── playtest/ # Headless engine driver: Chromium discovery, static server,
│ │ # render_map + run_playtest (optional playwright-core)
│ ├── validation/ # Known-command tables + event/move/plugin/reference validators
│ └── utils/ # File I/O, the commit choke point, and RPG Maker MZ types
├── test/ # Vitest suite
├── scripts/
│ └── sync-tool-count.mjs # Re-stamps the tool count into the README + SVGs
├── assets/ # Banner + architecture SVGs
├── .claude/skills/
│ └── tileset-catalog/ # Vision catalog-bootstrap skill for custom tilesets
├── dist/ # Compiled JavaScript (gitignored)
└── README.mdSafety and best practices
Close the RPG Maker MZ editor while using this server — it writes JSON files directly, and the editor can overwrite changes on save.
Use version control for your project. Combined with dry-run previews and validation, git is the safety net (the server does not make automatic backups).
Preview destructive edits with
dryRun: truebefore committing them.Test in-engine after significant changes.
Limitations
Writes JSON files directly; the editor must be closed to avoid conflicts.
Plugin commands are validated against the plugins your project actually ships (
scan_pluginsparses their@command/@argannotations), falling back to a small built-in allowlist. Since RPG Maker MZ has no "required argument" annotation, scanned args are checked for unknown names only, never for missing ones; a plugin with no annotation block passes through unchecked.Animations (
Animations.json, Effekseer-based) are not edited by this server.
Acknowledgements
This project started life as a fork of k4zuki0539/-rpgmaker-mz-mcp (MIT), which provided the original CRUD scaffolding. It has since grown well beyond that starting point — into full vanilla level-design and game-logic authoring (see Capabilities) — and is now maintained as its own project. Thanks to the original author for the foundation.
License
Resources
Available Tools
128 toolsadd_class_learningA
Add a "learn skill at level" entry to a class (replaces the hack of attaching skills to an actor via an Add-Skill trait). Validates the skillId exists and keeps the learnings sorted by level. Warns (never blocks) when the skill's stypeId is not covered by an Add Skill Type trait ({ code: 41, dataId: stypeId, value: 1 }) on the class — without it the skill-type command never appears and actors cannot use the skill.
Inputs: level (required), classId (required), skillId (required), note, +1 more.
add_event_commandA
Add a command to an event page. Refuses the write (nothing is saved) if the resulting page is structurally invalid — e.g. the command has the wrong parameter count for its code. Pass force: true to override.
Inputs: mapId (required), command (required), eventId (required), pageIndex (required), +4 more.
add_troop_pageA
Append one battle-event page (e.g. the page from build_troop_page) to an existing troop without re-sending its other pages; position inserts it at that 0-based page index instead (the first page whose conditions hold runs, so order matters when triggers overlap). A structurally invalid page refuses the write (nothing is saved) — pass force: true to override; an HP condition on a troop slot past the troop's members, or a page with no condition enabled, is warned (never blocked). Returns { troop, pageIndex, warnings? }; fill it further with insert_event_commands target "troop_page".
Inputs: page (required), troopId (required), force, dryRun, +2 more.
batch_createA
Create many database records of one type in a single call and a single file write — the batch sibling of create_actor/create_item/create_weapon/create_armor/create_skill/create_enemy/create_state/create_class. Each entry in records takes the same fields its single create_* tool accepts (only name is required for most; omitted fields use the editor's defaults). Ids are allocated sequentially from the current max, so a record can reference a sibling created earlier in the same batch. Use this instead of N sequential create_* calls when authoring a cast, a loot table, or a skill list. Returns { type, count, created, warnings? } (classes are summarized like create_class; enemy battlerName misses and record fields the create_* tool doesn't accept are warnings, never blocked). Throws — writing nothing at all — if any record references a database id that does not exist, naming the offending records[i].
Inputs: type (required), records (required), dryRun.
build_battle_commandA
Build an in-battle event command for a troop battle-event page (see build_troop_page / add_troop_page / insert_event_commands target "troop_page"): enemy_appear (335 — reveal a troop member added with hidden: true, i.e. a summon/reinforcement), enemy_state (333 — add/remove a state on one troop member or the whole troop, e.g. a telegraph "Gathering power" state), or abort_battle (340 — end the battle with no victory/defeat; the calling Battle Processing takes its Escape branch). enemyIndex is the 0-based troop slot (members[] order), NOT an enemy id; enemy_state also accepts -1 = entire troop. Read-only: returns { command }.
Inputs: kind (required), indent, stateId, enemyIndex, +1 more.
build_battle_processingA
Build a Battle Processing (301) event command for insertion via insert_event_commands — start a battle against a troop (direct id, a variable holding the id, or "random" like the map encounters). canEscape/canLose gate the battle result branches. Read-only: returns { command }.
Inputs: troop, indent, canLose, troopId, +1 more.
build_change_actorA
Build an actor stat-change scene command for insertion via insert_event_commands: hp (311), mp (312), state (313), recover_all (314), exp (315), or level (316). Targets a fixed actor (0 = whole party) or a variable. hp/mp/exp/level take an increase/decrease operand (constant or variable); state takes add/remove + stateId; recover_all takes nothing extra. Read-only: returns { command }.
Inputs: kind (required), target (required), indent, operand, +5 more.
build_change_goldA
Build a Change Gold (125) event command for insertion via insert_event_commands — increase or decrease party gold by a constant or variable amount. Read-only: returns { command }.
Inputs: operand (required), operation (required), indent.
build_change_itemsA
Build a Change Items (126), Change Weapons (127), or Change Armors (128) event command for insertion via insert_event_commands — gain/lose an item/weapon/armor by a constant or variable amount. includeEquip (weapon/armor only) also counts equipped copies when removing. Read-only: returns { command }.
Inputs: id (required), kind (required), operand (required), operation (required), +2 more.
build_change_party_memberA
Build a Change Party Member (129) event command for insertion via insert_event_commands — add or remove an actor from the party. initialize (add only) resets the actor to their initial state. Read-only: returns { command }.
Inputs: actorId (required), operation (required), indent, initialize.
build_character_effectA
Build a Show Animation (212) or Show Balloon Icon (213) event command for insertion via insert_event_commands, played over a character (characterId: -1 player, 0 this event, N event id). Read-only: returns { command }.
Inputs: id (required), kind (required), characterId (required), wait, +1 more.
build_conditional_branchA
Build a Conditional Branch block (111 condition + then-branch + optional 411 Else + 412 closer, each branch terminated like the editor) for insertion via insert_event_commands. Condition types: switch, self_switch, variable, actor_in_party, gold, item. Provide thenBranch/elseBranch as EventCommand[] (e.g. from other builders). Read-only: returns { commands }.
Inputs: condition (required), indent, elseBranch, thenBranch.
build_control_switchA
Build a Control Switches (121) or Control Self Switch (123) event command for insertion via insert_event_commands. scope "switch": set a switch (or the inclusive switchId..endId range) on/off. scope "self_switch": set the current event's self switch A–D. Read-only: returns { command }.
Inputs: scope (required), name, endId, value, +2 more.
build_control_variableA
Build a Control Variables (122) event command for insertion via insert_event_commands. Applies operation (set/add/sub/mul/div/mod) to a variable (or the inclusive variableId..endId range) using an operand: constant, another variable, a random range, or game_data (item/actor/party/… readouts). Read-only: returns { command }.
Inputs: operand (required), variableId (required), endId, indent, +1 more.
build_flow_commandA
Build a single flow-control event command for insertion via insert_event_commands: wait (230, N frames), exit_event (115), label (118, a named jump target), or jump_to_label (119). Read-only: returns { command }.
Inputs: kind (required), name, frames, indent.
build_name_inputA
Build a Name Input Processing (303) event command for insertion via insert_event_commands — open the name-entry screen for an actor. Read-only: returns { command }.
Inputs: actorId (required), indent, maxLength.
build_pictureA
Build a Show Picture (231) or Erase Picture (235) event command for insertion via insert_event_commands. show: display name in slot pictureId with origin/position/scale/opacity/blend; erase: clear the slot. Read-only: returns { command }.
Inputs: kind (required), pictureId (required), x, y, +7 more.
build_play_audioA
Build a Play BGM/BGS/ME/SE (241/245/249/250) event command for insertion via insert_event_commands. Warns (never blocks) when name is not a known audio asset for that channel (checked against list_assets). Returns { command, warnings? }.
Inputs: kind (required), name (required), pan, pitch, +2 more.
build_screen_effectA
Build a screen transition/effect event command for insertion via insert_event_commands: fadeout (221) / fadein (222) — no params; tint (223) & flash (224) — an [r,g,b,a] color over duration frames; shake (225) — power/speed over duration. wait holds the event until it finishes. Read-only: returns { command }.
Inputs: kind (required), wait, color, power, +3 more.
build_shop_processingA
Build a Shop Processing (302 + one 605 row per extra good) event-command sequence for insertion via insert_event_commands. Each good sells an item/weapon/armor at its database price, or a specified price. purchaseOnly hides the sell tab. Read-only: returns { commands }.
Inputs: goods (required), indent, purchaseOnly.
build_show_choicesA
Build a Show Choices block (102 opener + a 402 branch per choice + optional 403 When-Cancel branch + 404 closer, each branch terminated like the editor) for insertion via insert_event_commands. Pass per-choice branches (each an EventCommand[] — e.g. from build_show_text) to fill the branch bodies. Read-only: returns { commands }.
Inputs: choices (required), indent, branches, position, +4 more.
build_show_textA
Build a Show Text event-command sequence (101 setup + one 401 line per text line) for insertion via insert_event_commands. Supports face image (from list_assets("faces")), window background/position, and the MZ name-box speaker. MZ does NOT word-wrap: keep each line under ~55 chars (~38 with a face) or it is cut off at the window edge (warned, never blocked) — or pass wrap: true to word-wrap automatically to that same width (escape codes like \C[n] do not count) and split into as many 4-line message boxes as needed. Read-only: returns { commands, warnings? }, writes nothing.
Inputs: lines (required), wrap, indent, faceName, +4 more.
build_transfer_playerA
Build a Transfer Player (201) event command for insertion via insert_event_commands — move the party to (x, y) on a map. With designation "variable", mapId/x/y are variable ids resolved at runtime. Read-only: returns { command }.
Inputs: x (required), y (required), mapId (required), fade, +3 more.
build_troop_pageA
Build a troop battle-event page { conditions, list, span } from a compact trigger — no hand-built 12-field conditions object. when keys (ANDed, at least one): turn [a, b] (turn a + bX; b 0 = only turn a), enemyHpBelow [enemyIndex, pct] (0-based troop slot, NOT enemy id), actorHpBelow [actorId, pct], switch id, turnEnd true. span: battle (runs once per battle, default), turn (once per turn), moment (re-runs while the condition holds — guard it with a switch). Timing (turn-based battles): an enemy action pattern with conditionType 1 / [a, b] is chosen during turn N's input phase (troop turnCount N-1, +1) and a troop page turn [a, b] is checked once turn N's action phase starts (turnCount N), so matching [a, b] land on the same battle turn N — the page runs before anyone acts; add turnEnd: true to run it after that turn resolves instead (the classic telegraph: warn at the end of the wind-up turn, strike next turn). Turn 0 = battle start. With b > 0 use span "turn", or a "battle" page fires only once. commands come from the build_ tools (build_show_text, build_battle_command, …); the end marker is appended. Read-only: returns { page } — land it with add_troop_page (or create_troop/update_troop pages).
Inputs: when (required), span, commands.
call_common_eventA
Build a "Common Event" event command (code 117) that calls the given common event, for insertion into an event page via insert_event_commands. Validates the common event exists. Read-only: returns { command } (matching the build_* tools, so it composes into a thenBranch/commands array); writes nothing.
Inputs: commonEventId (required), indent.
check_passabilityA
Check whether a map cell can be walked onto, reproducing the engine's layered passage rule: the stacked tiles at (x, y) are examined upper-layer first, and the first non-[*] tile decides each direction. Reads the map's tileset flags. Returns per-direction passability (down/left/right/up — true = a character can walk off the cell that way), the cell's terrain tag, the stacked tile ids, and — when direction is given — a single passable boolean for that direction. Read-only.
Inputs: x (required), y (required), mapId (required), direction.
create_actorA
Create a new actor in data/Actors.json. Only name is required; omitted fields use the editor's new-actor defaults (class 1, level 1-99, five empty equip slots, no traits). Allocates and returns the next unused actor id. NOTE: an actor's physical accuracy comes from its class + own traits — a class/actor with no Hit Rate trait (xparam id 0: trait { code: 22, dataId: 0, value: 0.95 }) always misses physical actions. The built-in class 1 has one; a custom class needs it added.
Inputs: name (required), note, dryRun, equips, +11 more.
create_armorA
Create a new armor in data/Armors.json. Only name is required; omitted fields use the editor's new-armor defaults (Shield equip slot, no stat bonuses). params is a flat 8-length stat bonus; etypeId is the equip slot (System.json equipTypes: 2 Shield, 3 Head, 4 Body, 5 Accessory). Allocates and returns the next unused armor id.
Inputs: name (required), note, price, dryRun, +6 more.
create_buff_skillC
Create a buff skill (simplified)
Inputs: name (required), scope (required), turns (required), mpCost (required), +3 more.
create_chestA
Create a complete, placed treasure chest on a map in one call — the two-page self-switch idiom done correctly, so the chest can never be looted twice. Page 1 (closed) is an action-button, priority-same event that optionally shows text, gives the contents, then flips its self switch; page 2 (opened) is gated on that self switch, shows the opened graphic and does nothing. kind picks the payout: item/weapon/armor (needs id) or gold. On the RTP !Chest sheet the open/closed states are the direction rows of one character block (down = closed, up = open), which is what closedDirection/openedDirection default to. Throws if the item/weapon/armor id does not exist; warns (never blocks) on an unknown characterName or a chest with no graphic.
Inputs: x (required), y (required), kind (required), mapId (required), +11 more.
create_classA
Create a new character class in data/Classes.json. Only name is required; omitted fields use the editor's new-class defaults (EXP curve [30,20,30,30], no traits/learnings, a linear param curve to maxLevel). Allocates and returns the next unused class id. NOTE: a class with no Hit Rate trait (xparam id 0: trait { code: 22, dataId: 0, value: 0.95 }) makes its actors always miss physical actions — pass one in traits for a combat-ready class. Likewise every learned skill's stypeId needs an Add Skill Type trait ({ code: 41, dataId: stypeId, value: 1 }) or the skill-type command never appears (warned, never blocked).
Inputs: name (required), note, dryRun, params, +4 more.
create_common_eventA
Create a new common event (reusable event-command list) in data/CommonEvents.json. Only name is required; omitted fields use the editor's new-slot defaults (empty command list, trigger 0 = call-only, switchId 1). Allocates and returns the next unused id. A structurally invalid command list refuses the write (nothing is saved) — pass force: true to override.
Inputs: name (required), list, force, dryRun, +3 more.
create_damage_skillC
Create a damage-dealing skill (simplified)
Inputs: name (required), scope (required), mpCost (required), damageFormula (required), +3 more.
create_enemyA
Create a new enemy in data/Enemies.json. Only name is required; omitted fields use the editor's new-enemy defaults (100 HP, one Attack action, no drops). Allocates the next unused enemy id and returns { enemy, warnings? } (warn-by-default: a battlerName not found in img/enemies (img/sv_enemies for a side-view project) is flagged, never blocked). Throws if an actions[].skillId or a dropItems[].dataId (item/weapon/armor by kind) references a record that does not exist. NOTE: an enemy with no Hit Rate trait (xparam id 0: trait { code: 22, dataId: 0, value: 0.95 }) always misses physical actions — pass one in traits if the enemy should land basic attacks.
Inputs: name (required), exp, gold, note, +7 more.
create_healing_skillC
Create a healing skill (simplified)
Inputs: name (required), scope (required), mpCost (required), healFormula (required), +2 more.
create_itemA
Create a new item in data/Items.json. Only name is worth passing; omitted fields use the editor's new-item defaults (Regular Item, consumable, no effects). Allocates and returns the next unused item id. An effect referencing a missing record throws: Add/Remove State (code 21/22) → state, Learn Skill (43) → skill, Common Event (44) → common event.
Inputs: name (required), note, price, scope, +14 more.
create_mapA
Create a new blank map: writes a new data/MapNNN.json (all tiles unpainted) and registers it in the map tree (MapInfos.json). Allocates the next unused map id and returns it. Paint tiles afterward with paint_tiles/fill_area (autotile-aware) and add events with create_map_event/create_npc.
Inputs: name (required), width, dryRun, height, +2 more.
create_map_eventA
Create a new event on a map. Each page is merged onto a blank "New Event" page (trigger 0 action-button, priority 0 below characters, no graphic, empty command list, standing move type), so you only supply the fields that differ — pass e.g. { image: { characterName: 'Actor1', characterIndex: 0 }, trigger: 3, list: [...] } and the rest is filled in. Nested image/conditions deep-merge; an omitted list becomes a valid empty (code-0-terminated) list. Omit pages entirely for a bare one-page event. For the common "talking NPC" case prefer create_npc. An action-button page meant to fire from facing (doors, entrances, signs) needs priorityType: 1 — with the default 0 (below) it only fires when stood on, so on an impassable tile it can never trigger (this is refused, not written; pass force: true to override). A structurally invalid command list is refused the same way. A page with no graphic, priority 1 and through off on a walkable tile is an invisible wall — warned (not refused); give it priority 0 or through: true if it should be walked past. Exempt: an action-button page over a drawn upper-layer (B–E) object — the solid-landmark idiom. Page fields: image { characterName, characterIndex, direction (2 down/4 left/6 right/8 up), pattern, tileId }, trigger (0 action-button/1 player-touch/2 event-touch/3 autorun/4 parallel), priorityType (0 below/1 same/2 above), moveType (0 fixed/1 random/2 approach/3 custom), conditions, list.
Inputs: x (required), y (required), name (required), mapId (required), +4 more.
create_move_routeA
Build a movement route from a named pattern (patrol/approach/flee/wander/custom) instead of raw move-command codes. Read-only: returns { moveRoute, warnings? }. Use the route as an event page’s autonomous moveRoute (update_map_event with moveType 3), or feed it to set_movement_route for a forced route in an event command list.
Inputs: pattern (required), wait, steps, repeat, +3 more.
create_npcA
Create a complete, placed NPC event on a map in one call — a graphic + trigger + a talk list. Provide text (built into a Show Text sequence, with optional face/speaker; wrap: true word-wraps paragraphs into 4-line message boxes) or an explicit commands array (commands wins if both given). Defaults to a solid, action-button NPC facing down. Warns (never blocks) on an unknown characterName, and on NO graphic at all (an NPC with no characterName is invisible in-game — use create_map_event for an intentionally-invisible trigger). The one-shot "make a talking NPC that says X" primitive.
Inputs: x (required), y (required), name (required), mapId (required), +15 more.
create_plugin_commandA
Build an RPG Maker MZ plugin command (event command code 357) for insertion into an event page via add_event_command. Validates against the plugins this project actually ships (scanned from their js/plugins/*.js @command/@arg annotations) merged over a small built-in allowlist — warn-by-default: an unknown plugin/command, a stray arg, or a plugin that is installed but disabled in js/plugins.js produces a warning but never blocks. Args are normalized to the editor’s string-valued shape. Read-only: returns { command, warnings? }, writes nothing.
Inputs: pluginName (required), commandName (required), args, label, +1 more.
create_skillA
Create a new skill with custom properties. Omitted fields use new-skill defaults: stypeId 1 (Magic), scope 1, occasion 1 (battle only), hitType derived — 0 certain for recovery or ally/user scopes, else 2 magical for Magic skills, else 1 physical if it deals damage, else 0. An effect referencing a missing record throws: Add/Remove State (code 21/22) → state, Learn Skill (43) → skill, Common Event (44) → common event.
Inputs: name (required), note, scope, speed, +18 more.
create_stateA
Create a new state (status condition like Poison/Sleep) in data/States.json. Only name is required; omitted fields use the editor's new-state defaults (no restriction, priority 50, no auto-removal, 1-turn duration). Allocates and returns the next unused state id.
Inputs: name (required), note, dryRun, motion, +20 more.
create_state_skillA
Create a state-inflicting skill (poison, sleep, etc.). Throws if stateId does not exist in States.json (create the state first with create_state).
Inputs: name (required), scope (required), chance (required), mpCost (required), +3 more.
create_transferA
Create a complete, placed map-transfer event in one call, using whichever of the two working idioms you pick. idiom: "action_button" (default) makes a priority-same event the player faces and presses — the right shape for a solid landmark (building, dungeon mouth, door); idiom: "player_touch" makes an invisible priority-below doormat the player walks onto — for interior exits and map-edge gaps. direction is the facing the player lands with, fade the screen transition. Throws if the destination map does not exist; warns if the destination tile is outside that map, if the characterName is unknown, or if the event can never fire from where it sits.
Inputs: x (required), y (required), mapId (required), targetX (required), +10 more.
create_troopA
Create a new troop (enemy battle group) in data/Troops.json. name is required; members defaults to empty and pages to one blank battle-event page. Every member.enemyId must reference an existing enemy. A structurally invalid battle-event page refuses the write (nothing is saved) — pass force: true to override.
Inputs: name (required), force, pages, dryRun, +2 more.
create_weaponA
Create a new weapon in data/Weapons.json. Only name is required; omitted fields use the editor's new-weapon defaults (Weapon equip slot, no stat bonuses). params is a flat 8-length stat bonus [maxHP, maxMP, atk, def, mat, mdf, agi, luk]. Allocates and returns the next unused weapon id.
Inputs: name (required), note, price, dryRun, +6 more.
delete_mapA
Delete a map: remove its entry from the map tree (MapInfos.json) and delete its data/MapNNN.json file. The deleted map's direct children are reparented onto its parent (not deleted), so removing one node doesn't wipe a whole sub-tree. Does not touch System.json.
Inputs: mapId (required), dryRun.
delete_map_eventB
Delete an event from a map by ID
Inputs: mapId (required), eventId (required), dryRun.
delete_recordA
Delete one database record (actor, class, skill, item, weapon, armor, enemy, troop, state, or common_event) by nulling its slot — ids never shift, so nothing else is renumbered. Reports every reference the deletion would leave dangling (an actor's class, a troop member, a Change Items / Shop / Battle Processing command, a skill effect, the starting party, …; found with the same audit validate_references runs, see coverage in the response) and REFUSES, writing nothing, when there are any — pass force: true to delete anyway, or dryRun: true to preview the references without throwing. Deleting skill 1 (Attack), skill 2 (Guard) or state 1 (Knockout) is always reported, since the engine hard-codes them. Returns { type, deleted: { id, name }, referenceCount, references[], coverage }.
Inputs: id (required), type (required), force, dryRun.
describe_tileA
Decode a raw RPG Maker MZ tile id into its tileset sheet (A1–A5, B–E), and for autotiles its kind + shape slot (0–47) and autotile geometry (floor/wall/waterfall). Read-only inspection helper — raw tile ids are opaque integers, this makes one legible. Returns { tileId, empty, sheet, sheetIndex, autotile, kind?, shape?, autotileType? }. Pass tilesetId to also inspect the sheet PNG and report transparent (true = the tile is see-through and needs an opaque base tile on a lower layer; painting it on layer 0 alone shows the map void) + transparentPercent.
Inputs: tileId (required), tilesetId.
export_webA
Export a pruned HTML5 web deployment (for itch.io or any static host): copies index.html, js/, css/, fonts/, icon/ and data/.json, plus only the img/audio/movies files the game references (every string in data/.json, string literals in the core js and plugins, plugin @default annotations; img/system is always kept) and only the effects/*.efkefc Effekseer effects actually referenced (an animation's effectName, a Plugin Command argument, or a plugin parameter/string — not other data strings) together with the textures/models they list internally. Writes the folder to outDir and, by default, .zip with index.html at the archive root. Returns file/byte counts, kept/dropped asset counts (+ dropped paths), the screen size from System.advanced (the itch embed size), and warnings for itch's 1000-file / 200 MB-per-file limits. Writes nothing inside the project; outDir must be outside the project's copied folders, and an existing non-empty outDir is only replaced if it was a previous export_web output. Follow up with a playtest of the exported build.
Inputs: outDir (required), zip, prune.
fill_areaA
Fill a rectangular area of a map with one tile id, with automatic autotiling — a filled autotile region borders itself correctly (and re-borders any same-kind tiles it touches). Flat tiles fill uniformly. Defaults to the lower ground layer (0). For region ids, fill layer 5 with the region number as tileId.
Inputs: x (required), y (required), mapId (required), width (required), +4 more.
find_tileA
Find tiles in a tileset by a case-insensitive SUBSTRING match on their catalog name — a quick bridge from a name fragment like 'grass' or 'forest' to a paintable tile id. This is a literal substring match, NOT synonym/semantic search: 'water' matches 'Endless Waterfall' but not 'Sea' or 'Pond' (their names lack the substring). To browse the actual tile names first, use get_tile_catalog with a sheet filter, then search a fragment you see. Set searchDescriptions: true to also match the free-text description a project catalog carries (custom sheets named by the tileset-catalog skill — their names are terse, the descriptions say what the tile looks like); built-in RPG Maker entries have no description, so this only widens the search over custom sheets. Returns matching catalog entries (name, sheet, tile id, autotile kind, source, matchedIn [which fields matched], transparent [true = needs an opaque base on a lower layer], plus description/confidence/manual for project catalog drafts). Covers the default RPG Maker tilesets, non-default sheets with a .txt name sidecar in img/tilesets/ (DLC packs ship these; loaded automatically, source: 'sidecar'), plus custom sheets cataloged into data/tilecatalog/ (via the tileset-catalog skill). Read-only.
Inputs: query (required), tilesetId (required), searchDescriptions.
get_databaseA
Read a database table in full: actors, classes, items, weapons, armors, skills, enemies, troops, states, or common_events. Returns the raw 1-indexed array (slot 0 is null), or — with id — that single record, or null if no such record exists. These are full records: prefer list_names for an id→name index, or search_actors/search_items/search_skills to find records by name, and reach for this only when you need every field. Maps and tilesets are not here: use get_map_infos/get_map and get_tilesets/get_tile_flags. Read-only.
Inputs: type (required), id.
get_game_titleA
Get the game title
Inputs: no named parameters.
get_mapA
Get map data by ID. The tile data array can be huge on a painted map (widthheight6 ints) and blow the MCP token limit, so pass includeData:false to omit it (you get dataTileCount instead) and read tiles with get_map_region when needed. includeData defaults to true for backward compatibility.
Inputs: mapId (required), includeData.
get_map_dimensionsA
Get the width and height (in tiles) of a map
Inputs: mapId (required).
get_map_eventB
Get a specific event from a map
Inputs: mapId (required), eventId (required).
get_map_eventsA
Get all events from a specific map
Inputs: mapId (required).
get_map_infosB
Get information about all maps
Inputs: no named parameters.
get_map_regionA
Read the raw tile ids in a rectangular window of one map layer — a token-cheap alternative to get_map for inspecting part of a painted map. Returns tiles as a 2D array (rows top→bottom, each left→right) of raw engine tile ids. The rectangle must lie fully within the map bounds (throws otherwise). layer defaults to 0 (see set_map_tile for the z-layer meanings).
Inputs: x (required), y (required), mapId (required), width (required), +2 more.
get_partyA
Get the starting party — the actor ids the game begins with. Returns { partyMembers }, rhyming with set_party's input/output shape.
Inputs: no named parameters.
get_projectA
Get the project directory the server is currently operating on: its path, whether it is a valid RPG Maker MZ project, and the game title it holds.
Inputs: no named parameters.
get_starting_positionA
Get the game starting position ({ mapId, x, y })
Inputs: no named parameters.
get_switchesA
Get all game switch names
Inputs: no named parameters.
get_systemC
Get system data
Inputs: no named parameters.
get_termsA
Get the game vocabulary/terms: the basic, commands, params string arrays and the messages map (menu labels, system messages).
Inputs: no named parameters.
get_tile_catalogA
Get the semantic tile catalog for a tileset: the named tiles (e.g. 'Grassland A', 'Forest', 'Sea') in each of its image sheets, each with its representative tile id and a source ('builtin' = RPG Maker's own labels; 'sidecar' = authoritative names from an img/tilesets/.txt file shipped next to a non-default sheet, as DLC packs do; 'project' = a data/tilecatalog/ entry — a vision-bootstrap draft, or a human-verified manual one, which outranks a sidecar name). Project (custom-sheet) entries also carry the skill's description, confidence ('high'/'medium'/'low'), and manual (true = a human verified it) so you can gauge how trustworthy a draft name is. Autotile entries (A1–A4) return the kind's base tile id — feed it to a paint command, which recomputes the shape from neighbours. Covers the default RPG Maker tilesets, any non-default sheet with a .txt name sidecar in img/tilesets/ (loaded automatically), plus custom sheets cataloged into data/tilecatalog/ (via the tileset-catalog skill); still-uncovered sheets are omitted. Called WITHOUT sheet it returns only a per-sheet index (name + entry count) to stay within the tool-output limit — a full tileset can hold thousands of named tiles. Pass sheet (filename 'World_A2' or slot role 'A2') to list one sheet's actual tile entries. Sheet-filtered entries also carry transparent (true = the tile is see-through and needs an opaque base tile on a lower layer — painting it on layer 0 alone shows the map void; e.g. trees/objects/overlays). Read-only.
Inputs: tilesetId (required), sheet.
get_tile_flagsA
Decode a tileset's flag word for a single tile id into a legible view: 4-direction passability (down/left/right/up — true = walkable that way), the [*] 'star' overlay bit, ladder/bush/counter/damage-floor flags, and terrain tag (0–7). Read-only inspection of data/Tilesets.json flags[]. Note passability here is for the tile in isolation; a real cell's passability layers its stacked tiles — use check_passability for that. Returns { tilesetId, tileId, tile, flags }.
Inputs: tileId (required), tilesetId (required).
get_tilesetsA
List every tileset in the project with its id, name, mode (0 world / 1 area), and the image sheets it uses (labelled A1–A4, A5, B–E; empty slots omitted). Use this to discover valid tilesetId values (needed by find_tile, get_tile_catalog, paint_tiles, fill_area, place_object, get_tile_flags, set_tile_flags, check_passability) and to see which sheets each tileset is built from. For a plain id→name list, list_names(type:"tilesets") is even cheaper. Read-only.
Inputs: no named parameters.
get_title_screenA
Get the title screen settings: title1Name/title2Name (background layers, from list_assets("titles1"/"titles2") — title2Name draws over title1Name), titleBgm (the AudioFile that plays while it is shown), and drawTitle (whether the game title text is drawn over the art).
Inputs: no named parameters.
get_typesA
Get one System.json type-name array — the named lists other data references by index: elements, skillTypes, weaponTypes, armorTypes, or equipTypes.
Inputs: category (required).
get_variablesA
Get all game variable names
Inputs: no named parameters.
insert_event_commandsA
Insert a pre-built sequence of event commands (from the build_* builders) into any of the three command lists an MZ project has — the mutating companion to the read-only builders. Splices before the list’s end marker (or at position). target "map_event" (the default) needs mapId + eventId + pageIndex; "common_event" needs commonEventId; "troop_page" needs troopId + pageIndex. The resulting list is validated before writing: a structural problem (wrong parameter count for a command code, a list left unterminated) refuses the write and saves nothing — pass force: true to override. Advisory findings (unrecognized code, over-long text line) are returned as warnings and never block. Returns { target, id, listLength, listCodes, warnings? } — the resulting list as its length and its command CODES, which is what you verify a splice against; pass verbose: true for the full list with parameters, or read it back with get_map_event.
Inputs: commands (required), force, mapId, dryRun, +7 more.
list_allocated_idsA
Show which switch / variable / common-event IDs are already spoken for, derived from the project's own JSON (never a hand-maintained list, which would drift the moment someone edited in the RPG Maker editor). An id counts as allocated if it is declared (a System.json label, a CommonEvents row) OR referenced anywhere — event page conditions and command lists, common events, troop pages, and Common Event skill/item effects. Use this before reusing an id, and pass id to answer "where is switch 23 actually used?" before touching it. Returns { count, highest, gaps, declaredCapacity, allocated[], coverage }. Read-only. To claim a fresh id instead, use next_free_id.
Inputs: type (required), id.
list_assetsA
List the available asset filenames (extension stripped) for one asset kind — the exact names RPG Maker's data references (a sprite/face/tileset/audio name). Use it to validate a graphic or audio name before wiring it into an event; a wrong filename fails silently at runtime. Fails soft: an unused asset directory returns an empty list.
Inputs: type (required).
list_namesA
Cheap names-only index for a database table. Returns { id, name } entries instead of full records — use it to look up or sanity-check IDs before wiring them into events, without paying the token cost of a full get_*/search_* dump.
Inputs: type (required).
list_plugin_commandsA
List every plugin command create_plugin_command can validate (plugin filename → command key → args): the plugins this project actually ships, scanned from their js/plugins/*.js annotations, merged over a small built-in allowlist. Pass pluginName to narrow to one plugin. Read-only. Use scan_plugins for the richer per-project view (arg types/defaults, enabled state); an unlisted plugin command can still be built, it just isn’t validated.
Inputs: pluginName.
next_free_idA
Reserve the next unallocated switch / variable / common-event ID(s) instead of picking one by hand. Ids are handed out strictly above every id already declared or referenced, so two sessions editing the same project over time cannot silently claim the same switch — a collision that never crashes and only surfaces hours into a playtest as a door that is inexplicably already open. Pass reuseGaps: true to fill holes below the highest id first (off by default: a hole is often an id claimed in notes but not yet written). Read-only — it suggests ids, it does not write them; name what you take with set_switch_name / set_variable_name so the next session sees the claim.
Inputs: type (required), count, reuseGaps.
object_tilesA
Expand a top-left flat tile id + a width×height size into the grid of tile ids that object occupies on the sheet — feed the returned tiles straight into place_object. This handles the flat sheets' two-half-column layout, where the tile below id N is NOT N+16 (indices 0–127 are the left half of the sheet, 128–255 the right), which is otherwise painful to compute by hand. Get the top-left id from find_tile/get_tile_catalog. Read-only. Throws if topLeftId isn't a flat id or the rectangle runs off the 16×16 sheet; warns if the tileset lacks that sheet.
Inputs: width (required), height (required), tilesetId (required), topLeftId (required).
paint_blueprintA
Paint a whole map area from an ASCII blueprint in ONE call and one write. rows are equal-length strings (one glyph per cell); legend maps each glyph to what that cell holds: [[layer, tile], ...] pairs (multi-layer cells, e.g. ground on 0 + fence on 1); a bare string = a catalog tile name on layer 0; { wall: { top, side?, faceHeight?, layer? }, tiles?: [...] } = an A4 wall (or A3 roof) — every cell gets the wall-top kind and the bottom faceHeight (default 1) cell(s) of each vertical run get the wall-side kind (derived as top + 8 kinds = +384 ids unless side is given; a run continuing off the map's bottom edge gets no face); or null = leave the cell untouched. Tiles may be ids or catalog names (exact name, else a unique substring — unknown/ambiguous names are an error). Row lengths, unknown glyphs, names and fit are all validated before anything is written. With clearUpperLayers (default true) each painted cell zeroes the tile layers (0-3) above its lowest specified layer that it does not specify, so stale objects vanish ([] erases the cell). Autotiling is recomputed once per layer, as in paint_tiles. Returns cells painted per layer, cleared count, wall faces made, and a passability overview of the rectangle, judged like the engine's canPass (a step needs the source to allow leaving and the target to allow entry): rows with # = impassable — a cell with no walkable direction (face, water, solid object) or part of a region whose own edge flags refuse entry from the walkable cells around it (an A4 wall-top mass, a stair-less plateau) — and . = walkable ground, plus the impassable [x, y] cells. Stamp multi-tile B/C objects afterwards with place_object.
Inputs: rows (required), mapId (required), legend (required), dryRun, +2 more.
paint_tilesA
Paint specific tiles onto a map, with automatic autotiling. Each cell is set to its tile id; if that id is an autotile (A1-A4, e.g. a catalog 'kind' base from find_tile), its shape and its neighbours' shapes are recomputed from same-kind adjacency so borders/corners line up. Flat tiles are painted as-is. Defaults to the lower ground layer (0). Higher-level than set_map_tile, which is a single raw tile with no autotiling.
Inputs: mapId (required), tiles (required), layer, dryRun.
place_objectA
Place a multi-tile B/C object (a house, tree, fountain, …) on a map and report its passability. tiles is the object's block of flat tile ids as rows (top to bottom), each row left to right; a 0 leaves that cell untouched so L-shaped/irregular objects work. Stamped onto the upper tile layer (2) by default so it draws over the ground. Unlike paint_tiles this does NOT autotile (objects are flat sheet tiles) — instead it uses the tileset flags to warn when a footprint cell sits on impassable terrain or overwrites an existing tile, and returns the resulting per-cell passability plus the collision cells the object turns into a solid obstacle. Warn-by-default: never refuses a placement. Get tile ids from find_tile/get_tile_catalog.
Inputs: x (required), y (required), mapId (required), tiles (required), +2 more.
render_mapA
Screenshot a map as the game actually draws it: boots the project headless, starts a new game on the map, and saves a PNG. Validators prove structure, not looks — use this to catch wrong wall/autotile kinds, void (unbased transparent tiles), odd sprites or missing images. Default renders the WHOLE map (canvas resized to width×height×48px, player hidden, autorun/parallel events frozen, map-name banner off); pass x+y for a normal 816×624 game-screen view centred on that tile. Returns the PNG path plus problems — console errors, page errors and HTTP 404s (missing assets — a missing image is drawn blank instead of stopping the engine on its load-error retry screen). Read-only. Needs the optional dependency playwright-core and a Chromium from the Playwright cache (npx playwright install chromium-headless-shell) or the RPGMAKER_MCP_CHROMIUM env var.
Inputs: mapId (required), x, y, out, +5 more.
reset_tableA
Clear a whole database table (actor, class, skill, item, weapon, armor, enemy, troop, state, or common_event) except the ids in keep — e.g. reset_table('skill', { keep: [1, 2] }) wipes the RTP skills but keeps Attack/Guard, the usual first step before authoring your own database with batch_create. Kept records stay at their own id; the rest become null and trailing empty slots are trimmed (the table is [null] when nothing is kept). Like delete_record it REFUSES, writing nothing, when the removal would leave references dangling (map events giving removed items, troops of removed enemies, …) unless force: true; use dryRun: true first to see what disappears and what would break. Returns { type, kept[], removedCount, removed[], referenceCount, references[], coverage } (lists are capped at 100).
Inputs: type (required), keep, force, dryRun.
resize_mapA
Resize a map to new width/height, safely repadding every z-layer of its tile data (existing tiles kept where the old and new grids overlap; new cells blank; shrinking crops). This is the ONLY safe way to change a map's dimensions — update_map refuses a width/height change because it would not resize the tile array. Warns about any event left outside the new bounds.
Inputs: mapId (required), width (required), height (required), dryRun, +1 more.
run_playtestA
Play the game headless from a script of steps and report what happened — the runtime check validators cannot do (does the door transfer, does the NPC say the right thing, does the choice branch, is there an invisible wall). One browser session runs the whole script; each step reports its outcome and the run stops at the first failing step. Steps: load {mapId,x,y,direction?,party?,level?,gold?,switches?,variables?,selfSwitches?,items?,equip?,encounters?} starts a fresh game there (random encounters off unless encounters:true); startEvent {eventId} starts a map event as if triggered and lets it run until it shows text or goes idle (waiting out any transfer — reported as transferredTo); advanceText {maxMs?} presses OK until the event is idle, STOPPING at an open choice list/battle — returns the map message lines shown and any open choices (text shown during a battle comes back separately as battleLines); choose {index} picks a 0-based choice; walk {direction, steps?} walks tile by tile, reporting where it ended (to); if a tile refused entry, stoppedAt (the player's tile) and blockedTile (the refused one); when a step fires a touch event (a door) it stops, waits out the transfer and reports transferredTo {mapId,x,y}, plus eventRunning/messageOpen if the event is still going; press {button, times?}; wait {ms}; autoBattle {troopId?, canEscape?, canLose?, maxMs? (default 60000)} fights (a started or new battle) on auto AI until it ends, returning the battle's message lines (troop events, victory text). Battles are fast-forwarded (20 engine frames per drawn frame: same logic, same odds, a 10-turn boss fight in seconds) unless the run sets realtime: true; screenshot {name?} saves a PNG; eval {script} evaluates a JS expression in the game page and returns its value (e.g. "$gameSwitches.value(3)"). Reported text reads as the message window shows it: \V[n]/\N[n]/\P[n]/\G expanded, control codes (\C[n], \I[n], ., | …) removed. Every step result carries ok; the response ends with finalState (scene, map, position, gold, party) and problems (console/page errors, HTTP 404s). Max 200 steps. Read-only: never writes the project. A run can take MINUTES (booting ~5-10 s, long cutscenes, realtime battles): clients should raise their request timeout, or send a progressToken with resetTimeoutOnProgress — the tool then sends a progress notification per step and every 5 s during long ones. Split long scripts into several runs if your client can do neither. Needs the optional dependency playwright-core and a Chromium from the Playwright cache (npx playwright install chromium-headless-shell) or the RPGMAKER_MCP_CHROMIUM env var.
Inputs: steps (required), out, inline, realtime.
scan_pluginsA
Discover the plugin commands this project actually has, by parsing the @command/@arg annotations in js/plugins/*.js and the enabled/disabled state in js/plugins.js. Use it to find out what create_plugin_command can call and with which args — it reports every command's key, label, description and args (name/type/default), plus whether the plugin is enabled in the editor's Plugin Manager (a disabled plugin's commands never run). create_plugin_command validates against this scan automatically, so you don't need to call this first; it's for discovery. Pass pluginName to narrow to one plugin, or enabledOnly:true to skip plugins that are installed but switched off. Read-only. NOTE: MZ has no 'required argument' annotation, so scanned args are checked for unknown names only, never for missing ones.
Inputs: pluginName, enabledOnly.
search_actorsA
Search actors by name or nickname
Inputs: searchTerm (required).
search_enemiesA
Search enemies by name (case-insensitive)
Inputs: searchTerm (required).
search_itemsA
Search items by name or description
Inputs: searchTerm (required).
search_map_eventsA
Search events on a map by name
Inputs: mapId (required), searchTerm (required).
search_skillsA
Search skills by name or description
Inputs: searchTerm (required).
search_troopsA
Search troops by name (case-insensitive)
Inputs: searchTerm (required).
set_class_param_curveA
Replace one of a class's 8 parameter growth curves. paramId is 0-7 ([maxHP,maxMP,atk,def,mat,mdf,agi,luk]); values must match the existing curve length (same max level).
Inputs: values (required), classId (required), paramId (required), dryRun.
set_currency_unitA
Set the currency unit shown next to gold amounts (e.g. "G", "Gold").
Inputs: unit (required), dryRun.
set_encountersA
Set a map's random-encounter list (replaces it wholesale) and optionally its encounterStep (average steps between encounters). Each encounter is { troopId, weight?, regionSet? }: weight biases the random pick (default 5), regionSet restricts it to those map region ids (empty/omitted = anywhere). Every troopId is validated against Troops.json — a non-existent troop throws. Prefer this over update_map for encounters (it validates and hides the on-disk shape).
Inputs: mapId (required), encounters (required), dryRun, encounterStep.
set_event_pageA
Update an existing event page's graphic and behavior in one call, without rebuilding the whole page or touching its command list: sprite (characterName/characterIndex/direction/pattern or a tileId), trigger, priority, movement (type/speed/frequency/route), and the through/walkAnime/stepAnime/directionFix flags. Graphic fields merge onto the current image; warns (never blocks) on an unknown characterName. Refuses the write if the change would leave the event unreachable (an action-button page with priority below on an impassable tile) — pass force: true to override.
Inputs: mapId (required), eventId (required), pageIndex (required), force, +18 more.
set_map_tileA
Set a single raw tile ID at (x, y) on a given z-layer (0-5). Note: tile IDs are raw engine integers; this is a low-level primitive without autotile/passability awareness.
Inputs: x (required), y (required), layer (required), mapId (required), +2 more.
set_movement_routeA
Insert a forced "Set Movement Route" (event command 205, plus the 505 continuation rows the editor expects) into an event page’s command list, moving a character as part of that page. characterId: -1 player, 0 this event, N event id. Pass a moveRoute from create_move_route. A structurally invalid route or page refuses the write (nothing is saved) — pass force: true to override.
Inputs: mapId (required), eventId (required), moveRoute (required), pageIndex (required), +5 more.
set_partyA
Set the starting party (the actor ids the game begins with, in order). Every id must reference an existing actor.
Inputs: partyMembers (required), dryRun.
set_projectA
Point the server at a different RPG Maker MZ project directory for the rest of the session (overrides RPGMAKER_PROJECT_PATH until the server restarts). The directory must contain game.rmmzproject and data/System.json.
Inputs: path (required).
set_switch_nameA
Set a switch name. Grows the project's switch list if the id is past the end (padded to the editor's 20-slot block), so an id from next_free_id can always be labelled. Naming a switch as soon as you claim it is what makes it visible to the next session — see list_allocated_ids.
Inputs: name (required), switchId (required), dryRun.
set_termA
Set one vocabulary term. For category 'basic'/'commands'/'params' the key is a numeric index (as a string); for 'messages' it's a message key (e.g. 'actorDamage'). Returns the updated terms.
Inputs: key (required), value (required), category (required), dryRun.
set_tile_flagsA
Edit a tile's passability/terrain/behaviour flags in a tileset's flags[] array (the write side of get_tile_flags). Only the fields you pass change — everything else on the tile is preserved (a non-destructive merge onto the current flag word). passage is walkability (down/left/right/up, true = a character can walk off that way). Also settable: star ([*] overlay), ladder, bush, counter, damage (damage floor), and terrainTag (0–7). For an autotile id (A1–A4) the change is applied to all 48 shape slots of its kind by default (set applyToAutotileKind:false to touch only the exact id) so painting any border shape keeps the same passability. Writes data/Tilesets.json through the commit choke point (dry-run/diff). Returns { tilesetId, tileId, appliedTileCount, before, after }.
Inputs: tileId (required), tilesetId (required), bush, star, +7 more.
set_type_nameA
Rename one entry in a System.json type-name array (elements/skillTypes/weaponTypes/armorTypes/equipTypes). Index 0 is the conventional empty slot. Returns the updated array.
Inputs: name (required), index (required), category (required), dryRun.
set_variable_nameA
Set a variable name. Grows the project's variable list if the id is past the end (padded to the editor's 20-slot block), so an id from next_free_id can always be labelled. Naming a variable as soon as you claim it is what makes it visible to the next session — see list_allocated_ids.
Inputs: name (required), variableId (required), dryRun.
update_actorC
Update an actor's properties
Inputs: actorId (required), updates (required), dryRun.
update_armorB
Update an armor's properties (shallow merge into the existing record)
Inputs: armorId (required), updates (required), dryRun.
update_classA
Update a class's properties (shallow merge into the existing record). Use for name, expParams, traits, or to replace the whole learnings/params arrays; for targeted edits prefer add_class_learning / set_class_param_curve. Warns when a learned skill's stypeId has no Add Skill Type trait ({ code: 41 }).
Inputs: classId (required), updates (required), dryRun.
update_common_eventA
Update a common event's properties (shallow merge into the existing record). Use for name, trigger, switchId, or to replace the whole command list. A structurally invalid command list refuses the write (nothing is saved) — pass force: true to override.
Inputs: updates (required), commonEventId (required), force, dryRun, +1 more.
update_enemyA
Update an enemy's properties (shallow merge into the existing record). Returns { enemy, warnings? } — a battlerName not found in img/enemies (img/sv_enemies for a side-view project) is flagged warn-by-default.
Inputs: enemyId (required), updates (required), dryRun.
update_game_titleB
Update the game title
Inputs: title (required), dryRun.
update_itemA
Update an item's properties (shallow merge into the existing record)
Inputs: itemId (required), updates (required), dryRun.
update_mapA
Update a map's top-level properties (name, display name, bgm, encounters, etc.). Does not repaint tiles. Cannot change width/height (that would desync the tile data array) — use resize_map for that. The echo omits the tile data array and the events map (neither is touched here) and reports dataTileCount/eventCount instead; pass verbose: true or use get_map for the full record.
Inputs: mapId (required), updates (required), dryRun, verbose.
update_map_eventA
Update a map event's properties. Refuses the write (nothing is saved) if the resulting event is structurally invalid — pass force: true to override.
Inputs: mapId (required), eventId (required), updates (required), force, +2 more.
update_map_treeA
Edit the map tree (MapInfos.json) only — reparent, reorder, rename, or expand/collapse maps without touching their tiles or events. Takes a batch of per-map updates; every referenced map (and any non-zero parentId) must exist, and the resulting tree must stay acyclic.
Inputs: updates (required), dryRun.
update_skillC
Update a skill's properties
Inputs: skillId (required), updates (required), dryRun.
update_starting_positionC
Update the game starting position
Inputs: x (required), y (required), mapId (required), dryRun.
update_stateA
Update a state's properties (shallow merge into the existing record)
Inputs: stateId (required), updates (required), dryRun.
update_title_screenA
Update the title screen: background layers (title1Name/title2Name, basenames from list_assets("titles1"/"titles2")), the BGM that plays while it is shown, and/or whether the game title text is drawn over the art. Only the provided fields are changed. Warns (never blocks) when an image/audio name is not a known asset. Returns the updated title screen settings.
Inputs: dryRun, titleBgm, drawTitle, title1Name, +1 more.
update_troopA
Update a troop's properties (shallow merge). If members is provided, each enemyId is validated to exist. A structurally invalid battle-event page refuses the write (nothing is saved) — pass force: true to override.
Inputs: troopId (required), updates (required), force, dryRun, +1 more.
update_weaponA
Update a weapon's properties (shallow merge into the existing record)
Inputs: updates (required), weaponId (required), dryRun.
validate_assetsA
Audit asset-filename integrity across the whole project (read-only, warn-by-default): every image/audio name field — actor characterName/faceName/battlerName, enemy battlerName, tileset sheets, map bgm/bgs/parallax/battlebacks, event page graphics, event Play BGM/BGS/ME/SE / Show Picture / Show Text face / Change Actor Images, and system titles/battlebacks/default audio/vehicle graphics — is checked against the files present under img/ and audio/. Catches a wrong filename (e.g. a battlerName with no matching img/enemies/*.png) before it becomes a runtime "Failed to load" error. An asset kind whose directory is empty/missing is skipped (not flagged). Complements validate_references (which checks id integrity). Returns { ok, warnings[] }.
Inputs: no named parameters.
validate_eventA
Validate a single event's command lists against the known RPG Maker MZ command table, plus its placement against the tile it sits on: an action-button page with priority below on an impassable tile (can never trigger) and an invisible wall (a graphic-less, priority-same, non-through page on a walkable tile — the player bumps into nothing; an action-button page over a drawn B–E object is exempt, as the solid-landmark idiom). Read-only: reports warnings without changing anything.
Inputs: mapId (required), eventId (required).
validate_projectA
Validate the event command lists of every map in the project, plus each event's placement (action-button-below on an impassable tile; graphic-less priority-same invisible walls on walkable tiles, except action-button pages over a drawn B–E object). Read-only: returns aggregated, map-tagged warnings for auditing before or after a batch of edits.
Inputs: no named parameters.
validate_referencesA
Audit cross-file reference integrity across the whole project (read-only, warn-by-default): Transfer Player targets and starting position point at existing maps; starting party, actor classes, class/enemy skills, troop members, enemy drops, and skill/item effects (states, learned skills, common events, animations) all resolve; event commands that name a record (Change Items/Weapons/Armors, Change Party Member, Battle Processing, Shop Processing, Change State/Skill, Common Event) and map random encounters point at existing rows; and the map tree has no dangling or cyclic parentId. Complements validate_project (which checks command shape). Returns { ok, warnings[] }.
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 128 tools
Most tools have clearly distinct purposes, with detailed descriptions that clarify boundaries between high-level helpers (create_npc, create_transfer, create_chest) and low-level builders (build_show_text, insert_event_commands). Some overlapping tile-painting tools (paint_tiles, fill_area, paint_blueprint, set_map_tile, place_object) and event-creation tools could still cause occasional misselection, but the distinctions are usually spelled out.
Nearly all tools use a consistent snake_case, verb-first naming convention (create_actor, get_map_region, update_troop, delete_map_event). Minor deviations like batch_create, next_free_id, object_tiles, and list_names are readable and do not seriously break predictability.
128 tools is an extreme mismatch for practical agent use, far beyond the typical well-scoped range and even the 50+ threshold for a score of 1. Although many tools are specialized for RPG Maker MZ's large domain, the sheer count imposes heavy selection and context costs.
The surface covers project setup, maps, events, database records, tiles, assets, system data, playtesting, and web export with lifecycle operations across create, read, update, delete, batch, and validation workflows. Only minor edge gaps exist, such as explicit removal of a single event command, but they are workable through existing tools.
Maintenance
Related MCP Connectors
Discover AI tools for game development — 100+ tools indexed by engine, task, and pricing.
D&D and TTRPG campaign manager for GMs: your AI reads and writes a live, typed campaign database.
AI game assets for agents: consistent sprites, 2D animations, tiles, maps, music and engine exports.
Savecraft serves real save game data and expert game knowledge to AI assistants.
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.36185 npm2MIT
- AlicenseCqualityDmaintenanceEnables AI models to develop and automate RPG Maker MZ projects by creating maps, events, and plugins through natural language commands. It provides comprehensive tools for database management, asset integrity checks, and direct map tile manipulation.2823 npm1ISC
- AlicenseAqualityDmaintenanceEnables creating RPG Maker MZ games using natural language through AI assistance, with tools for project management, map creation, event systems, and batch operations.10185 npm1MIT
- AlicenseCqualityDmaintenanceProvides tools for managing RPG Maker MZ game data, maps, events, and system settings through natural language, enabling AI-assisted game development.35185 npm35MIT