mcp-retroarch
The mcp-retroarch server bridges MCP clients (like Claude) to RetroArch's Network Control Interface (NCI) over UDP, enabling programmatic control of emulated games across many systems (NES, SNES, Genesis, GBA, PSX, N64, etc.).
Connectivity & Status
retroarch_ping— Verify connectivity and retrieve the RetroArch version stringretroarch_get_status— Check if emulation is playing or paused, and get loaded game info (system, name, CRC32)retroarch_get_config— Read RetroArch configuration parameters (e.g. save directories, settings)
Memory Access
retroarch_read_memory/retroarch_write_memory— Read/write emulated memory via the libretro core's system memory map (preferred; up to 4 KiB per call)retroarch_read_ram/retroarch_write_ram— Read/write memory via the CHEEVOS address space (fallback when no memory map is available)
Emulation Control
retroarch_pause_toggle— Toggle between paused and running statesretroarch_frame_advance— Step emulation forward by exactly one frame (while paused)retroarch_reset— Soft-reset the running game
Save States
retroarch_save_state_current— Save emulator state to the currently-selected slotretroarch_load_state_current/retroarch_load_state_slot— Restore state from the current or a specific slot (0–9)retroarch_state_slot_plus/retroarch_state_slot_minus— Increment or decrement the current save slot pointer
Visual & Display
retroarch_screenshot— Capture a PNG screenshot saved to RetroArch's screenshot directoryretroarch_show_message— Display a custom on-screen notification overlay
Notable Limitations
No gamepad/button input — RetroArch's NCI does not expose controller input
Saving to a specific slot requires walking the pointer with slot_plus/slot_minus
Most control commands are fire-and-forget UDP datagrams with no acknowledgment; use status/memory reads to verify effects
Memory map availability varies by core
Provides tools for interacting with RetroArch's Network Control Interface, enabling memory read/write, save/load states, screenshots, pause/frame advance, reset, and on-screen messages for emulated games.
mcp-retroarch
An MCP server that bridges Claude (and any other MCP client) to RetroArch via its built-in Network Control Interface (UDP, port 55355).
Works against any libretro core (NES, SNES, Genesis, GB/GBC/GBA, PSX, N64, etc.) — give the model memory r/w, save-state automation, screenshot, pause / frame-advance / reset, and on-screen messages.
What it can do
Capability | Available? | Notes |
Memory read / write | ✅ | Two paths: |
Save / load state | ✅ | Current slot or explicit slot for load; save is current-slot-only (NCI limitation) |
Screenshot | ✅ | Saved to RetroArch's configured screenshot directory |
Pause / frame advance | ✅ |
|
Reset | ✅ | Hard-reset the running game |
On-screen message | ✅ | Useful for "look here" cues during scripted runs |
Game info | ✅ | Title, system, CRC32 |
Game-pad input | ❌ | NCI doesn't expose this. RetroArch has a separate "Remote RetroPad" core on UDP port 55400 that does, but it requires loading that specific core (you can't drive an existing emulation core through it). Not in scope for v0.1.0. |
If you need game-pad input on Game Boy Advance specifically, see mcp-mgba. For PCSX2 (memory + savestate only, no input/screenshot), see mcp-pine.
Related MCP server: mcp-mgba
How it works
+----------------+ stdio +-----------------+ UDP :55355 +-----------------+
| MCP client | JSON-RPC | mcp-retroarch | text proto | RetroArch |
| (Claude etc) | -----------> | (Node.js) | ------------> | (NCI enabled) |
+----------------+ +-----------------+ +-----------------+Requirements
RetroArch (any recent version) with Network Commands enabled
Node.js 22+
Install
Option A — install from npm (recommended)
npm install -g mcp-retroarchOption B — npx (no install)
npx -y mcp-retroarchOption C — clone and develop
git clone https://github.com/dmang-dev/mcp-retroarch
cd mcp-retroarch
npm installEnable RetroArch's Network Control Interface
Either:
GUI: Settings → Network → Network Commands → ON, then confirm
Network Cmd Portis55355(the default)Or via
retroarch.cfg:network_cmd_enable = "true" network_cmd_port = "55355"
Then launch any libretro core + game. The NCI is always-on once enabled — no script to load.
Register with your MCP client
Claude Code
claude mcp add retroarch --scope user mcp-retroarchVerify:
claude mcp list
# retroarch: mcp-retroarch - ✓ ConnectedClaude Desktop
Edit claude_desktop_config.json:
Platform | Path |
macOS |
|
Windows |
|
Linux |
|
{
"mcpServers": {
"retroarch": {
"command": "mcp-retroarch"
}
}
}Restart Claude Desktop after editing.
Configuration
Env var | Default | Purpose |
|
| UDP destination host |
|
| UDP port (must match |
Tools
Tool | Description |
| Verify reachability — returns RetroArch version |
| State (playing/paused), system, game, CRC32 |
| Read named RetroArch config values (e.g. |
| Memory r/w via system memory map |
| Memory r/w via CHEEVOS address space (fallback when no memory map) |
| Toggle pause state |
| Step one frame (only effective while paused) |
| Hardware-reset the running game |
| Save a screenshot to RetroArch's screenshot directory |
| Display a notification on the RetroArch window |
| Save to currently-selected slot |
| Load from currently-selected slot |
| Load from explicit slot number |
| Change current slot pointer (NCI has no "set slot to N") |
See docs/RECIPES.md for end-to-end examples.
Tested cores
Verified end-to-end against mcp-retroarch:
System | Core |
|
| Notes |
Game Boy Advance |
| ✅ | ✅ | GBA interrupt vector table visible at |
NES |
| ✅ (only NES core tested that does) | ✅ | Full 16-bit NES address space exposed. WRAM at |
NES |
| ❌ no memory map | ✅ | CHEEVOS only. 64 KB bound. For NES + memory map, prefer Mesen. |
SNES |
| ❌ no memory map | ✅ | CHEEVOS bounded to ~128 KB (matches SNES WRAM size). 65C816 RTS opcodes ( |
Sega Mega Drive / Genesis |
| ❌ no memory map | ⚠️ sparse | CHEEVOS exposes some 68K WRAM addresses but fails at others ("no error message"). Usable if you know specific addresses; blanket sweep doesn't work. |
Nintendo 64 |
| ✅ | ✅ | Full N64 RAM exposed. KSEG0 mirror is faithful — |
PlayStation 1 |
| ❌ no memory map | ✅ | CHEEVOS only. PSX main RAM begins around CHEEVOS offset |
Patterns observed
Most libretro cores don't advertise a system memory map to NCI — they implement only the CHEEVOS read API. Of those tested, only Mesen (NES) and Mupen64Plus-Next (N64) expose a system memory map. Both also expose CHEEVOS, so they're strictly better.
System memory maps are faithful to real hardware — Mupen64Plus-Next preserves the N64's KSEG0 mirror (
0x80000000reads as0x0); Mesen preserves the NES's WRAM mirroring (0x1000reads as0x0). This is great for anyone using the bridge alongside disassembly.CHEEVOS bounds match the system's main RAM size — NES exposes 64 KB, SNES 128 KB, etc. Reads past the bound fail with "no error message".
When choosing a core for memory work, prefer the one with a system memory map if available.
If you've tested another core, please open a PR adding it to this table.
Troubleshooting
Symptom | Cause / Fix |
| Network Commands aren't enabled in RetroArch, or the port doesn't match |
| The loaded libretro core doesn't advertise a system memory map. Try |
| The address isn't covered by the core's memory map. Either a different core would expose it, or the address you want is outside the system bus (e.g. video memory in some cores). |
Screenshots don't appear where I expect | RetroArch saves to its configured screenshot directory. The NCI doesn't expose |
Can't save to a specific state slot directly | NCI limitation, not a bug. The protocol only exposes "save to current slot" — you have to walk the slot pointer to your target with |
Development
npm install
npm run dev # tsc --watchSmoke test against a running RetroArch:
node .scratch/smoke.cjsDebugging with the MCP Inspector
Browse and call this server's tools interactively with the MCP Inspector:
npm run inspectorBuild first if you've edited src/ since your last npm install (npm run build, or keep npm run dev running). Override the target with RETROARCH_HOST / RETROARCH_PORT (default 127.0.0.1:55355). tools/list works even without RetroArch connected; calling a tool needs RetroArch running with Network Commands enabled.
License
Related
Available Tools
17 toolsretroarch_frame_advanceA
PURPOSE: Step emulation forward by exactly one frame. USAGE: Use for frame-precise input automation, animation inspection, or letting the system initialize after a reset. ONLY effective while emulation is paused — RetroArch's FRAMEADVANCE is a no-op when running, so call retroarch_pause_toggle first (after checking retroarch_get_status to confirm you'll end up paused, not unpaused). For long jumps (thousands of frames) prefer retroarch_save_state_current / retroarch_load_state_current of a pre-prepared state — frame-by-frame stepping costs ~1 UDP round-trip per frame. BEHAVIOR: When paused, advances the emulator by exactly one frame and remains paused. When NOT paused, the command is silently ignored by RetroArch. FIRE-AND-FORGET: the NCI does NOT acknowledge this command — the call returns as soon as the UDP datagram is sent, with no confirmation that RetroArch received or applied it. To verify the effect, follow up with an observable tool (retroarch_get_status for run state, retroarch_read_memory / retroarch_read_ram for memory mutations, retroarch_screenshot for visual state). UDP packets to a not-listening RetroArch are silently dropped. The new frame count is not reported — to verify progress, take screenshots before/after with retroarch_screenshot or read a known-changing memory value. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). RETURNS: Single line 'Advanced one frame' (UDP-send confirmation only — does NOT confirm that RetroArch was paused or that the frame actually advanced).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so thoroughly. It discloses that the command is silently ignored when not paused, is fire-and-forget with no acknowledgment, UDP packets are silently dropped if not listening, the frame count is not reported, and the return string is only a send confirmation. This fully reveals critical behavioral traits beyond basic functionality.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Though lengthy, the description is structured with labeled sections (PURPOSE, USAGE, BEHAVIOR, FIRE-AND-FORGET, Transport, RETURNS). Each sentence conveys a necessary operational detail such as pause requirement, no-ack behavior, verification methods, and configuration. The length is justified by the tool's complexity, and it is front-loaded with the core purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers purpose, usage, behavior, return value, transport, prerequisites, and verification strategies, even referencing sibling tools for confirmation. Given the fire-and-forget nature, no output schema, and no annotations, this description is fully complete for an agent to invoke the tool correctly and verify its effect.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is no parameter meaning to clarify. The description instead provides useful invocation context (UDP transport, network_cmd_enable requirement), which adds value, but the parameter dimension is vacuously satisfied. Baseline 4 for no params is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise purpose: "Step emulation forward by exactly one frame." It clearly distinguishes itself from sibling tools by emphasizing frame-precise stepping and even contrasts with long jumps using save/load states. This is a specific verb+resource+outcome with strong sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit usage contexts are given: "frame-precise input automation, animation inspection, or letting the system initialize after a reset." It states the condition "ONLY effective while emulation is paused," instructs to call retroarch_pause_toggle first after checking retroarch_get_status, and recommends alternatives for long jumps. This is exemplary when-to-use versus when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_get_configA
PURPOSE: Read a single RetroArch configuration parameter by name via the NCI's GET_CONFIG_PARAM command. USAGE: Use to discover RetroArch's filesystem paths and selected settings without parsing retroarch.cfg yourself. For run-state (playing/paused, loaded ROM) use retroarch_get_status instead — this tool only reads static config values. NOTE: RetroArch whitelists which params are exposed via NCI; unknown / non-whitelisted names return an error from RetroArch even though they may exist in retroarch.cfg. The screenshot output directory is NOT exposed (see retroarch_screenshot). BEHAVIOR: No side effects — pure read. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). Returns an error if the named param isn't in RetroArch's NCI whitelist, the value contains characters that break the line-based reply parser, or the UDP query times out. RETURNS: Single line 'NAME = VALUE'.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Config parameter name (case-sensitive). Commonly-supported values: `savefile_directory`, `savestate_directory`, `system_directory`, `cache_directory`, `log_dir`, `runtime_log_directory`, `netplay_nickname`, `video_fullscreen`. RetroArch's exact whitelist varies by version; if a name returns an error, it isn't exposed via the NCI on this build. `screenshot_directory` is NOT exposed by RetroArch — there is no NCI way to query the screenshot output path. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It states the tool is a pure read with no side effects, describes the transport (NCI over UDP, with network_cmd_enable required), and lists potential errors (non-whitelisted param, parser breakage, timeout). This is very good, though missing details on empty values or error format.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear headings (PURPOSE, USAGE, NOTE, BEHAVIOR, RETURNS) and is front-loaded with the purpose. Every sentence adds value, and it is not overly verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (one parameter) and lack of output schema, the description covers purpose, usage, behavior, and return format. It mentions error conditions and transport requirements. Minor omission: does not specify error return format, but overall very complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% coverage with detailed description of the 'name' parameter, including common values and caveats. The description adds little beyond what the schema provides, only repeating some info and adding the note about screenshot_directory not being exposed. Baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool reads a single RetroArch config parameter via NCI's GET_CONFIG_PARAM command. It distinguishes from siblings like retroarch_get_status and retroarch_screenshot, specifying different use cases.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says when to use this tool (to discover paths/settings without parsing retroarch.cfg) and when not to (for run-state, use retroarch_get_status). It also notes the screenshot directory is not exposed, pointing to retroarch_screenshot.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_get_statusA
PURPOSE: Report whether RetroArch is currently playing or paused, plus the loaded system, game basename, and CRC32. USAGE: Call after retroarch_ping to learn what (if anything) is loaded; before retroarch_pause_toggle to decide whether the toggle will pause or unpause; before retroarch_frame_advance (which only steps when paused); whenever you need to confirm the previous fire-and-forget control command (pause/reset/load_state) actually took effect. For RetroArch settings (paths, flags) use retroarch_get_config instead — this tool only reports run-state and the loaded ROM identity. BEHAVIOR: No side effects — pure read of emulator status via the NCI's GET_STATUS command. Returns 'No content loaded' (state=contentless) when RetroArch is sitting at the menu with no ROM. Returns an error on UDP timeout (RetroArch not reachable). RETURNS: When content is loaded: four lines 'State: playing|paused', 'System: SYSTEM_ID', 'Game: BASENAME', 'CRC32: HEX or (none reported)'. When no content: literal 'No content loaded'.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully shoulders the transparency burden. It states 'No side effects — pure read of emulator status via the NCI's GET_STATUS command', explains the contentless case ('Returns 'No content loaded' (state=contentless) when RetroArch is sitting at the menu with no ROM'), and discloses error behavior on UDP timeout. This goes beyond what structured fields could convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is organized with clear labels (PURPOSE, USAGE, BEHAVIOR, RETURNS) and every sentence contributes essential information. Despite its length, there is no redundancy or filler; it remains succinct while covering all necessary facets. The front-loaded purpose lets an agent quickly classify the tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that there is no output schema and no annotations, the description compensates by fully specifying the return format for both loaded and contentless states, including line-by-line details. It covers prerequisites (call after ping), side effects, and error cases, making it essentially self-contained for an agent to invoke confidently.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema provides no semantics to enrich. The baseline for 0 params is 4. The description adds value by detailing the return payload, which is more relevant than parameter documentation for this no-arg tool.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear, specific verb ('Report') and resource ('whether RetroArch is currently playing or paused, plus the loaded system, game basename, and CRC32'). It explicitly distinguishes itself from sibling tools like retroarch_get_config by stating what this tool does not do ('this tool only reports run-state and the loaded ROM identity'), making it easy for an agent to select it correctly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance: 'Call after retroarch_ping to learn what (if anything) is loaded; before retroarch_pause_toggle to decide whether the toggle will pause or unpause; before retroarch_frame_advance (which only steps when paused); whenever you need to confirm the previous fire-and-forget control command...'. It also names an alternative for a different use case: 'For RetroArch settings (paths, flags) use retroarch_get_config instead'. This is exemplary usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_load_state_currentA
PURPOSE: Restore the emulator from RetroArch's currently-selected save slot (one of slots 0-9). USAGE: Counterpart to retroarch_save_state_current. Use to undo a sequence of writes/inputs (the snapshot/experiment/restore workflow) or to start each tool-call sequence from a known baseline. Loads from whichever slot is currently selected (the same slot save_state_current would target). To load from a specific slot WITHOUT changing the current-slot pointer, use retroarch_load_state_slot instead — that's important if you're alternating between bookmarks. To start fresh from boot, use retroarch_reset. BEHAVIOR: DESTRUCTIVE TO LIVE STATE: replaces ALL current emulator state (RAM, registers, mapper, audio, framecount) with the slot file's contents. Anything not previously snapshotted is lost. The state file MUST come from the same ROM and same core version that produced it — loading mismatched files typically fails or destabilizes the core. FIRE-AND-FORGET: the NCI does NOT acknowledge this command — the call returns as soon as the UDP datagram is sent, with no confirmation that RetroArch received or applied it. To verify the effect, follow up with an observable tool (retroarch_get_status for run state, retroarch_read_memory / retroarch_read_ram for memory mutations, retroarch_screenshot for visual state). UDP packets to a not-listening RetroArch are silently dropped. If the currently-selected slot has no saved state, RetroArch silently ignores the command — no error is raised. To verify the load happened, follow up with a memory-read or screenshot. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). RETURNS: Single line 'Loaded from current slot' (UDP-send confirmation only — does NOT verify the slot existed or the load succeeded).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full responsibility and excels. It discloses destructive impact on live state, fire-and-forget UDP behavior with no acknowledgment, silent drops when not listening, silent ignore when no save exists, and the need for follow-up verification. This goes well beyond what annotations would have provided.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy but well-structured with PURPOSE/USAGE/BEHAVIOR/RETURNS labels. Some redundancy exists (e.g., repeated emphasis on verifying after load), but most sentences convey essential safety and operational details. It is denser than necessary but earns most of its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema, the description explicitly states the return line and its limited meaning. It covers transport configuration, prerequisites (network_cmd_enable), failure modes, and verification strategies. For a complex, side-effect-heavy tool with zero parameters, this is exceptionally complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4. The description adds semantic context by explaining that the 'currently-selected slot' is the one save_state_current targets, and how to select a specific slot via sibling tools, effectively giving meaning to the implicit parameter state. This exceeds the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: restoring emulator state from RetroArch's currently-selected save slot. It distinguishes itself from siblings by explicitly contrasting with retroarch_load_state_slot and retroarch_reset, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance: as a counterpart to save_state_current, for undoing writes/inputs, and for starting from a known baseline. It also gives clear alternative tools for different scenarios (load_state_slot for specific slots without changing pointer, reset for fresh boot), satisfying the when/not/alternatives criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_load_state_slotA
PURPOSE: Load state from an explicitly-named save slot number, without modifying RetroArch's currently-selected slot pointer. USAGE: Use to load from a specific slot when you don't want to disturb the current-slot pointer (e.g. you're alternating between two bookmarks while keeping the 'live' slot for ongoing saves). For loading from the currently-selected slot, use retroarch_load_state_current — semantically distinct: this tool ignores the current-slot pointer entirely and addresses by number. Slots are numbered 0-9 by RetroArch convention. There is no retroarch_save_state_slot counterpart in the NCI — saving to a specific slot still requires walking the pointer with state_slot_plus/minus and then calling save_state_current. BEHAVIOR: DESTRUCTIVE TO LIVE STATE: replaces ALL current emulator state with the named slot's contents. Anything not previously snapshotted is lost. The state file MUST come from the same ROM and core version that produced it. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). UNLIKE most NCI control commands, LOAD_STATE_SLOT does send a reply (this client awaits it), so a UDP timeout will surface as an error here even though sibling load/save calls are fire-and-forget. If the named slot has no saved state, RetroArch's reply still indicates the command was processed — verify with a memory-read or screenshot. The current-slot pointer is unchanged after this call. RETURNS: Single line 'Loaded from slot N' echoing the requested slot number.
| Name | Required | Description | Default |
|---|---|---|---|
| slot | Yes | Save state slot number to load from. RetroArch's standard slot range is 0-9 (ten slots), but the NCI does not enforce a hard upper bound — slot numbers outside the configured range will simply find no file and silently no-op. This call does NOT change the currently-selected slot pointer (use retroarch_state_slot_plus / retroarch_state_slot_minus for that). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully carries the burden. It explicitly warns 'DESTRUCTIVE TO LIVE STATE: replaces ALL current emulator state with the named slot's contents', notes ROM/core version requirements, explains that LOAD_STATE_SLOT sends a reply unlike siblings, and clarifies no-op behavior and pointer invariants. This is thorough and goes far beyond basic info.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than average, but its labeled sections (PURPOSE, USAGE, BEHAVIOR, RETURNS) make it scannable and every sentence carries meaningful information. The detail is justified by the destructive nature and the need to separate from siblings. It is concise relative to the complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no annotations, no output schema, and a high-risk destructive operation, the description covers all needed context: purpose, usage alternatives, behavioral side effects, transport details, timeout behavior, verification advice, and return format. Nothing material is missing for an AI agent to select and invoke this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema description coverage is 100% and already provides rich detail: integer, min 0, slot range 0-9, no hard upper bound, no-op outside range, and no pointer change. The description adds one useful nuance—this tool addresses by number and ignores current-slot pointer entirely—but it mostly reinforces schema content. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with a clear PURPOSE: 'Load state from an explicitly-named save slot number, without modifying RetroArch's currently-selected slot pointer.' It uses a specific verb and resource, and explicitly distinguishes itself from the sibling retroarch_load_state_current. The scope and uniqueness are fully clarified.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The USAGE section explicitly states when to use this tool ('use to load from a specific slot when you don't want to disturb the current-slot pointer') and when not to ('For loading from the currently-selected slot, use retroarch_load_state_current'). It also notes the absence of a save counterpart and suggests the alternative state_slot_plus/minus walking approach. This is exemplary guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_pause_toggleA
PURPOSE: Toggle RetroArch's pause state — pause if running, unpause if paused. USAGE: RetroArch's NCI exposes ONLY a toggle, not separate pause/unpause commands. To reach a known state, call retroarch_get_status first to check state: playing|paused, then toggle if and only if you need to flip it. Use before a sequence of memory-inspect / write / screenshot calls when you need a stable game state across calls; pair with retroarch_frame_advance to step single frames without leaving pause. BEHAVIOR: Modifies emulator run state by flipping it. FIRE-AND-FORGET: the NCI does NOT acknowledge this command — the call returns as soon as the UDP datagram is sent, with no confirmation that RetroArch received or applied it. To verify the effect, follow up with an observable tool (retroarch_get_status for run state, retroarch_read_memory / retroarch_read_ram for memory mutations, retroarch_screenshot for visual state). UDP packets to a not-listening RetroArch are silently dropped. Calling toggle when you don't know the current state will flip it to whichever state it ISN'T — confirm with retroarch_get_status before and after if it matters. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). RETURNS: Single line 'Pause toggled' (this is a confirmation that the UDP datagram was sent, NOT that RetroArch received or acted on it).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully discloses critical behavioral traits: it is fire-and-forget, receives no acknowledgment, silently drops UDP if not listening, and requires verification via other tools. It also states it modifies emulator run state, giving the agent a complete operational awareness.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear section headers and every section adds essential operational detail. It is longer than a minimal toggle description, but the additional length is justified by the lack of annotations and the need to explain the fire-and-forget behavior and verification steps.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no annotations, no output schema, and zero parameters, the description covers all essential aspects: what it does, when to use it, expected behavior, transport details, and how to verify results. It provides a complete mental model for an agent to invoke this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, and the schema already shows no properties. The description adds no parameter-specific details because there are none to document. This aligns with the baseline for zero-parameter tools.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Toggle') and resource ('RetroArch's pause state'), explicitly stating it pauses if running and unpauses if paused. This clearly distinguishes it from siblings like retroarch_get_status or retroarch_frame_advance, which serve different purposes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The usage section explicitly directs when to use the tool (e.g., before memory/screenshot sequences for a stable state) and names companion tools like retroarch_get_status and retroarch_frame_advance. It also warns that the NCI exposes only a toggle, preventing incorrect use as separate pause/unpause commands.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_pingA
PURPOSE: Verify connectivity to RetroArch's Network Control Interface and return the running RetroArch version string. USAGE: Call once at start-of-session before issuing other tool calls — if it succeeds, the UDP transport is up and other tools should reach RetroArch. Use retroarch_get_status afterwards to confirm a game is loaded (ping succeeds even when RetroArch is sitting at the menu with no content). BEHAVIOR: No side effects — pure liveness probe. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). Times out after ~5 seconds with a clear error if RetroArch isn't running, has Network Commands disabled, is bound to a different host/port, or a firewall is blocking UDP 55355. RETURNS: Single line 'OK — RetroArch VERSION', e.g. 'OK — RetroArch 1.20.0'.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does exceptionally well: it declares 'No side effects — pure liveness probe,' explains the UDP transport and prerequisite (network_cmd_enable = true), the default host/port, and the ~5-second timeout with an explicit list of error conditions (RetroArch not running, disabled commands, wrong host/port, firewall blocking).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is organized into labeled sections (PURPOSE, USAGE, BEHAVIOR, RETURNS) and every sentence adds value—purpose, usage context, transport details, error behavior, and return format. No fluff or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete for a zero-parameter liveness probe: it covers prerequisites, default connection details, timeout and error conditions, and the exact return format with an example. Even without an output schema or annotations, the agent has everything needed to invoke and interpret the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
This tool has 0 parameters, so the schema coverage is 100% and the baseline is 4. The description does not need to discuss parameters and doesn't, which is appropriate. It adds no parameter information because none exists.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states 'Verify connectivity to RetroArch's Network Control Interface and return the running RetroArch version string,' which is a specific verb+resource. It clearly distinguishes this from sibling tools like retroarch_get_status, which confirms game loading rather than basic connectivity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: 'Call once at start-of-session before issuing other tool calls.' It also names the alternative for verifying a loaded game: 'Use retroarch_get_status afterwards to confirm a game is loaded.' This fully addresses when to use and when to choose another tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_read_memoryA
PURPOSE: Read up to 4096 bytes from emulated memory via the libretro core's system memory map (READ_CORE_MEMORY) and return them as a hex dump. USAGE: Preferred memory-read tool when the loaded core advertises a memory map (most modern cores do). If it returns 'no memory map defined', fall back to retroarch_read_ram which uses the CHEEVOS address space. To poke a value back, pair with retroarch_write_memory at the same address. The classic two-snapshot RAM-hunt workflow uses this: snapshot before a known change, snapshot after, diff for matching deltas. Maximum 4096 bytes per call (NCI line-length limit); for larger reads, batch in 4 KiB chunks. BEHAVIOR: No side effects — pure read. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). Reads work whether emulation is paused or running. Returns an error if the loaded core doesn't expose a memory map ('no memory map defined'), the address is outside any core descriptor, length < 1, length > 4096, or the UDP query times out. RetroArch may return FEWER bytes than requested if the read crosses a memory-region boundary — the response reports the actual count.
RetroArch exposes TWO distinct memory APIs with different address spaces: • READ_CORE_MEMORY / WRITE_CORE_MEMORY (used by retroarch_read_memory / retroarch_write_memory): goes through the libretro core's system memory map. Preferred when the loaded core advertises a memory map (most modern cores do). Errors with 'no memory map defined' if the loaded core doesn't. • READ_CORE_RAM / WRITE_CORE_RAM (used by retroarch_read_ram / retroarch_write_ram): uses the achievement (CHEEVOS) address space. Works even when no core memory map is defined, but addresses follow CHEEVOS conventions, not the system bus. Use as a fallback when read_memory returns 'no memory map defined'. Both APIs depend on the loaded core's exposed mapping — addresses you used on a different core / system will NOT carry over.
RETURNS: Header line 'ADDR_HEX [N bytes]:' followed by space-separated 2-digit uppercase hex bytes.
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Starting address in the libretro core's system memory map (NOT the CHEEVOS address space — that's read_ram). Address layout depends on the loaded core: e.g. SNES WRAM is typically at 0x7E0000-0x7FFFFF, GBA EWRAM at 0x02000000-0x0203FFFF, Genesis 68K RAM at 0xFF0000-0xFFFFFF. Reads `length` consecutive bytes starting here. | |
| length | Yes | Number of consecutive bytes to read (1-4096). Hard cap is RetroArch's NCI single-datagram size; chunk larger reads yourself. RetroArch may return fewer bytes if the read crosses a memory-region boundary in the core's descriptor list. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and does so thoroughly. It discloses 'No side effects — pure read', transport details over UDP, behavior while paused/running, specific error conditions (no memory map, address out of range, length out of bounds, timeout), and the important nuance that RetroArch may return fewer bytes than requested when crossing memory-region boundaries.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear labels (PURPOSE, USAGE, BEHAVIOR, RETURNS) and is front-loaded with the primary purpose. It is longer than strictly necessary, and the distinction between the two memory APIs is explained twice (once in USAGE and again in a dedicated comparison section), but the redundancy is mild and each section adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema and no annotations, the description is remarkably complete. It describes the return format, error conditions, fallback strategy, transport prerequisites, and core-specific address behavior. The only missing element might be example output, but the return format is clearly specified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds substantial meaning beyond the schema: it provides concrete example address spaces (SNES WRAM at 0x7E0000, GBA EWRAM at 0x02000000, Genesis 68K RAM at 0xFF0000), clarifies that addresses are system-map not CHEEVOS, and explains the 4096-byte cap is due to NCI line-length limits. This goes well beyond the baseline 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource statement: 'Read up to 4096 bytes from emulated memory via the libretro core's system memory map (READ_CORE_MEMORY) and return them as a hex dump.' It clearly distinguishes this tool from retroarch_read_ram by naming the alternative and explaining when each should be used.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The USAGE section explicitly states when to use this tool versus alternatives: 'Preferred memory-read tool when the loaded core advertises a memory map (most modern cores do). If it returns 'no memory map defined', fall back to retroarch_read_ram.' It also provides a pairing recommendation with retroarch_write_memory and describes the RAM-hunt workflow, giving concrete context for use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_read_ramA
PURPOSE: Read up to 4096 bytes from emulated memory via the achievement (CHEEVOS) address space (READ_CORE_RAM) and return them as a hex dump. USAGE: Fallback memory-read tool — use when retroarch_read_memory returns 'no memory map defined' (older cores or those without an exposed system memory map can still respond to the older CHEEVOS read API). To poke back, pair with retroarch_write_ram at the same CHEEVOS address. Maximum 4096 bytes per call (NCI line-length limit). BEHAVIOR: No side effects — pure read. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). Reads work whether emulation is paused or running. Returns an error if the address is invalid for the CHEEVOS space, length < 1, length > 4096, or the UDP query times out. Like read_memory, RetroArch may return fewer bytes than requested at memory-region boundaries.
RetroArch exposes TWO distinct memory APIs with different address spaces: • READ_CORE_MEMORY / WRITE_CORE_MEMORY (used by retroarch_read_memory / retroarch_write_memory): goes through the libretro core's system memory map. Preferred when the loaded core advertises a memory map (most modern cores do). Errors with 'no memory map defined' if the loaded core doesn't. • READ_CORE_RAM / WRITE_CORE_RAM (used by retroarch_read_ram / retroarch_write_ram): uses the achievement (CHEEVOS) address space. Works even when no core memory map is defined, but addresses follow CHEEVOS conventions, not the system bus. Use as a fallback when read_memory returns 'no memory map defined'. Both APIs depend on the loaded core's exposed mapping — addresses you used on a different core / system will NOT carry over.
RETURNS: Header line 'ADDR_HEX [N bytes, CHEEVOS]:' followed by space-separated 2-digit uppercase hex bytes.
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Starting address in the CHEEVOS (achievements) address space — distinct from the libretro system memory map used by retroarch_read_memory. CHEEVOS addresses follow per-system conventions used by RetroAchievements (e.g. SNES CHEEVOS addresses for WRAM start at 0x000000, not the SNES system bus 0x7E0000). If unsure, retroarch_read_memory is usually the right starting point. | |
| length | Yes | Number of consecutive bytes to read (1-4096). Hard cap is RetroArch's NCI single-datagram size. May return fewer bytes at region boundaries. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries full burden. It discloses 'No side effects — pure read', behavior when paused/running, error conditions (invalid address, length bounds, timeout), and the caveat that fewer bytes may be returned at region boundaries. Transport and config requirements are also stated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with PURPOSE, USAGE, BEHAVIOR, API comparison, and RETURNS sections. It front-loads the core purpose and usage, and every paragraph adds necessary context for correct invocation. No fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and no annotations, the description fully covers return format, error handling, transport details, address space differences, and edge cases. It provides enough context for an agent to decide when to use this tool and interpret results correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already provides detailed parameter descriptions. The description adds extra semantic value by explaining the CHEEVOS address space distinction, cross-core non-portability of addresses, and the pairing with write_ram. This goes beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Read up to 4096 bytes from emulated memory via the achievement (CHEEVOS) address space (READ_CORE_RAM) and return them as a hex dump.' It clearly distinguishes from sibling retroarch_read_memory by explicitly naming the CHEEVOS space and framing this tool as a fallback.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance: 'use when retroarch_read_memory returns "no memory map defined"' and contrasts the two memory APIs, naming preferred vs fallback. Also suggests pairing with retroarch_write_ram for write-back, and warns that addresses don't carry over across cores.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_resetA
PURPOSE: Soft-reset the running game — equivalent to pressing the console's reset button (NOT a power cycle). USAGE: Use to start fresh from the game's reset vector. To return to a specific known-good point instead of boot, use retroarch_load_state_current or retroarch_load_state_slot with a previously saved state. Note this is a SOFT reset (button reset): RAM contents and any cart-internal state may persist depending on the system, unlike a true power cycle. BEHAVIOR: DESTRUCTIVE: triggers the loaded core's reset routine, which on most systems clears registers, resets the PC to the reset vector, and starts the boot sequence over. Unsaved game progress is lost. The loaded ROM stays loaded — only volatile state is affected. FIRE-AND-FORGET: the NCI does NOT acknowledge this command — the call returns as soon as the UDP datagram is sent, with no confirmation that RetroArch received or applied it. To verify the effect, follow up with an observable tool (retroarch_get_status for run state, retroarch_read_memory / retroarch_read_ram for memory mutations, retroarch_screenshot for visual state). UDP packets to a not-listening RetroArch are silently dropped. To confirm the reset took, follow up with retroarch_get_status (state should still be 'playing') and/or a screenshot. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). RETURNS: Single line 'Game reset' (UDP-send confirmation only — does NOT verify the reset executed).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without annotations, the description carries full burden. It discloses destructive nature ('triggers the loaded core's reset routine... Unsaved game progress is lost'), the soft-reset semantics versus power cycle, fire-and-forget behavior with no acknowledgement, and silent UDP drops. Also recommends verification via other tools.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Structured in labeled sections (PURPOSE, USAGE, BEHAVIOR, TRANSPORT, RETURNS) with the core action first. Every sentence provides necessary operational details (reset semantics, destructive effects, verification steps, transport requirements) without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (missing annotations, no output schema, zero parameters), the description covers all essential aspects: transport protocol, prerequisites, return value, side effects, and verification strategy. It also cross-references sibling tools for follow-up, making it self-sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the description cannot add parameter semantics beyond the schema. However, it clarifies the return value ('Single line 'Game reset'') and that it is only a send confirmation, which is useful context. Baseline for no params is 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the function: 'Soft-reset the running game — equivalent to pressing the console's reset button (NOT a power cycle).' Distinguishes from power cycle and mentions alternatives like load state, so it is unambiguous and differentiated from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly explains when to use: 'Use to start fresh from the game's reset vector.' Also says 'To return to a specific known-good point instead of boot, use retroarch_load_state_current or retroarch_load_state_slot...' This provides clear usage guidance and names alternative tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_save_state_currentA
PURPOSE: Save the entire emulator state to RetroArch's currently-selected save slot (one of slots 0-9). USAGE: Use as a rollback point before risky writes, to bookmark interesting game states, or to share repro states. RetroArch's NCI has NO 'save to slot N' command — to target a specific slot, you must first walk the slot pointer there with retroarch_state_slot_plus / retroarch_state_slot_minus, then call this. The current slot is RetroArch's internal state and is NOT reported back by the NCI, so if you don't track it yourself, observe the on-screen slot indicator after each plus/minus or use retroarch_show_message as a confirmation echo. The companion retroarch_load_state_current restores from the same slot. For path-based savestate I/O (no slots), there is no NCI equivalent — use the BizHawk or mGBA MCP servers instead. BEHAVIOR: DESTRUCTIVE TO TARGET SLOT FILE: overwrites whatever was previously in the currently-selected slot with no prompt or backup. The state file lands in RetroArch's configured savestate_directory (queryable via retroarch_get_config). State files are bound to the EXACT ROM and core version that produced them — loading on a different ROM or core typically fails. FIRE-AND-FORGET: the NCI does NOT acknowledge this command — the call returns as soon as the UDP datagram is sent, with no confirmation that RetroArch received or applied it. To verify the effect, follow up with an observable tool (retroarch_get_status for run state, retroarch_read_memory / retroarch_read_ram for memory mutations, retroarch_screenshot for visual state). UDP packets to a not-listening RetroArch are silently dropped. To verify the save happened, retroarch_load_state_current it back and observe via memory-read or screenshot. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). RETURNS: Single line 'Saved to current slot' (UDP-send confirmation only — does NOT verify the file was written, nor report which slot number it landed in).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and excels. It discloses that the tool is 'DESTRUCTIVE TO TARGET SLOT FILE', overwriting without prompt/backup, that it is fire-and-forget with no acknowledgment, that UDP packets can be silently dropped, and that state files are bound to ROM/core versions. Verification strategies are also provided.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but exceptionally well-structured with labeled sections (PURPOSE, USAGE, BEHAVIOR, RETURNS). Every sentence adds critical operational detail—overwrite risk, fire-and-forget behavior, verification, transport config—making it dense but not wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has no output schema, no annotations, and no parameters, so the description must fully compensate. It covers return value, failure modes, verification steps, transport prerequisites, and slot-selection mechanics. This is complete for a destructive, non-acknowledged UDP command.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4. The description adds essential meaning beyond the empty schema by explaining that the target is the 'currently-selected save slot' and how to select a specific slot using retroarch_state_slot_plus/minus. This is valuable semantic context absent from the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Save the entire emulator state to RetroArch's currently-selected save slot (one of slots 0-9).' It clearly distinguishes the save action from sibling tools like retroarch_load_state_current and retroarch_state_slot_plus.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit usage guidance is provided: 'Use as a rollback point before risky writes, to bookmark interesting game states, or to share repro states.' It also explains when NOT to use it (for path-based I/O, use BizHawk/mGBA) and how to target a specific slot via sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_screenshotA
PURPOSE: Capture a PNG screenshot of the current emulator display and save it to RetroArch's configured screenshot directory. USAGE: Use to capture visible game state for inspection, sequence documentation, or to verify that a fire-and-forget control command (pause / reset / load_state / write) had a visible effect. To capture a specific game state, pause / advance frames / load state first to get the frame you want, then call this. IMPORTANT: unlike most screenshot tools, this one DOES NOT take a path argument — RetroArch saves to its own configured screenshot_directory, which the NCI does not expose (it is NOT readable via retroarch_get_config). To find the file, check RetroArch's settings UI (Settings → Directory → Screenshots) or look at where screenshots normally land for your install. BEHAVIOR: Writes a new timestamped PNG to RetroArch's screenshot directory — no existing files are overwritten (RetroArch generates a fresh filename per shot). FIRE-AND-FORGET: the NCI does NOT acknowledge this command — the call returns as soon as the UDP datagram is sent, with no confirmation that RetroArch received or applied it. To verify the effect, follow up with an observable tool (retroarch_get_status for run state, retroarch_read_memory / retroarch_read_ram for memory mutations, retroarch_screenshot for visual state). UDP packets to a not-listening RetroArch are silently dropped. The returned message confirms only that the SCREENSHOT command was sent, not that the file was actually written (disk full, permission denied, etc. would fail silently from the tool's perspective). Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). RETURNS: Single line 'Screenshot saved to RetroArch's configured screenshot directory' (UDP-send confirmation only).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses fire-and-forget UDP behavior, no acknowledgement, silently dropped packets, lack of file-write confirmation, timestamped filenames, non-overwriting, and the inaccessible screenshot_directory. This is exceptionally thorough and leaves no critical ambiguity.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Though long, the description is well-structured with clear labeled sections (PURPOSE, USAGE, BEHAVIOR, RETURNS) and every sentence delivers necessary operational detail. It is front-loaded with the purpose and uses formatting to enhance scannability, making the length justified.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the absence of annotations and output schema, this description is remarkably complete. It covers transport prerequisites, failure modes, verification strategies, and return-value semantics, and even explains how to locate the output file. It leaves no meaningful gap for an AI agent to misinterpret or misuse the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With zero parameters and a 100% coverage baseline, the description still adds significant value by explicitly explaining why there is no path argument: RetroArch uses its own configured directory, not exposed via the NCI. This prevents the agent from assuming a path parameter exists and clarifies the tool's role despite the empty schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear, specific verb and resource: 'Capture a PNG screenshot of the current emulator display and save it to RetroArch's configured screenshot directory.' It also distinguishes itself from typical screenshot tools by explicitly stating it does NOT accept a path argument, which sets it apart from any sibling tools or generic expectations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance: for inspection, sequence documentation, or verifying visible effects of fire-and-forget commands. It explains the workflow (pause/advance/load state first) and contrasts with observation alternatives like retroarch_get_status, retroarch_read_memory, and retroarch_read_ram, making the decision boundary clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_show_messageA
PURPOSE: Display a single-line notification message overlaid on the RetroArch window (OSD overlay). USAGE: Use for in-emulator debug output, progress markers during long-running scripts, or to communicate with a human watching the RetroArch window. The overlay appears in RetroArch's standard notification area and fades out after RetroArch's configured notification timeout. This is purely cosmetic — it has no effect on game state. There is no sibling tool: this is the ONLY way to push text from the agent onto the RetroArch display. BEHAVIOR: Renders the supplied message string in RetroArch's on-screen notification area. FIRE-AND-FORGET: the NCI does NOT acknowledge this command — the call returns as soon as the UDP datagram is sent, with no confirmation that RetroArch received or applied it. To verify the effect, follow up with an observable tool (retroarch_get_status for run state, retroarch_read_memory / retroarch_read_ram for memory mutations, retroarch_screenshot for visual state). UDP packets to a not-listening RetroArch are silently dropped. Messages are not queued — calling rapidly will replace the previous message before users can read it. Line breaks in the message are stripped (NCI is line-based). Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). RETURNS: Single line 'Showed: MESSAGE' echoing what was sent (UDP-send confirmation only — does NOT verify that the overlay was actually rendered).
| Name | Required | Description | Default |
|---|---|---|---|
| message | Yes | Message text to display. Spaces inside the string are preserved; line breaks (\n / \r) are NOT — the NCI protocol is line-terminated, so newlines truncate the message. Keep messages short (one line, ~80 chars) to fit RetroArch's notification overlay without clipping. Consecutive calls replace the previous message rather than queueing. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description fully bears the burden. It thoroughly details behavior: renders the message, fire-and-forget (no acknowledgment), UDP silent drops, messages not queued, line breaks stripped, and transport requirements. This exceeds typical transparency expectations for a simple notification tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with labeled sections (PURPOSE, USAGE, BEHAVIOR, etc.), making it easy to scan. It is front-loaded with the purpose. Although it is lengthy, every sentence adds value and does not contain fluff. It could be slightly more concise, but overall it is effective.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (1 parameter, no annotations, no output schema), the description is exceptionally complete. It covers purpose, usage, behavior, limitations, transport requirements, return format, and even mentions the lack of sibling tools. An agent can fully understand how and when to use this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter 'message' has 100% schema description coverage. The description adds some context beyond the schema (e.g., fire-and-forget), but the schema already covers line breaks, consecutive calls, and length. Per guidelines, baseline is 3 when coverage is high, and while the description adds value, it does not significantly elevate parameter understanding beyond what is already in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Display a single-line notification message overlaid on the RetroArch window (OSD overlay).' It specifies the verb (display), resource (notification message), and location. It also distinguishes from siblings by stating 'this is the ONLY way to push text from the agent onto the RetroArch display.'
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit use cases: 'debug output, progress markers during long-running scripts, or to communicate with a human.' It explains when to use (cosmetic communication) and gives guidance on the fire-and-forget nature and verification steps. However, it doesn't explicitly state when NOT to use; this is implied by the context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_state_slot_minusA
PURPOSE: Decrement RetroArch's currently-selected save slot pointer by 1 (e.g. slot 3 → slot 2). USAGE: Counterpart to retroarch_state_slot_plus. Combine with retroarch_save_state_current or retroarch_load_state_current to target a lower-numbered slot — these tools always operate on the current slot. RetroArch's NCI exposes NO way to set the slot directly to N or to query the current slot number, so track it client-side or walk from a known position. For loading a specific slot WITHOUT changing the pointer, use retroarch_load_state_slot. BEHAVIOR: Mutates RetroArch's internal current-slot pointer (-1). Wraps or clamps per RetroArch's slot-cycling configuration (typically wraps at 0 → 9). FIRE-AND-FORGET: the NCI does NOT acknowledge this command — the call returns as soon as the UDP datagram is sent, with no confirmation that RetroArch received or applied it. To verify the effect, follow up with an observable tool (retroarch_get_status for run state, retroarch_read_memory / retroarch_read_ram for memory mutations, retroarch_screenshot for visual state). UDP packets to a not-listening RetroArch are silently dropped. The new slot number is NOT reported back — track it client-side or watch the on-screen slot indicator. No effect on emulator memory / run state — only the slot pointer used by future save_state_current / load_state_current calls changes. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). RETURNS: Single line 'Decremented current slot' (UDP-send confirmation only — does NOT report the new slot number).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses behavior: it mutates the pointer, wraps/clamps, is fire-and-forget with no acknowledgment, UDP packets are silently dropped, and no slot number is returned. It also notes no effect on emulator memory/run state. This is exemplary transparency for a network command tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with labeled sections (PURPOSE, USAGE, BEHAVIOR, FIRE-AND-FORGET, Transport, RETURNS) and front-loads the core purpose. However, it is somewhat verbose with minor redundancy, such as repeating that the new slot number is not reported back in both the BEHAVIOR and RETURNS sections.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (mutating RetroArch state via UDP), the description covers all necessary context: prerequisites, exact behavior, consequences, verification methods, and return value. It also addresses the lack of an output schema by explaining what the return line means.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and an empty schema, so there is nothing to explain; baseline 4 applies. The description adds value by explaining the unspoken semantics of the operation itself, though no parameter-specific detail is needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description begins with 'Decrement RetroArch's currently-selected save slot pointer by 1' which clearly states the verb, resource, and expected effect. It also distinguishes from siblings by naming retroarch_state_slot_plus and retroarch_load_state_slot, making the tool's unique role unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance is provided: 'Counterpart to retroarch_state_slot_plus' and 'For loading a specific slot WITHOUT changing the pointer, use retroarch_load_state_slot.' It also advises tracking the slot client-side because no direct set/query exists, giving clear context on when and how to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_state_slot_plusA
PURPOSE: Increment RetroArch's currently-selected save slot pointer by 1 (e.g. slot 3 → slot 4). USAGE: Combine with retroarch_save_state_current or retroarch_load_state_current to target a specific slot — these tools always operate on the current slot, so to save TO slot 5 you must walk the pointer there first. Pair with retroarch_state_slot_minus to walk backwards. RetroArch's NCI exposes NO way to set the slot directly to N or to query the current slot number, so if you don't track it yourself you must walk from a known position (e.g. slot 0) or observe the on-screen indicator. For loading a specific slot WITHOUT changing the pointer, use retroarch_load_state_slot instead. BEHAVIOR: Mutates RetroArch's internal current-slot pointer (+1). Wraps or clamps per RetroArch's slot-cycling configuration (typically wraps at 9 → 0). FIRE-AND-FORGET: the NCI does NOT acknowledge this command — the call returns as soon as the UDP datagram is sent, with no confirmation that RetroArch received or applied it. To verify the effect, follow up with an observable tool (retroarch_get_status for run state, retroarch_read_memory / retroarch_read_ram for memory mutations, retroarch_screenshot for visual state). UDP packets to a not-listening RetroArch are silently dropped. The new slot number is NOT reported back — track it client-side or watch the on-screen slot indicator. No effect on emulator memory / run state — only the slot pointer used by future save_state_current / load_state_current calls changes. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). RETURNS: Single line 'Incremented current slot' (UDP-send confirmation only — does NOT report the new slot number).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses mutation of the internal pointer, wrap/clamp behavior, fire-and-forget semantics with no acknowledgment, silent UDP drops, lack of slot-number reporting, and no effect on memory/run state. This is exemplary transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with PURPOSE, then USAGE, BEHAVIOR, and RETURNS. Though long, every sentence addresses a distinct operational need (e.g., NCI limitations, verification strategies, return behavior), and there is no fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no annotations, no output schema, and zero parameters, the description must be self-sufficient. It covers purpose, usage, behavioral caveats, transport, verification, and return format — complete for the complexity of a fire-and-forget UDP command.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
This tool has zero parameters, so the schema coverage is 100% vacuously. The baseline for 0 params is 4; the description adds no parameter-specific details because none exist, but it explains the operational semantics fully without needing parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description begins with a specific verb and resource: 'Increment RetroArch's currently-selected save slot pointer by 1 (e.g. slot 3 → slot 4).' This clearly distinguishes it from siblings like retroarch_state_slot_minus and retroarch_load_state_slot.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Extremely explicit usage guidance: combine with save_state_current/load_state_current, pair with state_slot_minus, and explicitly states when to use retroarch_load_state_slot instead. It also warns about the inability to set the slot directly, which is critical for correct tool selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_write_memoryA
PURPOSE: Write a byte sequence to emulated memory via the libretro core's system memory map (WRITE_CORE_MEMORY). USAGE: Preferred memory-write tool when the loaded core advertises a memory map. Use for cheats, debug pokes, and game-state mutations (give a player N lives, unlock a flag, install a cheat table). If it returns 'no memory map defined', fall back to retroarch_write_ram. Maximum 4096 bytes per call (NCI line-length limit); for larger writes, batch in 4 KiB chunks. To establish a rollback point first, use retroarch_save_state_current. BEHAVIOR: DESTRUCTIVE: overwrites N bytes starting at address with no undo (snapshot via retroarch_save_state_current first if you need rollback). Disables RetroArch's hardcore mode for the rest of the session (RetroArch silently flips this flag when any memory-write NCI command is used). UNLIKE most NCI commands, this one DOES return a count — RetroArch replies with the number of bytes actually written, which may be less than requested if a read-only descriptor is hit mid-write (writes still apply up to that boundary). Direct memory write — bypasses MBC/mapper/DMA semantics. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). Returns an error if the loaded core doesn't expose a memory map, the address is invalid, the byte array is empty or > 4096, or the UDP query times out.
RetroArch exposes TWO distinct memory APIs with different address spaces: • READ_CORE_MEMORY / WRITE_CORE_MEMORY (used by retroarch_read_memory / retroarch_write_memory): goes through the libretro core's system memory map. Preferred when the loaded core advertises a memory map (most modern cores do). Errors with 'no memory map defined' if the loaded core doesn't. • READ_CORE_RAM / WRITE_CORE_RAM (used by retroarch_read_ram / retroarch_write_ram): uses the achievement (CHEEVOS) address space. Works even when no core memory map is defined, but addresses follow CHEEVOS conventions, not the system bus. Use as a fallback when read_memory returns 'no memory map defined'. Both APIs depend on the loaded core's exposed mapping — addresses you used on a different core / system will NOT carry over.
RETURNS: Single line 'Wrote N bytes → ADDR_HEX' where N is RetroArch's reported actual byte count.
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Starting address in the libretro core's system memory map (NOT CHEEVOS space). Bytes are written sequentially address, address+1, ..., address+N-1. | |
| bytes | Yes | Byte values to write, one per element (each 0-255). Length 1-4096 (hard cap from RetroArch's NCI single-datagram size). Written sequentially from `address`. If a read-only descriptor is encountered mid-array, the write stops at that boundary and the response reports how many bytes actually landed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, but the description fully discloses behavioral traits: it is DESTRUCTIVE with no undo, disables RetroArch's hardcore mode, may write fewer bytes than requested if a read-only descriptor is hit, and returns an actual byte count. This goes well beyond the basic 'writes memory' expectation and covers side effects and edge cases.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with clear PURPOSE, USAGE, BEHAVIOR, and RETURNS sections. Every section adds essential information—fallback logic, destructive side effects, return format, and error conditions—with no filler or redundancy. The structure makes it easy for an agent to parse and extract key facts quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description explicitly states the return format ('Wrote N bytes → ADDR_HEX') and explains the meaning of the count. It also covers error cases, prerequisites (network_cmd_enable), the distinction between the two memory APIs, and the fact that addresses don't carry across cores. This makes the tool fully understandable without external documentation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides highly detailed descriptions for both parameters, including the 0-255 range, 1-4096 length cap, sequential write behavior, and the distinction from CHEEVOS space (100% coverage). The description adds little new parameter-specific meaning beyond the schema, mostly repeating or rephrasing the same constraints, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Write a byte sequence to emulated memory via the libretro core's system memory map (WRITE_CORE_MEMORY).' It clearly identifies the target memory space and distinguishes this tool from the sibling retroarch_write_ram by stating this is the 'preferred' tool when a memory map is advertised.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit usage context: 'Use for cheats, debug pokes, and game-state mutations.' It names an alternative tool (retroarch_write_ram) as a fallback and specifies a prerequisite (use retroarch_save_state_current for rollback). This makes the when-to-use vs. when-not-to-use very clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retroarch_write_ramA
PURPOSE: Write a byte sequence to emulated memory via the achievement (CHEEVOS) address space (WRITE_CORE_RAM). USAGE: Fallback memory-write tool — use when retroarch_write_memory returns 'no memory map defined' or the core only supports the older CHEEVOS write API. Maximum 4096 bytes per call (NCI line-length limit). To verify the write landed (this command does NOT acknowledge — see BEHAVIOR), follow up with retroarch_read_ram at the same address. To establish a rollback point first, use retroarch_save_state_current. BEHAVIOR: DESTRUCTIVE: overwrites bytes starting at address with no undo (snapshot via retroarch_save_state_current first if you need rollback). Disables RetroArch's hardcore mode for the rest of the session. FIRE-AND-FORGET: the NCI does NOT acknowledge this command — the call returns as soon as the UDP datagram is sent, with no confirmation that RetroArch received or applied it. To verify the effect, follow up with an observable tool (retroarch_get_status for run state, retroarch_read_memory / retroarch_read_ram for memory mutations, retroarch_screenshot for visual state). UDP packets to a not-listening RetroArch are silently dropped. This is the key behavioral difference vs retroarch_write_memory, which DOES return a count: write_ram has no way to report a partial write or a rejected address — the only way to verify is a follow-up retroarch_read_ram. Direct memory write — bypasses MBC/mapper/DMA semantics. Transport: RetroArch's Network Control Interface (NCI) over UDP (default 127.0.0.1:55355, requires network_cmd_enable = true in retroarch.cfg). Local input validation rejects empty arrays, > 4096 bytes, or values outside 0-255 before the UDP send.
RetroArch exposes TWO distinct memory APIs with different address spaces: • READ_CORE_MEMORY / WRITE_CORE_MEMORY (used by retroarch_read_memory / retroarch_write_memory): goes through the libretro core's system memory map. Preferred when the loaded core advertises a memory map (most modern cores do). Errors with 'no memory map defined' if the loaded core doesn't. • READ_CORE_RAM / WRITE_CORE_RAM (used by retroarch_read_ram / retroarch_write_ram): uses the achievement (CHEEVOS) address space. Works even when no core memory map is defined, but addresses follow CHEEVOS conventions, not the system bus. Use as a fallback when read_memory returns 'no memory map defined'. Both APIs depend on the loaded core's exposed mapping — addresses you used on a different core / system will NOT carry over.
RETURNS: Single line 'Wrote N bytes → ADDR_HEX (CHEEVOS, no ack)' where N is the array length you sent. The 'no ack' in the message is a reminder that RetroArch did not confirm the write.
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | Starting address in the CHEEVOS (achievements) address space — distinct from the libretro system memory map used by retroarch_write_memory. See retroarch_read_ram for address-space caveats. Bytes are written sequentially address, address+1, ... | |
| bytes | Yes | Byte values to write, one per element (each 0-255). Length 1-4096 (hard cap from RetroArch's NCI single-datagram size). Written sequentially from `address`. Because RetroArch does not acknowledge this command, partial / rejected writes cannot be distinguished from successful ones at the protocol level. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden and excels. It discloses destructive overwrites with no undo, hardcore-mode disabling, fire-and-forget semantics with no acknowledgment, silent UDP drops, input validation limits, and bypassing of MBC/mapper/DMA semantics. This level of behavioral disclosure is exceptional.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with clear PURPOSE, USAGE, BEHAVIOR, and RETURNS sections, plus a bulleted comparison of the two memory APIs. It is appropriately detailed for a complex tool. Minor redundancy in repeating 'no ack' in multiple places costs a point, but overall it earns its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, no output schema, and no annotations, the description is remarkably complete. It covers purpose, alternatives, behavioral caveats, transport requirements, input validation, return format, and verification strategies. It even notes the two distinct memory APIs and address-space non-portability across cores, leaving no critical gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description adds substantial meaning beyond the schema: the 4096-byte NCI line-length cap, the distinct CHEEVOS address-space interpretation, sequential write ordering, and the implication of no acknowledgment for partial writes. It also clarifies that `bytes` length maps to the protocol limit and that `address` follows CHEEVOS conventions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Write a byte sequence to emulated memory via the achievement (CHEEVOS) address space (WRITE_CORE_RAM).' It clearly distinguishes itself from the sibling retroarch_write_memory by naming the CHEEVOS address space and its role as a fallback, making the tool's purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool: 'use when retroarch_write_memory returns no memory map defined or the core only supports the older CHEEVOS write API.' It also contrasts the two memory APIs, advises using retroarch_save_state_current for a rollback point, and explains when to follow up with other tools. This is exemplary usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
7 tool updates
v0.1.2- Changed
retroarch_get_config2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / name / descriptionPrevious value: -"Config parameter name (see description for supported values)"New value: +"Config parameter name (case-sensitive). Commonly-supported values: `savefile_directory`, `savestate_directory`, `system_directory`, `cache_directory`, `log_dir`, `runtime_log_directory`, `netplay_nickname`, `video_fullscreen`. RetroArch's exact whitelist varies by version; if a name returns an error, it isn't exposed via the NCI on this build. `screenshot_directory` is NOT exposed by RetroArch — there is no NCI way to query the screenshot output path."
- Changed
retroarch_load_state_slot2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / slot / descriptionPrevious value: -"Save state slot number"New value: +"Save state slot number to load from. RetroArch's standard slot range is 0-9 (ten slots), but the NCI does not enforce a hard upper bound — slot numbers outside the configured range will simply find no file and silently no-op. This call does NOT change the currently-selected slot pointer (use retroarch_state_slot_plus / retroarch_state_slot_minus for that)."
- Changed
retroarch_read_memory4 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / address / descriptionPrevious value: -"Memory address (in the core's address space)"New value: +"Starting address in the libretro core's system memory map (NOT the CHEEVOS address space — that's read_ram). Address layout depends on the loaded core: e.g. SNES WRAM is typically at 0x7E0000-0x7FFFFF, GBA EWRAM at 0x02000000-0x0203FFFF, Genesis 68K RAM at 0xFF0000-0xFFFFFF. Reads `length` consecutive bytes starting here." - added
Input schema / properties / address / minimumAdded value: +0 - added
Input schema / properties / length / descriptionAdded value: +"Number of consecutive bytes to read (1-4096). Hard cap is RetroArch's NCI single-datagram size; chunk larger reads yourself. RetroArch may return fewer bytes if the read crosses a memory-region boundary in the core's descriptor list."
- Changed
retroarch_read_ram4 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / address / descriptionAdded value: +"Starting address in the CHEEVOS (achievements) address space — distinct from the libretro system memory map used by retroarch_read_memory. CHEEVOS addresses follow per-system conventions used by RetroAchievements (e.g. SNES CHEEVOS addresses for WRAM start at 0x000000, not the SNES system bus 0x7E0000). If unsure, retroarch_read_memory is usually the right starting point." - added
Input schema / properties / address / minimumAdded value: +0 - added
Input schema / properties / length / descriptionAdded value: +"Number of consecutive bytes to read (1-4096). Hard cap is RetroArch's NCI single-datagram size. May return fewer bytes at region boundaries."
- Changed
retroarch_show_message2 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / message / descriptionPrevious value: -"Message text. Spaces are kept; line breaks are not."New value: +"Message text to display. Spaces inside the string are preserved; line breaks (\\n / \\r) are NOT — the NCI protocol is line-terminated, so newlines truncate the message. Keep messages short (one line, ~80 chars) to fit RetroArch's notification overlay without clipping. Consecutive calls replace the previous message rather than queueing."
- Changed
retroarch_write_memory4 fields changed- added
Input schema / additionalPropertiesAdded value: +false - changed
Input schema / properties / address / descriptionPrevious value: -"Memory address"New value: +"Starting address in the libretro core's system memory map (NOT CHEEVOS space). Bytes are written sequentially address, address+1, ..., address+N-1." - added
Input schema / properties / address / minimumAdded value: +0 - added
Input schema / properties / bytes / descriptionAdded value: +"Byte values to write, one per element (each 0-255). Length 1-4096 (hard cap from RetroArch's NCI single-datagram size). Written sequentially from `address`. If a read-only descriptor is encountered mid-array, the write stops at that boundary and the response reports how many bytes actually landed."
- Changed
retroarch_write_ram4 fields changed- added
Input schema / additionalPropertiesAdded value: +false - added
Input schema / properties / address / descriptionAdded value: +"Starting address in the CHEEVOS (achievements) address space — distinct from the libretro system memory map used by retroarch_write_memory. See retroarch_read_ram for address-space caveats. Bytes are written sequentially address, address+1, ..." - added
Input schema / properties / address / minimumAdded value: +0 - added
Input schema / properties / bytes / descriptionAdded value: +"Byte values to write, one per element (each 0-255). Length 1-4096 (hard cap from RetroArch's NCI single-datagram size). Written sequentially from `address`. Because RetroArch does not acknowledge this command, partial / rejected writes cannot be distinguished from successful ones at the protocol level."
17 tool updates
v0.1.1- First observed
retroarch_frame_advance - First observed
retroarch_get_config - First observed
retroarch_get_status - First observed
retroarch_load_state_current - First observed
retroarch_load_state_slot - First observed
retroarch_pause_toggle - First observed
retroarch_ping - First observed
retroarch_read_memory - First observed
retroarch_read_ram - First observed
retroarch_reset - First observed
retroarch_save_state_current - First observed
retroarch_screenshot - First observed
retroarch_show_message - First observed
retroarch_state_slot_minus - First observed
retroarch_state_slot_plus - First observed
retroarch_write_memory - First observed
retroarch_write_ram
TDQS
Scored across 17 tools
Every tool has a clearly distinct purpose. Memory read/write tools are explicitly differentiated by API (core memory map vs. CHEEVOS), save/load state tools distinguish between current slot and specific slot, and control tools (pause, reset, frame advance) have non-overlapping functions. The descriptions thoroughly clarify boundaries.
All tool names follow a consistent 'retroarch_verb_noun' pattern in snake_case (e.g., retroarch_read_memory, retroarch_pause_toggle, retroarch_state_slot_plus). Verbs are imperative and nouns are specific, making the naming predictable and self-explanatory.
17 tools cover the necessary operations for emulator control via RetroArch's NCI: connectivity, status, config, controls, state management, memory access, screenshot, and messaging. The count is well-scoped for the domain, with no superfluous tools and no critical gaps.
The tool set covers all major NCI capabilities: connectivity check, status, config, pause/reset/frame advance, save/load state with slot management, memory read/write via two APIs, screenshot, and OSD messaging. Within the scope of runtime emulator control, it is fully complete.
Maintenance
Related MCP Connectors
Official remote MCP server for Archivist AI TTRPG campaign memory: characters, sessions, and more.
Remote MCP server to read and manage your Atako AI agents, messages, files, and integrations.
The official MCP Server for the Mux API
- ArcjetOAuthcom.arcjet
An MCP server for Arcjet - the runtime security platform that ships with your AI code.
Related MCP Servers
- AlicenseAqualityCmaintenanceMCP server for PCSX2 and other emulators that speak the PINE protocol. Read and write 8/16/32/64-bit emulator memory and control save states for PlayStation-family emulation.1417 npm2MIT
- 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.1816 npm2MIT
- AlicenseAqualityCmaintenanceMCP server for BizHawk, the multi-system emulator. Drive NES, SNES, GB/GBC/GBA, Genesis, N64, PSX, Saturn and more through one Lua bridge — memory r/w across named domains, joypad input, frame-advance, screenshot, save/load state.2018 npm4MIT
- AlicenseAqualityBmaintenanceAn MCP server that exposes PPSSPP — the PlayStation Portable emulator — to any MCP-compatible client (Claude Desktop, Claude Code, etc.) via PPSSPP's built-in WebSocket debugger interface. Read and write PSP memory, drive games with button input, capture screenshots, set CPU breakpoints, inspect MIPS Allegrex registers — all through a clean tool interface. No bridge plugin needed; PPSSPP's debugg2319 npm8MIT