ppsspp_write16
Write a 16-bit little-endian value to PSP memory for game cheats such as HP, score, or coordinates. Overwrites two bytes at the specified address.
Instructions
PURPOSE: Write an unsigned 16-bit little-endian value to PSP memory. USAGE: Use for 16-bit cheats and pokes (HP, score, coordinates). For single bytes use ppsspp_write8; for 32/larger use ppsspp_write32/write_range. BEHAVIOR: DESTRUCTIVE: overwrites two bytes with no undo. PSP is little-endian (low byte at address, high at address+1). Returns an error if address+2 exceeds valid memory or value > 65535. RETURNS: Single line 'Wrote VAL → ADDR_HEX'.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| address | Yes | PSP physical address. PSP memory layout: user RAM starts at 0x08800000 (or 0x08000000 — varies by firmware allocation), kernel RAM at 0x08000000-0x087FFFFF, VRAM at 0x04000000-0x041FFFFF, scratchpad at 0x00010000-0x00013FFF, hardware regs at 0xBC000000+. Most game state lives in user RAM. Note PPSSPP may also accept 0x88xxxxxx kernel-mode mirrors of the same physical memory. | |
| value | Yes | 16-bit value (0-65535). |
Implementation Reference
- src/tools.ts:163-178 (schema)Input schema for ppsspp_write16 tool: defines the tool name, description, and inputSchema with address (integer) and value (0-65535) parameters.
{ name: "ppsspp_write16", description: "PURPOSE: Write an unsigned 16-bit little-endian value to PSP memory. " + "USAGE: Use for 16-bit cheats and pokes (HP, score, coordinates). For single bytes use ppsspp_write8; for 32/larger use ppsspp_write32/write_range. " + "BEHAVIOR: DESTRUCTIVE: overwrites two bytes with no undo. PSP is little-endian (low byte at `address`, high at address+1). Returns an error if address+2 exceeds valid memory or value > 65535. " + "RETURNS: Single line 'Wrote VAL → ADDR_HEX'.", inputSchema: { type: "object", required: ["address", "value"], properties: { address: { type: "integer", minimum: 0, description: ADDRESS_PARAM_DESC }, value: { type: "integer", minimum: 0, maximum: 65535, description: "16-bit value (0-65535)." }, }, additionalProperties: false, }, - src/tools.ts:461-463 (handler)Handler for ppsspp_write16: calls PPSSPP's memory.write_u16 via WebSocket with the address and value, then returns success message 'Wrote VAL → ADDR_HEX'.
case "ppsspp_write16": { await pp.call("memory.write_u16", { address: a(), value: p.value }); return ok(`Wrote ${fmtHex(p.value)} → ${addrHex(a())}`); - src/tools.ts:405-412 (registration)The registerTools function registers all tools (including ppsspp_write16) with the MCP server via ListToolsRequestSchema and CallToolRequestSchema handlers.
export function registerTools(server: Server, pp: PpssppClient): 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>; const a = () => p.address as number; - src/tools.ts:394-403 (helper)Helper functions used by the handler: ok() formats success responses, fmtHex() formats numbers as decimal+hex, addrHex() formats addresses as zero-padded hex.
function ok(text: string) { return { content: [{ type: "text" as const, text }] }; } function fmtHex(n: unknown): string { if (typeof n !== "number") return String(n); return `${n} (0x${n.toString(16).toUpperCase()})`; } function addrHex(n: number): string { return `0x${n.toString(16).toUpperCase().padStart(8, "0")}`; } - src/ppsspp.ts:235-272 (helper)The PpssppClient.call() method - core WebSocket RPC client used by ppsspp_write16 handler to send the 'memory.write_u16' request to PPSSPP.
async call<T extends Record<string, unknown> = Record<string, unknown>>( event: string, params: Record<string, unknown> = {}, ): Promise<T> { // Auto-(re)connect on demand. PPSSPP can be launched, closed, relaunched // at any point during the MCP server's lifetime; ensureConnected() will // bring the socket back up (or throw a clear error if PPSSPP isn't // reachable). Without this, a single failed connect at MCP boot would // leave every subsequent tool call broken until MCP-client restart. await this.ensureConnected(); return new Promise<T>((resolve, reject) => { const ticket = `t${this.nextTicket++}`; const pending: PendingCmd = { ticket, resolve: (r) => resolve(r as T), reject, }; const timer = setTimeout(() => { this.inflight.delete(ticket); reject(new Error( `PPSSPP call "${event}" timed out (${this.timeoutMs}ms) — ` + `is PPSSPP running with "Allow remote debugger" enabled?`, )); }, this.timeoutMs); const origResolve = pending.resolve, origReject = pending.reject; pending.resolve = (r) => { clearTimeout(timer); origResolve(r); }; pending.reject = (e) => { clearTimeout(timer); origReject(e); }; this.inflight.set(ticket, pending); const msg = JSON.stringify({ event, ticket, ...params }); if (process.env.MCP_PPSSPP_DEBUG) { process.stderr.write(`[trace] TX: ${msg}\n`); } this.ws!.send(msg); }); } }