Skip to main content
Glama
AstralVoidZ
by AstralVoidZ

ppsspp_read_memory

Read-onlyIdempotent

Read PSP emulator memory at any address to inspect raw bytes, 32-bit integers, or ASCII strings during live debugging sessions.

Instructions

PURPOSE: Read memory (read_bytes / read_u32 / read_string).

USAGE: action; session_id optional when exactly one session is active; address as '0x' hex string; read_bytes ≤65536 per call (split larger reads); Memory scanning has moved to ppsspp_scan.

BEHAVIOR: READ-ONLY. read_string is ASCII-only (use read_bytes + Shift-JIS decode for game text). Reading code segments: use ppsspp_disassemble — MCP provides no IR-encoding detection (a read_u32 over JIT-IR bytes just returns the raw value).

RETURNS: {action, address, value, size, text, file} — read_bytes has output=value (default; byte list + hex text) / hex (text only, value=null) / file (paths + 64-byte preview; payload saved under .ppsspp-dfx/output/memory_reads/).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
sizeNoNumber of bytes to read (read_bytes only). Max 65536 per call (MAX_SINGLE_READ_BYTES); larger reads are rejected with ARGS_INVALID -- chunk them instead.
actionYesRead action. Valid values: - 'read_bytes': read raw bytes (requires address + size). - 'read_u32': read a 32-bit unsigned int (requires address). - 'read_string': read a string (requires address).
lengthNo(deprecated, ignored) PPSSPP memory.readString does not accept a length parameter. Kept for backward schema compatibility.
outputNoPayload channel for read_bytes (ignored by other actions). 'value' (default) returns the byte list inline plus a hex dump in `text`. 'hex' keeps only the hex dump in `text` (value=null) — roughly half the characters. 'file' saves raw bytes + hex dump under .ppsspp-dfx/output/memory_reads/ and returns the paths plus a 64-byte preview — use for reads near the 65536-byte cap.value
addressNoRequired for every action. Starting address for read_bytes/read_u32/read_string, as a hex string (e.g. '0x08804000'). The schema default of '0x0' exists for legacy callers -- do NOT rely on it.0x0
max_lenNoMaximum string length in bytes for read_string (0 = default cap 4096). Values are clamped to 65536.
session_idNoActive session ID; omit to auto-resolve when exactly one session is active.

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
fileYesAbsolute path of the saved raw-byte file when read_bytes ran with output='file' (hex dump sits beside it as <file>.hex.txt); empty string otherwise.
sizeYesNumber of bytes read (read_bytes), or number of matches (scan). Unused for read_u32 / read_string.
textYesUnified text representation following spec conventions: '0xADDR: VAL (0xVAL_HEX)' for read_u32 (8-digit zero-padded hex), hex dump for read_bytes, repr for read_string, 'scan: N matches at 0xA1, 0xA2, ...' for scan.
valueYesRead value (int/str/list[int]/list[dict] depending on action).
actionYesRead action performed ('read_bytes'/'read_u32'/'read_string'/'scan').
addressYesStarting address, hex string (e.g. '0x08804000').

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed4 schema fields changedv0.1.7
    • changedInput schema / properties / action / description
      Previous value: -"Read action. Valid values:\n- 'read_bytes': read raw bytes (requires address + size).\n- 'read_u32': read a 32-bit unsigned int (requires address).\n- 'read_string': read a string (requires address).\npattern + start_addr + end_addr). Optional max_results (default 100)."New value: +"Read action. Valid values:\n- 'read_bytes': read raw bytes (requires address + size).\n- 'read_u32': read a 32-bit unsigned int (requires address).\n- 'read_string': read a string (requires address).\n"
    • changedInput schema / properties / address / description
      Previous value: -"Starting address for read_bytes/read_u32/read_string, as a hex string (e.g. '0x08804000')."New value: +"Required for every action. Starting address for read_bytes/read_u32/read_string, as a hex string (e.g. '0x08804000'). The schema default of '0x0' exists for legacy callers -- do NOT rely on it."
    • changedInput schema / properties / size / description
      Previous value: -"Number of bytes to read (read_bytes only)."New value: +"Number of bytes to read (read_bytes only). Max 65536 per call (MAX_SINGLE_READ_BYTES); larger reads are rejected with ARGS_INVALID -- chunk them instead."
    • changedOutput schema / properties / text / description
      Previous value: -"Unified text representation following spec conventions: '0xADDR: VAL (0xVAL_HEX)' for read_u32, hex dump for read_bytes, repr for read_string, 'scan: N matches at 0xA1, 0xA2, ...' for scan."New value: +"Unified text representation following spec conventions: '0xADDR: VAL (0xVAL_HEX)' for read_u32 (8-digit zero-padded hex), hex dump for read_bytes, repr for read_string, 'scan: N matches at 0xA1, 0xA2, ...' for scan."
  2. Changed10 schema fields changedv0.1.6
    • changedInput schema / properties / action / description
      Previous value: -"Read action. Valid values:\n- 'read_bytes': read raw bytes (requires address + size).\n- 'read_u32': read a 32-bit unsigned int (requires address).\n- 'read_string': read a string (requires address).\n- 'scan': scan memory for a pattern (requires pattern + start_addr + end_addr). Optional max_results (default 100)."New value: +"Read action. Valid values:\n- 'read_bytes': read raw bytes (requires address + size).\n- 'read_u32': read a 32-bit unsigned int (requires address).\n- 'read_string': read a string (requires address).\npattern + start_addr + end_addr). Optional max_results (default 100)."
    • changedInput schema / properties / action / enum
      Previous value: -[
      -  "read_bytes",
      -  "read_u32",
      -  "read_string",
      -  "scan"
      -]New value: +[
      +  "read_bytes",
      +  "read_u32",
      +  "read_string"
      +]
    • changedInput schema / properties / address / description
      Previous value: -"Starting address for read_bytes/read_u32/read_string, as a hex string (e.g. '0x08804000'). Ignored for scan (use start_addr)."New value: +"Starting address for read_bytes/read_u32/read_string, as a hex string (e.g. '0x08804000')."
    • removedInput schema / properties / chunk_size
      Removed value: -{
      -  "default": 4096,
      -  "description": "Bytes per read request during scan (scan only, default 4096). Larger values reduce round-trips but increase per-read latency.",
      -  "title": "Chunk Size",
      -  "type": "integer"
      -}
    • removedInput schema / properties / end_addr
      Removed value: -{
      -  "default": "0x0",
      -  "description": "Scan end address, exclusive (scan only), hex string (same format as `address`).",
      -  "title": "End Addr",
      -  "type": "string"
      -}
    • changedInput schema / properties / max_len / description
      Previous value: -"Maximum string length in bytes for read_string (0 = default cap 4096). Always uses read_bytes + local NUL scan — PPSSPP memory.readString is never called (its strnlen scans to memory end and a giant response can kill the WebSocket). Values are clamped to 65536. Ignored for other actions."New value: +"Maximum string length in bytes for read_string (0 = default cap 4096). Values are clamped to 65536."
    • removedInput schema / properties / max_results
      Removed value: -{
      -  "default": 100,
      -  "description": "Maximum number of matches to return (scan only, default 100).",
      -  "title": "Max Results",
      -  "type": "integer"
      -}
    • removedInput schema / properties / pattern
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "string"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "default": null,
      -  "description": "Pattern to scan for (scan only). Interpreted according to `pattern_type`: 'hex' (default) expects even-length hex digits like 'AABBCCDD'; 'ascii' treats the string as literal ASCII bytes like 'hello'.",
      -  "title": "Pattern"
      -}
    • removedInput schema / properties / pattern_type
      Removed value: -{
      -  "default": "hex",
      -  "description": "How to interpret `pattern` (scan only). 'hex' (default) decodes as hex string; 'ascii' encodes the pattern string as literal ASCII bytes.",
      -  "enum": [
      -    "hex",
      -    "ascii"
      -  ],
      -  "title": "Pattern Type",
      -  "type": "string"
      -}
    • removedInput schema / properties / start_addr
      Removed value: -{
      -  "default": "0x0",
      -  "description": "Scan start address, inclusive (scan only), hex string (same format as `address`).",
      -  "title": "Start Addr",
      -  "type": "string"
      -}
  3. First observedv0.1.0

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, but the description adds real value beyond that: read_string is ASCII-only (with a workaround for game text), MCP does no IR-encoding detection so read_u32 on JIT-IR returns raw bytes, and the size cap behavior (rejected with ARGS_INVALID). This is the substantive behavioral detail the annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with PURPOSE/USAGE/BEHAVIOR/RETURNS sections, each sentence carrying distinct load. The structured layout lets an agent extract the scoping, routing, and output-channel rules quickly without wasted prose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter read tool with an output schema, the definition covers the action enum, the address/size constraints, the ASCII-only limitation, the disassembly routing, and the RETURN shape with the three output channels. An agent has everything needed to call it correctly in one pass.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents every parameter in detail; baseline would be 3. The description still adds cross-parameter relationships not obvious from the schema alone (read_string is ASCII-only, read_bytes outputs to value/hex/file, chunking semantics for size). It doesn't add much beyond the schema, but the added interaction rules are genuinely useful.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with an explicit verb+resource ('Read memory') and immediately enumerates the three concrete actions (read_bytes/read_u32/read_string). It also distinguishes itself from siblings by routing scanning to ppsspp_scan and disassembly to ppsspp_disassemble, so an agent can place it precisely among the 37 tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use rules: session_id optional when exactly one session is active, address must be '0x' hex, reads over 65536 bytes must be chunked. It also names the alternative destination for related work ('Memory scanning has moved to ppsspp_scan', disassembly to ppsspp_disassemble), which is exactly the sibling routing a good definition provides.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.