retroarch_ping
Confirm that RetroArch's Network Control Interface is accessible and retrieve its version string to verify connectivity.
Instructions
Verify connectivity to RetroArch's Network Control Interface. Returns the RetroArch version string if reachable.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/tools.ts:184-187 (handler)Handler for retroarch_ping: calls ra.getVersion() and returns 'OK — RetroArch <version>'. This is the actual tool execution logic.
case "retroarch_ping": { const v = await ra.getVersion(); return ok(`OK — RetroArch ${v}`); } - src/tools.ts:21-25 (schema)Schema/definition of the retroarch_ping tool in the TOOLS array. Has no input parameters (empty inputSchema) and verifies connectivity to RetroArch's NCI returning the version string.
{ name: "retroarch_ping", description: "Verify connectivity to RetroArch's Network Control Interface. Returns the RetroArch version string if reachable.", inputSchema: { type: "object", properties: {} }, }, - src/retroarch.ts:123-126 (helper)getVersion() method on RetroArchClient: sends 'VERSION' UDP query to RetroArch and returns the trimmed response string. This is the low-level helper that the handler delegates to.
async getVersion(): Promise<string> { const r = await this.query("VERSION"); return r.toString().trim(); } - src/tools.ts:176-246 (registration)registerTools function that registers all tools (including retroarch_ping) on the MCP server via setRequestHandler for both ListToolsRequestSchema and CallToolRequestSchema. The switch-case at line 183 dispatches to the retroarch_ping handler.
export function registerTools(server: Server, ra: RetroArchClient): void { server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS })); server.setRequestHandler(CallToolRequestSchema, async (req) => { const { name, arguments: args = {} } = req.params; const p = args as Record<string, unknown>; switch (name) { case "retroarch_ping": { const v = await ra.getVersion(); return ok(`OK — RetroArch ${v}`); } case "retroarch_get_status": { const s = await ra.getStatus(); if (s.state === "contentless") return ok("No content loaded"); return ok( `State: ${s.state}\n` + `System: ${s.system}\n` + `Game: ${s.game}\n` + `CRC32: ${s.crc32 ?? "(none reported)"}`, ); } case "retroarch_get_config": { const v = await ra.getConfigParam(p.name as string); return ok(`${p.name} = ${v}`); } case "retroarch_read_memory": { const bytes = await ra.readMemory(p.address as number, p.length as number); const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0").toUpperCase()).join(" "); return ok(`${addrHex(p.address as number)} [${bytes.length} bytes]:\n${hex}`); } case "retroarch_write_memory": { const n = await ra.writeMemory(p.address as number, p.bytes as number[]); return ok(`Wrote ${n} bytes → ${addrHex(p.address as number)}`); } case "retroarch_read_ram": { const bytes = await ra.readRam(p.address as number, p.length as number); const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0").toUpperCase()).join(" "); return ok(`${addrHex(p.address as number)} [${bytes.length} bytes, CHEEVOS]:\n${hex}`); } case "retroarch_write_ram": { await ra.writeRam(p.address as number, p.bytes as number[]); return ok(`Wrote ${(p.bytes as number[]).length} bytes → ${addrHex(p.address as number)} (CHEEVOS, no ack)`); } case "retroarch_pause_toggle": await ra.pauseToggle(); return ok("Pause toggled"); case "retroarch_frame_advance": await ra.frameAdvance(); return ok("Advanced one frame"); case "retroarch_reset": await ra.reset(); return ok("Game reset"); case "retroarch_screenshot": await ra.screenshot(); return ok("Screenshot saved to RetroArch's configured screenshot directory"); case "retroarch_show_message": { await ra.showMessage(p.message as string); return ok(`Showed: ${p.message}`); } case "retroarch_save_state_current": await ra.saveStateCurrent(); return ok("Saved to current slot"); case "retroarch_load_state_current": await ra.loadStateCurrent(); return ok("Loaded from current slot"); case "retroarch_load_state_slot": await ra.loadStateSlot(p.slot as number); return ok(`Loaded from slot ${p.slot}`); case "retroarch_state_slot_plus": await ra.stateSlotPlus(); return ok("Incremented current slot"); case "retroarch_state_slot_minus": await ra.stateSlotMinus(); return ok("Decremented current slot"); default: throw new Error(`Unknown tool: ${name}`); } }); } - src/index.ts:18-43 (registration)Server creation and registration call: creates the MCP Server instance and calls registerTools(server, ra) to wire up all tools including retroarch_ping.
const server = new Server( { name: "mcp-retroarch", version: "0.1.1" }, { capabilities: { tools: {} } }, ); registerTools(server, ra); const transport = new StdioServerTransport(); await server.connect(transport); process.stderr.write("[mcp-retroarch] MCP server ready (stdio)\n"); // Background connectivity probe — fire-and-forget, never blocks the server. ra.connect() .then(() => ra.getVersion()) .then((v) => process.stderr.write(`[mcp-retroarch] connected to ${ra.describeTarget()} — RetroArch ${v}\n`)) .catch((err) => process.stderr.write( `[mcp-retroarch] note: RetroArch not reachable yet (${ra.describeTarget()}): ${err}\n` + ` Enable Network Commands in retroarch.cfg (network_cmd_enable / network_cmd_port)\n` + ` or Settings > Network > Network Commands. Tool calls will connect on demand.\n`, )); } main().catch((err) => { process.stderr.write(`[mcp-retroarch] fatal: ${err}\n`); process.exit(1); });