@gbs-toolkit/mcp-server
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., "@@gbs-toolkit/mcp-server list all scenes in the project"
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.
@gbs-toolkit/mcp-server
MCP server for structured GB Studio 4.x project editing — read/patch scripts, scenes, actors, triggers, variables; build ROMs; sprite generation pipeline.
Designed to be driven by an LLM coding assistant (Claude Code, Cursor, etc.) so the model can mutate .gbsres resources safely instead of dropping bytes into JSON by hand.
Install
npm install -g @gbs-toolkit/mcp-serverOr invoke on demand via npx:
npx -y @gbs-toolkit/mcp-serverRelated MCP server: mcp-mgba
Run as an MCP server
The server speaks stdio MCP. Most users wire it up in their LLM client's .mcp.json:
{
"mcpServers": {
"gbs": {
"command": "npx",
"args": ["-y", "@gbs-toolkit/mcp-server"],
"env": {
"GBS_PROJECT_ROOT": "./gbsproj/demo"
}
}
}
}Environment variables
Variable | Required | Default | Notes |
| yes | — | Directory containing |
| no | probes common install locations | Absolute path to |
| no | none | Path to a libmgba-linked runner binary used by |
| no |
| Output directory for |
| no |
| Captured compile log |
| no |
| Where |
| no |
|
|
| conditional | — | Required if |
| conditional | — | Required for |
| conditional | — | Required for |
| conditional | — | Required for |
Tool inventory
Tool | Kind |
| read |
| write (insert / replace / delete, applied in order) |
| write (upserts a |
| write |
| write (cross-script reference scan; refuses unless |
| write (text-to-image → 4-colour DMG quantise → emits |
| write (no AI; same pipeline applied to a user-supplied PNG/JPG) |
| subprocess (spawns GB Studio CLI's |
| subprocess (drives a libmgba-linked C runner) |
| read image (returns base64 PNG as multimodal MCP content) |
What is NOT exposed
Creation/import of binary assets stays GUI-side: backgrounds, tilesets, emotes, avatars, fonts, music, sounds, plus actorPrefabs / triggerPrefabs / palettes / notes. The MCP layer can read and patch scripts that reference these resources by id, but cannot create their .png / .uge / .wav payloads. Sprites are the one exception (see generate_sprite / convert_image_to_sprite).
Built-in guardrails
The server enforces two checks that previously had to live in prompts:
Dialogue width audit —
patch_scriptvalidates everyEVENT_TEXT/EVENT_MENU/EVENT_CHOICE/EVENT_DIALOGUE/EVENT_MARQUEEstring against the GB Studio default-font line budget (18 columns;$var$placeholders reserve 5 chars to cover signed-16-bit values). Multi-boxtext: string[]form, CJK width (2 columns / char), and recursivechildrenbranches are all walked. A violation rejects the patch withDIALOGUE_WIDTH_EXCEEDEDand a per-line breakdown. PasswidthBudgetto override (e.g. for a custom narrow font) orforce: trueto bypass.Sprite quality check —
generate_spriteandconvert_image_to_spriteanalyse the post-quantisation RGBA buffer (opaque ratio, effective DMG colour count, edge density, single-shade dominance). Clearly degenerate outputs (near-empty frame, ≤1 effective shade) refuse to write the asset; borderline cases (2 shades, low edge density, >85% one shade) save with aquality.level: "warn"field in the response. Passforce: trueto skip the check.
Both checks return structured metadata so the LLM can self-correct rather than ploughing through.
Building the emulator runner
run_emulator requires a libmgba-linked C binary. Stock mGBA CLIs do not accept a startup --script flag, so we ship a small dedicated runner. From the cloned repo:
cd native
MGBA_SRC=/path/to/mgba MGBA_BUILD=/path/to/mgba/build ./build.shThen point the env var at the result: GBS_MGBA_RUNNER=/path/to/gbs-mgba-runner.
If you don't need run_emulator, ignore this — every other tool works without it.
License
MIT
Available Tools
23 toolsbuild_romBuild GB Studio project to ROMA
Invoke upstream gb-studio-cli (make:rom) to compile the project. Captures stdout+stderr to the configured compile log (read via read_compile_log). Returns { success, exitCode, romPath?, elapsedMs, stderrTail }. ALWAYS call this after structural edits before declaring work done. Requires GBS_CLI_PATH env var OR an installed GB Studio app in a standard location.
Inputs: target, outputName.
convert_image_to_spriteConvert a local image into a GB Studio spriteA
Read a local PNG/JPG and convert it to a 4-colour DMG-quantised GB Studio sprite. For animationType=fixed the image is treated as one frame. For animationType=multi/multi_movement the input MUST already be a sprite sheet (3 frames wide for multi, 6 frames wide for multi_movement) — single-frame inputs cannot be expanded to multiple directions. After quantisation a heuristic quality check runs: degenerate outputs (near-empty, single-shade, low-detail) refuse to write unless force: true. No API key required.
Inputs: name (required), inputPath (required), animationType (required), force.
create_actorCreate a new actor in a sceneA
Append a new actor file under project/scenes//actors/. Enforces GB Studio hardware caps: up to MAX_ACTORS=20 per normal scene, MAX_ACTORS_SMALL=10 when scene width*height <= 160 tiles. Coordinates default to tiles. Pass spriteSheetId of an existing sprite, or leave empty (actor will not render until set).
Inputs: x (required), y (required), name (required), sceneId (required), +8 more.
create_custom_eventCreate a new custom event (reusable script)A
Create a new script resource file under project/scripts/. Custom events are reusable scripts that can be called from scenes/actors/triggers. The script body starts empty — use patch_script with an ownerType: 'customEvent' locator to populate it.
Inputs: name (required), symbol, description.
create_sceneCreate a new sceneA
Create a new scene folder + scene.gbsres under project/scenes/. Name is slugified for the on-disk folder; collisions get _2/_3 suffixes. Scene type must be uppercase (TOPDOWN, PLATFORM, ADVENTURE, POINTNCLICK, SHMUP, LOGO) — changing type later resets engine configuration, so pick deliberately. Size defaults to 20×18 tiles (one screen); scenes >20×18 scroll. Does not create a background — pass backgroundId of an existing background, or set it empty and add one later.
Inputs: name (required), type (required), width, height, +2 more.
create_triggerCreate a new trigger in a sceneA
Append a new trigger file under project/scenes//triggers/. Triggers are rectangular zones that fire script on player enter and leaveScript on exit. Enforces MAX_TRIGGERS=30 per scene. Coordinates and size are in tiles.
Inputs: x (required), y (required), name (required), sceneId (required), +3 more.
create_variableCreate a new global variableA
Append a new Variable entry to project/variables.gbsres. Id is auto-assigned as the next numeric string. Symbol is auto-derived from name (camelCase → snake_case, e.g. 'curQ' → 'cur_q'). GB Studio variables are 16-bit signed (-32768..32767); set initial value via set_variable.
Inputs: name (required), symbol.
delete_actorDelete an actorA
Delete one actor file from a scene's actors/ directory. Refuses if any script references this actorId (including via property paths like <actorId>:x_pos); pass force: true to override. The actor's own scripts are not counted as external references — they are deleted with the file.
Inputs: actorId (required), sceneId (required), force.
delete_custom_eventDelete a custom eventA
Delete one custom-event (script resource) file under project/scripts/. Refuses if any script references this customEventId (typically via EVENT_CALL_CUSTOM_EVENT). Pass force: true to override. The custom event's own body is deleted with the file.
Inputs: customEventId (required), force.
delete_sceneDelete a sceneA
Recursively delete a scene folder (scene.gbsres + actors/ + triggers/). Refuses if the scene is the start scene, or if any other script references this sceneId (e.g. EVENT_SWITCH_SCENE) — pass force: true to override the reference check (the start-scene guard is unconditional). Use list_scenes to find target ids. There is no undo; commit your work first.
Inputs: sceneId (required), force.
delete_triggerDelete a triggerA
Delete one trigger file from a scene's triggers/ directory. Triggers are rarely referenced by other scripts (they only run on enter/leave), but the cross-reference check still runs for safety. Pass force: true to override. The trigger's own onEnter / onLeave scripts go away with the file.
Inputs: sceneId (required), triggerId (required), force.
delete_variableDelete a global variableA
Remove a Variable entry from project/variables.gbsres. Refuses if any script references the variable (e.g. VARIABLE_SET_TO_VALUE / IF_VARIABLE_VALUE; ScriptValue {type:"variable", value:<id>}). Pass force: true to override — but expect compile errors on the next build_rom unless every reference is repaired.
Inputs: variableId (required), force.
generate_spriteGenerate a sprite from a text promptA
Generate a GB Studio sprite from a text prompt. Calls the configured image-generation provider (SPRITE_PROVIDER env var ∈ {openai, gemini, replicate, fal}; default openai), runs the result through a 4-colour DMG quantiser, and writes (sprite.png + sprite.png.gbsres) under assets/sprites/. Returns a spriteSheetId you can pass to create_actor immediately. Frames are 16×16; for multi the provider is called 3× (one per direction), for multi_movement 6× (idle + walk per direction). After quantisation a heuristic quality check runs; degenerate outputs refuse to save unless force: true.
Inputs: name (required), prompt (required), animationType (required), force, +1 more.
list_actorsList actors in sceneA
List all actors in a scene with id, name, position, sprite sheet, and per-actor script presence flags (hasInteractScript / hasStartScript / hasUpdateScript / hasHit1Script / …). Use read_script to fetch event bodies.
Inputs: sceneId (required).
list_scenesList scenesA
List every scene in the active project. Returns id, name, type, width/height (in tiles), backgroundId, and actor/trigger counts. Use this for orientation before reading a specific scene.
Inputs: no named parameters.
patch_scriptPatch script eventsA
Apply an ordered list of structured operations (insert / replace / delete) to a ScriptEvent[] array. Full-array replacement is intentionally unsupported — use delete + insert. Operations apply sequentially: each op's index refers to the array state AFTER all prior ops in this call. Persists the edited scene/customEvent to disk atomically. Before writing, the resulting tree is checked against the dialogue width budget (default 18 chars/line for EVENT_TEXT/EVENT_MENU/EVENT_CHOICE strings); violations refuse the write unless force: true.
Inputs: locator (required), operations (required), force, widthBudget.
read_compile_logRead last compile logA
Read the full stdout+stderr captured from the last build_rom invocation. Use this INSTEAD of guessing when a build fails. Optionally returns only the last N lines via tailLines.
Inputs: tailLines.
read_sceneRead sceneA
Return the full structured representation of one scene: metadata, actors[], triggers[], and scene-level scripts (script, playerHit1Script, playerHit2Script, playerHit3Script). Does NOT include backgrounds, palettes, or sprites — fetch those separately if needed.
Inputs: sceneId (required).
read_scriptRead script eventsB
Return the ScriptEvent[] for a given owner and key. Each event has shape { id, command, args?, children? } where children is a Record<branchName, ScriptEvent[]> for composite events (if/switch/group). See the gbvm-scripting skill for command semantics.
Inputs: locator (required).
run_emulatorRun ROM in headless emulator (libmgba)A
Launch the ROM via the bundled libmgba-linked gbs-mgba-runner with a scripted input timeline. Captures a PNG at the end (and optionally mid-run). Returns { success, screenshotPath, midScreenshotPath?, exitCode, elapsedMs, stderrTail }. Retrieve the image via the screenshot tool. Build the runner once with mcp-server/native/build.sh (needs a local mGBA checkout); or set GBS_MGBA_RUNNER to an absolute path.
Inputs: romPath (required), inputs, durationMs, screenshotAt.
screenshotRead the latest emulator screenshotA
Return an emulator screenshot as an image content block (base64 PNG). Call AFTER run_emulator. Defaults to the latest.png from run_emulator's final frame; pass filename to read a different file in the screenshot dir.
Inputs: filename.
set_start_sceneSet the project's start sceneA
Patch startSceneId in project/settings.gbsres so the game boots into the given scene. Preserves every other setting field. The sceneId must resolve to an existing scene on disk, or build_rom will fail.
Inputs: sceneId (required).
set_variableSet variable initial valueA
Ensure a variable is initialised to value at game start by inserting/updating a VARIABLE_SET_TO_VALUE event at the top of the START SCENE's onInit script (GB Studio 4.x has no default-value field on Variable). Value must fit signed 16-bit (-32768..32767). The variable must already exist — to add a new variable, call create_variable first. For in-game variable changes during play, use patch_script instead.
Inputs: value (required), variableId (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 23 tools
Each tool targets a distinct resource and action (e.g., delete_custom_event vs delete_scene, create_actor vs create_trigger). Descriptions clearly differentiate overlapping operations like read_script vs patch_script, and list_scenes vs read_scene. No two tools serve the same purpose.
All tools follow a consistent verb_noun pattern in snake_case (e.g., list_scenes, create_variable, delete_actor). Verbs like list, read, create, delete, set, build, run, generate, convert are used predictably without mixing styles.
23 tools cover a comprehensive range of operations for GB Studio development (scenes, actors, triggers, variables, scripts, sprites, build/run). This count is well-scoped for the toolkit's purpose—neither too few to be incomplete nor too many to be unwieldy.
The toolkit covers CRUD for scenes, actors, triggers, variables, custom events, and scripts, plus building, emulation, and sprite generation. Minor gaps include lack of dedicated list tools for variables and custom events (though scoped via read_scene and inference), and no direct background/palette management despite backgroundId references.
Maintenance
Related MCP Connectors
MCP Server for Slima - AI Writing IDE for Novel Authors with AI Beta Reader.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Remote MCP server to read and edit GanttFather projects: tasks, dates, dependencies, critical path.
Official remote MCP server for Archivist AI TTRPG campaign memory: characters, sessions, and more.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn MCP server that parses GameMaker Studio 2 projects, providing developers and AI agents with quick access to project structure, GML code, and asset metadata.19-
- AlicenseAqualityBmaintenanceMCP server for the mGBA Game Boy Advance emulator. Read and write GBA memory, inject button presses, take screenshots, save/load state, and step the emulator through a Lua bridge.1840 npm7MIT
- AlicenseAqualityFmaintenanceA Godot 4 MCP server for AI-assisted project inspection, editing, validation, and runtime automation via stdio and optional WebSocket bridge.389MIT
- AlicenseAqualityDmaintenanceUnified MCP server for Construct 3 providing offline documentation, project read/write, analysis, and scripting support. Enables AI-driven game development and project management through natural language.61MIT