Claude does not have eyes on a Game Boy Advance screen, and it never needed them. In early 2025, a project called Claude Plays Pokemon turned that assumption into one of the year’s most-watched AI demos: an agent that looked at raw screenshots of Pokemon Red running on the PyBoy emulator and guessed which button to press next. It was slow, it misread sprites, and it got stuck in menus for hours at a time. Eighteen months later, a different approach has quietly made that whole screenshot-and-guess loop optional for Game Boy Advance games.
That approach is the Model Context Protocol, or MCP, and a small open-source bridge called mcp-mgba that wires it directly into the mGBA emulator. Instead of asking an AI model to recognize a health bar in a JPEG, mcp-mgba hands Claude 18 structured tools: read this memory address, press this button, advance one frame, save a screenshot. The model stops guessing what is on screen and starts reading exactly what the game’s RAM says is happening.
This tutorial walks through building that bridge from a clean install: setting up mGBA 0.10.5 with its Lua scripting console enabled, installing the mcp-mgba Node.js server, registering it with both Claude Desktop and Claude Code, and getting an AI agent to read party data, press buttons, and clear the first few minutes of a Pokemon game on its own. By the end you will have a working mGBA MCP server, a tested connection from at least one Claude client, and a minimal autonomous-agent loop you can extend into your own Pokemon emulator project.
None of this requires you to have followed the original Claude Plays Pokemon livestream or to have any background in emulator internals. The steps below assume you can install desktop software and copy a command into a terminal; everything specific to mGBA’s memory layout or the mcp-mgba tool surface is explained inline, with a pointer to the authoritative source whenever a number or address is likely to change between game revisions.
Don't miss new tech stories on Google
Add Tech Insider once in the Google app and our stories appear in your news suggestions.
What MCP Does Differently From the Screenshot Approach
The Model Context Protocol is an open standard that lets an AI application act as a client to external servers exposing structured tools, resources, and prompts. A local MCP server can wrap an emulator, a database, or a filesystem and present its capabilities, such as taking a screenshot or writing a byte to emulator memory, through a standardized interface that any MCP-compatible client can discover and call. The protocol is not tied to one model vendor: the same mGBA bridge that talks to Claude Desktop can, in principle, talk to any other client that implements the MCP transport.
That distinction matters for Pokemon emulation specifically. The original Claude Plays Pokemon experiments, including the public starter implementation built around the PyBoy emulator, worked by feeding Claude a screenshot and asking it to infer game state from pixels, then translating its reasoning into a button press. A public starter repository associated with developer David Hershey made that loop reproducible, and at least one independent project, LeePresswood/Claude-Plays-Pokemon, built a similar computer-vision agent on top of the Anthropic API. Community emulator-support references, such as RetroAchievements’ emulator documentation, list which cores expose the kind of memory-level hooks a project like this depends on, which is a useful starting point if you want to try the same pattern on a different system later. Both approaches work, but they spend a large share of every decision cycle on image interpretation rather than on game strategy.
mcp-mgba skips that step. Its architecture has two pieces: a Lua script called bridge.lua that runs inside mGBA’s own scripting engine and opens a local TCP server on port 8765, and a Node.js MCP server that talks to that TCP port and exposes the results as MCP tools over stdio. When Claude wants to know how many Pokemon are in the active party, it calls a memory-read tool and gets back an exact byte value, not a guess based on a sprite count. If you have already worked through a standard mGBA setup for Pokemon games, this tutorial picks up from there and adds the AI layer on top.
It also matters that none of this is proprietary to one lab. MCP servers are plain processes that speak a documented protocol over stdio or a network socket, which is why the same bridge architecture already has a sibling project: the mcp-mgba developer also maintains a comparable MCP server for the BizHawk emulator. A tutorial written around Claude today should still work with any other MCP-compatible client tomorrow, since the mGBA side of the bridge has no idea which model is on the other end of the TCP socket.
Prerequisites and Versions You’ll Need
Gather these before Step 1. Version mismatches are the single most common reason this setup fails on the first try, so confirm each one rather than assuming it is already current; mGBA’s public CHANGES log is the fastest way to check whether a given nightly build includes a scripting-related fix you might need.
| Component | Minimum Version | Why It Matters |
|---|---|---|
| mGBA | 0.10.5 (current stable, released March 8, 2025) or a newer nightly | Lua scripting was introduced as preliminary in 0.10.0; the bridge requires 0.10 or later with scripting enabled |
| Node.js | 22 or later | mcp-mgba’s server component is a Node.js package and will not run on older runtimes |
| mcp-mgba | Latest published release via npm | Installed with npm install -g mcp-mgba or run on demand with npx |
| Claude Desktop or Claude Code | Current build with MCP support | Either client can host the connection; this guide covers both |
| A legally obtained GBA ROM | Any Gen III Pokemon title | The bridge needs a loaded ROM before it can read or write memory |
| Operating system | Windows, macOS, or Linux | mGBA and Node.js both ship desktop builds for all three |
On the ROM question: emulator software is legal when it independently replicates console hardware without including Nintendo’s copyrighted game code, but downloading a Pokemon ROM you do not personally own is generally copyright infringement. The legally defensible path is dumping a cartridge you already own, a point that game-preservation guides like the one at Jacob Ainley’s 2026 ROM legality overview cover in more depth than this tutorial has room for.
Step 1: Install mGBA and Confirm Scripting Is Enabled
Download mGBA 0.10.5 from the official project site for your platform and install it normally. Once it is running, open Tools → Scripting…, the same window documented on mGBA’s own scripting API reference. If that menu item exists and opens a console window, scripting is available in your build. If you only see a grayed-out option or no Scripting entry at all, you likely have a very old build and need to update first.
Load any ROM through File → Load ROM before you touch the scripting console. mcp-mgba’s documentation is explicit that the ROM must be loaded before the Lua bridge script, because the bridge reads game metadata on startup and will not find a game title or game code if nothing is loaded yet.
Step 2: Get a Legal ROM and Verify the Game Code
With a ROM loaded, check Tools → Game Overrides or the title bar to confirm which Pokemon title and region you have. Gen III titles (Ruby, Sapphire, Emerald, FireRed, LeafGreen) each use different memory layouts for party and species data, so you will need to know exactly which game and revision you are working with before any memory-read tool call means anything. Write the game code down; you will reference it again in Step 9.
Step 3: Install Node.js 22+ and the mcp-mgba Package
Install Node.js 22 or later from your platform’s package manager or the official installer, then confirm the version before installing the bridge package.
node --version
# should print v22.x.x or newer
# Option A: install globally
npm install -g mcp-mgba
# Option B: run without installing, every time you need it
npx -y mcp-mgba
# Option C: clone for development or to read the source
git clone https://github.com/dmang-dev/mcp-mgba
cd mcp-mgba
npm install
Option A is the simplest for day-to-day use since both Claude Desktop and Claude Code will need a fixed command to launch the server. Option C is worth doing once if you want to read bridge.lua and dist/index.js yourself before trusting an AI model to send it button presses.
Step 4: Load bridge.lua Into mGBA’s Scripting Console
Back in mGBA, with your ROM still loaded, open the Scripting window and use File → Load script to load lua/bridge.lua from wherever you installed or cloned mcp-mgba. If the console prints a line confirming a TCP listener has started, the Lua half of the bridge is live. If it prints a Lua error instead, re-check that a ROM was loaded first; loading the script before a ROM is the most common reason this step fails.
Step 5: Verify the TCP Bridge Is Listening on Port 8765
Confirm the Lua bridge actually opened its socket before you wire up an MCP client, since that isolates a networking problem from an MCP configuration problem.
# macOS / Linux
lsof -i :8765
# Windows (PowerShell)
Get-NetTCPConnection -LocalPort 8765
You should see mGBA (or its process name) holding that port. If nothing is listed, go back to Step 4 and check the scripting console for an error before moving on.
Step 6: Register mcp-mgba in Claude Desktop
Claude Desktop has moved toward packaged Desktop Extensions (.mcpb files) installed through Settings → Extensions, but mcp-mgba is not currently distributed as one of those bundles, so you will add it through the manual MCP server configuration instead. Open the app’s Developer settings, locate claude_desktop_config.json, and add an entry for the server.
{
"mcpServers": {
"mgba": {
"command": "npx",
"args": ["-y", "mcp-mgba"],
"type": "stdio"
}
}
}
Save the file and fully restart Claude Desktop. A partial reload will not pick up a new entry in mcpServers; the app needs to re-read its config on launch.
Step 7: Register mcp-mgba in Claude Code
If you work primarily in Claude Code rather than the desktop app, the CLI handles this in one command. The claude mcp add syntax takes your own options first, then a double-dash separator, then the exact command used to launch the server.
# Local scope (default, this project only)
claude mcp add --transport stdio mgba -- npx -y mcp-mgba
# User scope (available across all your projects)
claude mcp add --transport stdio mgba --scope user -- npx -y mcp-mgba
Local scope writes the entry to a per-project file; user scope writes it to your global Claude configuration so every project can reach the same mGBA bridge. Pick user scope if you plan to build more than one Pokemon-playing project around this bridge.
Step 8: Confirm the Connection and Explore the Tool List
In either client, ask Claude to list its available tools, or check the connectors panel in Claude Desktop. You should see 18 tools prefixed mgba_. The table below groups them by what they actually do, since the names alone do not make the grouping obvious.
| Category | Tools | Purpose |
|---|---|---|
| Connectivity | mgba_ping, mgba_get_info | Confirm the bridge is alive; read game title, game code, and frame count |
| Memory reads | mgba_read8, mgba_read16, mgba_read32, mgba_read_range | Read 1, 2, or 4 bytes, or up to 4096 bytes in one call |
| Memory writes | mgba_write8, mgba_write16, mgba_write32, mgba_write_range | Write 1, 2, or 4 bytes, or up to 4096 bytes in one call |
| Input and timing | mgba_press_buttons, mgba_advance_frames | Queue button presses (FIFO) and step the emulator forward N frames |
| Emulation control | mgba_pause, mgba_unpause, mgba_reset | Pause, resume, or restart the loaded ROM |
| State capture | mgba_screenshot, mgba_save_state, mgba_load_state | Save a PNG of the display, or save and restore emulator state |
Step 9: Read Party Data With the Memory Tools
With the game code you confirmed in Step 2, ask Claude to call mgba_read_range against the known party-data address range for your specific title and revision. Gen III party structures differ between Ruby/Sapphire/Emerald and FireRed/LeafGreen, and addresses shift between revisions of the same game, so treat any address you find online as a starting point to verify, not a universal constant. The most reliable references for confirming an address are the pret disassembly projects, pokeemerald and pokefirered, which document the real symbol names and structure layouts the original games use rather than a number copied from an unrelated cheat sheet.
A reasonable first request to Claude once the tools are connected looks like this in plain language, which the model then translates into the matching tool call:
Call mgba_get_info to confirm the loaded game code.
Call mgba_read_range starting at the party count address for 100 bytes.
Report back how many Pokemon are in the party and their species IDs.
Because the tool returns raw bytes rather than a rendered screenshot, there is nothing for the model to misread. A wrong answer at this stage almost always traces back to an incorrect address for your specific game and revision, not a model mistake.
Decoding Gen III Memory: PID, Shiny Checks, and IVs
Raw bytes are only useful once you know how to interpret them, and Gen III’s data format is a good illustration of why the pret disassembly projects matter more than a copy-pasted address list. Every Pokemon in a Ruby, Sapphire, Emerald, FireRed, or LeafGreen save is built around a 32-bit Personality Value, commonly shortened to PID, which the games use to determine a Pokemon’s nature, gender, and whether it is shiny. The shiny check compares the upper and lower 16 bits of the PID against the trainer’s public and secret ID: if the XOR of all four values falls under a small threshold, the game renders the Pokemon with its shiny palette. That logic lives in the original game’s compiled code, which is exactly what pokeemerald and pokefirered reconstruct into readable C source, symbol names included.
Individual Values, or IVs, sit in a separate 32-bit field and are packed five bits at a time for HP, Attack, Defense, Speed, Special Attack, and Special Defense. The four 12-byte substructures that make up the rest of a Pokemon’s data (growth, attacks, EVs and condition, and miscellaneous) are also encrypted with the PID and stored in one of 24 possible orders, again determined by a calculation on the PID itself. None of this is specific to mGBA or to mcp-mgba; it is simply how the original Game Freak engineers laid out the data in 2002, and it has not changed across two decades of re-releases.
For a tracker built on top of mcp-mgba, the practical workflow is to have Claude read the full Pokemon data block with one mgba_read_range call, then reason about the PID, substructure order, and decryption in its own response rather than asking the emulator to do game-specific math. That keeps the Lua bridge generic and auditable, and it means the same 18 tools work whether you are checking for a shiny, verifying a trade, or just confirming a party slot is not empty.
# Prompt pattern for a shiny/IV check once raw bytes are in hand
Call mgba_read_range at the first party slot's base address for 100 bytes.
Using the pokeemerald substructure layout:
1. Extract the 32-bit PID and the 32-bit OT ID from the first 8 bytes.
2. Compute the shiny value from the PID and trainer/secret ID halves.
3. Determine substructure order from PID mod 24.
4. Decrypt the growth substructure and report species, level, and nature.
Tell me if this Pokemon is shiny and list its decoded IVs.
Treat the model’s arithmetic here the same way you would treat a junior engineer’s first pass: verify it once against a Pokemon whose stats you already know from in-game menus, and only trust the automated version once it matches.
Step 10: Send Button Presses and Advance Frames
Button input goes through mgba_press_buttons, and documentation for the bridge is specific that presses queue in FIFO order: two consecutive calls produce two distinct button events rather than one held input. Pair every press with mgba_advance_frames so the emulator actually steps forward and the game state has a chance to change before the next read.
Call mgba_press_buttons with ["A"].
Call mgba_advance_frames with 30.
Call mgba_screenshot and describe what changed.
Thirty frames is roughly half a second at native GBA speed, which is usually enough for a menu transition or a single dialogue advance to finish animating. Dense cutscenes may need two or three repeats of this pattern rather than one long frame-advance call.
Step 11: Capture Screenshots and Checkpoint With Save States
mgba_screenshot is still useful even in a memory-first workflow, mainly as a sanity check for the model and for you when something behaves unexpectedly. mgba_save_state and mgba_load_state matter more for actually running an agent unattended: save a checkpoint before Claude attempts anything risky, such as a wild battle it might lose, and you can roll back instead of restarting the whole session.
Step 12: Write a System Prompt That Keeps Claude on Task
An agent with 18 raw tools and no guidance will happily write to arbitrary memory addresses, which can corrupt a save file in ways a normal player could never do by hand. Before letting Claude run a long autonomous loop, give it an explicit system prompt that separates read actions it can take freely from write actions that need a stated reason.
You control mGBA through the mgba_* MCP tools. Rules:
1. Prefer mgba_read_range and mgba_get_info over write tools.
2. Only call mgba_write8/16/32/write_range if you state why first.
3. Call mgba_save_state before any wild encounter or trainer battle.
4. Advance in small frame increments (15-30) and re-check state after each.
5. If three consecutive reads return unexpected values, stop and report
instead of guessing further.
That last rule matters more than it looks. A model that keeps calling tools against a stale or incorrect address will burn its context window producing nonsense rather than catching the mistake, so an explicit stop condition is cheaper than letting it spiral.
Step 13: Run the Full Loop From a Fresh Boot
Load your ROM from the title screen, confirm the bridge is connected with mgba_ping, and give Claude a short, concrete goal such as “get through the opening dialogue and name the player character.” Watch the first few tool calls closely. If reads come back clean and button presses visibly move the game forward in mgba_screenshot output, the full chain from Claude’s reasoning to mGBA’s emulated hardware is working end to end, and you can hand it longer goals from there.
mGBA MCP vs the Screenshot-Based Claude Plays Pokemon Approach
Neither approach is strictly better in every situation. A screenshot-driven agent, like the public starter project built around PyBoy, needs no emulator scripting support at all and works on any system the emulator can render to an image, which is part of why general roundups of Pokemon emulators for Windows rarely mention scripting capability as a selection criterion at all. A memory-driven MCP bridge needs an emulator with a scripting hook, like mGBA’s Lua console, but trades a vision-interpretation problem for a far more reliable data-read problem.
| Factor | Screenshot-based agent (e.g. PyBoy starter) | mGBA MCP bridge |
|---|---|---|
| How the model perceives state | Interprets a rendered image | Reads exact bytes from emulator memory |
| Setup complexity | Lower; emulator just needs to render frames | Higher; needs Lua scripting support and a TCP bridge |
| Risk of misread state | Higher; sprites and UI can be misinterpreted | Lower, but wrong memory addresses cause equally wrong answers |
| Can write to memory directly | No | Yes, via the write tools, which adds save-corruption risk |
| Emulators supported today | PyBoy (Game Boy), various others by project | mGBA (GBA); a related dmang-dev project targets BizHawk’s wider system list |
| Best fit | Demonstrations and general-purpose vision agents | Developers building a repeatable, inspectable Pokemon automation tool |
Worth noting: the same developer behind mcp-mgba also maintains an MCP bridge for BizHawk that reaches a much longer list of systems, including NES, SNES, Genesis, N64, and PlayStation, through the same Lua-bridge pattern. If your project eventually needs a console mGBA does not emulate, that is the more relevant starting point, and it pairs well with the Lua-based approach covered in our BizHawk and Universal Pokemon Randomizer setup guide.
Common Pitfalls When Bridging Claude to mGBA
Most of the problems people hit with this setup trace back to a handful of ordering and assumption mistakes rather than anything wrong with mcp-mgba itself. The list below covers the ones that show up most often in the project’s own issue tracker and in general MCP-bridge setups.
- Loading bridge.lua before loading a ROM. The bridge reads game metadata on startup; with nothing loaded, it has nothing to report and will error or return empty values.
- Assuming one address works across every Gen III title. Ruby/Sapphire/Emerald and FireRed/LeafGreen use different party structures, and revisions within the same title can shift offsets. Verify against pokeemerald or pokefirered before trusting a number.
- Reloading the Lua script without restarting mGBA. mGBA does not fully tear down a previous script instance on reload, so a second load can leave a stale TCP listener behind. A full mGBA restart is the safer fix when the bridge starts behaving oddly.
- Calling read8/16/32 rapidly from inside a frame callback. Those direct calls can be flaky when invoked through a pcall inside a per-frame callback; the bridge internally routes similar cases through
read_range, so prefer range reads for anything latency-sensitive. - Letting the model write memory with no stated justification. Without the guardrail from Step 12, an agent can overwrite save data in ways a normal player never could, and there is no undo once it happens outside a save state.
- Forgetting that button presses queue instead of holding. Two quick
mgba_press_buttonscalls produce two separate press events, not a longer single press, which trips up anyone expecting held-input behavior from a physical controller. - Running two mGBA instances with the same bridge port. Only one Lua script can bind TCP port 8765 at a time; a second instance of mGBA trying to load bridge.lua simultaneously will fail silently or throw a bind error depending on the platform.
- Treating a model’s first decoded IV or shiny check as correct without verification. The arithmetic in the previous section is simple but easy to get subtly wrong across 24 possible substructure orders. Spot-check against a Pokemon whose real stats you already know from an in-game menu before trusting the automated version.
Troubleshooting Guide
| Symptom | Likely Cause | Fix |
|---|---|---|
| Scripting menu is missing or grayed out | mGBA build predates 0.10, or scripting was disabled at compile time | Install mGBA 0.10.5 or a current nightly from the official site |
| bridge.lua errors immediately on load | No ROM loaded before the script | Load a ROM first, then load the script from the Scripting console |
lsof -i :8765 shows nothing | The Lua bridge failed to open its TCP listener | Check the scripting console for an error; restart mGBA and reload the ROM and script |
| Claude reports no mgba_* tools available | Config file not reloaded, or wrong scope used | Fully quit and restart Claude Desktop, or re-run claude mcp add with the correct scope |
npx -y mcp-mgba hangs with no output | Node.js version below 22, or network restrictions blocking npm’s registry | Confirm node --version is 22+; try the global install instead of npx |
| Memory reads return values that don’t match the game | Wrong address for this specific title or revision | Cross-check against the pokeemerald or pokefirered disassembly for your exact game |
| Button presses don’t appear to do anything | No frame-advance call after the press | Always pair mgba_press_buttons with mgba_advance_frames |
| Bridge connects, then drops after reloading the script | Previous script instance not fully torn down | Close mGBA completely and relaunch, rather than reloading the script in place |
| Save file looks corrupted after a long agent session | An unguarded write tool call during autonomous play | Restore from a save state taken before the session and add the Step 12 guardrails |
Advanced Tips: Multi-Game Support, Safety Rails, and Performance
Once the base loop works, a few refinements make the setup more durable. First, keep a small lookup table in your own notes, not in the model’s prompt, mapping each Gen III game code to its verified party and species addresses; feeding Claude a smaller, pre-validated address set per game is more reliable than asking it to search blindly every session. Second, treat save states as checkpoints in the literal sense: have the agent call mgba_save_state before every battle and before any menu sequence that could lead to deleting an item or a Pokemon, so a bad decision costs you thirty seconds of replay rather than a whole save file. Third, if you want Claude to react to game events rather than poll constantly, combine mgba_advance_frames in small increments with a read immediately after, since polling every single frame wastes tool calls without adding useful precision for a turn-based game.
On the safety side, this entire setup is built for single-player, personal-device use. Do not point an autonomous mGBA agent at anything that touches another player’s save file, a trade, or an online battle server; link-cable and Wi-Fi emulation for Pokemon trading, covered separately in our guide to trading Pokemon between emulators, assumes a human on each end and was never designed with an unsupervised agent pressing buttons on one side. If you later want the model to also edit save data directly rather than just observe it, a purpose-built tool like the one covered in our PKHeX save-editing guide is a safer, more auditable path than giving an LLM raw write access to a live save.
Performance-wise, remember that every tool call round-trips from Claude to the MCP server to the TCP bridge to mGBA’s Lua engine and back. That path is fast enough for turn-based gameplay but is not the right foundation for anything frame-perfect; if you later want a comparison point for raw emulator speed and accuracy across non-AI setups, our breakdown of mGBA vs VBA-M vs SkyEmu covers that ground without the MCP layer involved.
Cost is a real constraint once you move from a quick test into a long autonomous run. Every mgba_read_range, every button press, and every screenshot is a separate tool call, and a model billed per token pays for the reasoning Claude does between each one, not just the final answer. A session that tries to clear an entire Gym battle unattended can easily rack up dozens of tool calls per in-game minute. Batching reads (checking party state once instead of polling individual Pokemon slots separately) and keeping the system prompt’s stop condition strict, as in Step 12, both reduce that overhead without changing what the agent is actually capable of doing.
Complete Working Project: A Minimal Autonomous Pokemon Agent
Putting every step together, here is the full configuration and prompt set for a working minimal agent, assuming mGBA 0.10.5, Node.js 22+, and a legally dumped Gen III ROM are already in place.
# 1. One-time setup
npm install -g mcp-mgba
claude mcp add --transport stdio mgba --scope user -- npx -y mcp-mgba
# 2. Each session, inside mGBA:
# File -> Load ROM (load your Gen III Pokemon ROM)
# Tools -> Scripting (open the console)
# File -> Load script (select lua/bridge.lua from mcp-mgba)
# Confirm the console reports a listener on port 8765
# 3. In Claude Code, start a session and send:
Connect to the mgba MCP server and call mgba_ping to confirm the bridge
is live. Then call mgba_get_info and tell me the game title and code.
# 4. System prompt for autonomous play (paste once per session):
You control mGBA through the mgba_* MCP tools.
Rules:
1. Prefer mgba_read_range and mgba_get_info over write tools.
2. Only call mgba_write8/16/32/write_range if you state why first.
3. Call mgba_save_state before any wild encounter or trainer battle.
4. Advance in small frame increments (15-30) and re-check state after each.
5. If three consecutive reads return unexpected values, stop and report.
Goal: get through the opening sequence, name the player character,
and report the first wild Pokemon encountered.
From this baseline, the natural next step is swapping the hardcoded goal for a longer objective, such as reaching the first Gym, and letting the save-state guardrail absorb any battles the agent loses along the way. Because every tool call is logged as a discrete, named action rather than an opaque image interpretation, you can audit exactly what the agent did and why at any point in the session, which is the core advantage this whole approach has over the original screenshot-based demos.
Where This Pattern Goes Next
Emulator bridges like mcp-mgba are a narrow example of a broader shift happening across agentic AI tooling in 2026: instead of wrapping a legacy system in a vision model that has to guess at its internal state, developers are exposing that state directly as structured tools and letting the model reason over clean data. The same logic that lets Claude read a Pokemon’s PID instead of squinting at a sprite also shows up in browser-automation MCP servers that read the DOM instead of a screenshot, and in database MCP servers that return query results instead of a rendered table image. Pokemon emulation happens to be a well-documented, low-stakes place to practice that pattern, since decades of community disassembly work like pokeemerald already did the hard part of mapping out what the memory means.
If this is your first MCP server, the lessons carry over directly to any other tool-bridge project: isolate the data-access layer from the language model, give the model a narrow and well-documented tool surface rather than raw access to everything, and put a human-auditable guardrail, like the save-state rule in Step 12, between the model’s judgment and anything that cannot be undone.
Frequently Asked Questions
Does mcp-mgba work with any Pokemon game, or just Gen III?
The bridge itself is generic: it exposes memory and input tools for any GBA ROM mGBA can run. Gen III titles (Ruby, Sapphire, Emerald, FireRed, LeafGreen) are the natural fit since they are native GBA games; earlier generations require a different emulator core entirely.
Do I need Claude specifically, or will any MCP client work?
mcp-mgba’s documentation names Claude Desktop and Claude Code as supported clients, but MCP is an open protocol, so any client that implements the standard stdio transport can in principle connect to the same bridge.
Is this legal if I only use a ROM I own?
Dumping and playing a ROM from a cartridge you personally own sits on the legally safer side of emulation. Downloading a ROM from an unofficial site, even for a game you also own physically, is generally still copyright infringement, independent of how you later play it.
Can the agent corrupt my save file?
Yes, if you let it call write tools without guardrails. Save states taken before risky actions are your rollback mechanism; treat the write tools as capable of the same damage a corrupted cartridge save would cause.
Why not just use the screenshot-based approach from the original Claude Plays Pokemon demos?
You still can, and for a general-purpose vision-agent demo it needs less setup. The memory-based MCP approach trades that simplicity for far more reliable, auditable state reads once you move past a demo and into something you actually want to run unattended.
What happens if I reload bridge.lua without restarting mGBA?
mGBA does not fully tear down the previous script instance, which can leave a stale listener or inconsistent state on port 8765. A full application restart, not just a script reload, is the documented workaround.
Can I use this same pattern for non-GBA Pokemon games, like the Nintendo DS titles?
Not directly through mcp-mgba, since it is built specifically around mGBA’s GBA core. A separate BizHawk-based MCP bridge from the same developer covers a wider range of systems through the same Lua-bridge pattern, but it is a different project with its own setup.
Do I need to know Lua to use this?
No. You only need to load the pre-written bridge.lua file as-is through mGBA’s Scripting console. Lua knowledge only becomes useful if you want to modify the bridge itself rather than just use the MCP tools it already exposes.
Does this cost money to run beyond buying the game?
mGBA, Node.js, and mcp-mgba are all free and open source. The only ongoing cost is whatever your Claude plan or API usage charges for the tokens spent reasoning between tool calls, which scales with how long and how chatty your autonomous sessions run.
Can I run this entirely offline?
The mGBA and Node.js side runs entirely on your machine with no internet connection required once mcp-mgba is installed. Claude itself is a hosted model, so the reasoning half of the loop still needs network access even though the emulator half does not.





