c64-mcp
C64-specific MCP tools layered over the public ghidra-mcp HTTP API and the
separately installed Ghidra VICE connector.
The server uses stdio transport by default. It does not open a VICE binary monitor socket; the connector remains the sole owner of that connection.
Tool visibility
The default static profile exposes the symbol, text, and graphics groups
plus four small catalog-management tools. This keeps live-debugger schemas out of the
agent context until they are needed. minimal starts with management tools
only, vice starts with the live-debugger group, and full exposes every
tool.
Use list_c64_tool_groups, search_c64_tools, and
load_c64_tool_group to discover and expose hidden tools at runtime.
unload_c64_tool_group removes only groups loaded after startup; profile
baseline groups remain visible. Thus static followed by loading all
still permits unloading the transient VICE group, while the full profile
does not permit partial unloading.
VICE debugger tools
The vice_* tools bind to the active VICE C64 Debugger TraceRMI target
through the generic Ghidra MCP HTTP API. Install and launch the separately
released ghidra-vice-connector first, then call vice_connect. The handshake
checks the complete versioned c64.vice/1 method schema, capability set,
machine, limits, and immutable connector instance ID. Compatibility is based
on that runtime contract rather than an assumed package-version pairing.
The handshake also requires connector surface revision 2, which adds the
display.capture capability; an older connector is refused there, naming the
revision it needs, rather than failing later on a missing method.
The tool set covers cached status, dynamic registers and banks, bank-aware
memory, checkpoints, execution control, stop-event waits, reset, and screen
capture. vice_disconnect releases only this MCP process's local binding; it
never closes the connector socket, trace, or VICE process. vice_status is
cached and performs no discovery or network operation.
vice_capture_screen returns the composited frame as an indexed PNG. It lives
in the vice group rather than graphics, because it needs the live debugger.
The connector returns the debug frame — border and blanking included — as one
palette index per byte, together with the palette VICE is using; the capture is
mapped through that palette rather than the static Pepto default, and the
default crop=true keeps only the inner screen rectangle the connector
reports, while crop=false returns the whole debug buffer. The summary carries
width, height, cropped, inner, palette_size, used_indices,
distinct_index_count, and output_path, which is written atomically and
refuses an existing file unless overwrite=true. The envelope is validated
before anything renders, and a mismatch is one vice_connector_incompatible
error naming the field.
Capture requires a stopped emulator, because any binary-monitor command traps
VICE into the monitor: call vice_interrupt, capture, then vice_resume, so
the stop stays visible instead of hiding inside a read-only-looking call. It
also requires a VICE at r46020 or later; earlier builds, including the 3.10
release, overrun their allocation while answering display get, and the
connector refuses them by design.
copy_vice_memory_to_ghidra is the only implicit bridge from live VICE memory
to a static program. It performs one complete connector read, verifies the
exact byte count, computes SHA-256, and calls the generic
write_memory_bytes endpoint exactly once. It defaults to dry_run=true and
never returns the complete payload. It does not create memory blocks or
disassemble.
Connector, generic target-method, and HTTP timeouts remain distinguishable. Mutating timeout responses explicitly say which VICE or Ghidra state may have changed, and no timed-out operation is retried automatically. The C64 MCP contains no VICE monitor host, port, socket, or binary protocol fallback.
C64 symbol profile
get_c64_symbol_profile returns the bundled, versioned C64 platform profile.
apply_c64_symbol_profile applies that exact profile to an explicitly named
Ghidra program through the generic apply_symbol_profile endpoint. It
defaults to dry_run=true, conflict_policy=error, and memory-block creation
disabled. Re-applying an unchanged profile is idempotent.
The profile covers the 6510 processor port, all VIC-II and SID registers,
both CIA devices, color RAM, the 39 standard KERNAL jump-table entry points,
processor vectors, and common KERNAL workspace addresses. Value-only equates
name documented VIC-II, SID, and CIA control bits. Optional RAM, ROM, I/O,
and color-RAM block templates are only considered when
create_memory_blocks=true; the generic endpoint preflights the complete
request before mutation and refuses ordinary-block overlap.
Every platform-symbol address explicitly targets the default RAM address
space. This keeps CPU-visible register and ROM references unambiguous after
ROM, I/O, or color-RAM overlays have been added. The bundled profile supports
6502:LE:16:default programs whose default CPU space is named RAM; an
overlay must not reuse that name.
The checked-in profile is generated deterministically by
tools/generate_c64_profile.py. Every symbol group cites its authoritative
Commodore manual or chip data sheet in the package data.
C64 text tools
The server includes immutable 256-entry mappings for upper/graphics and lower/upper PETSCII and C64 screen codes:
decode_c64_textdecodes inline hex/byte arrays or an exact bounded read from a named Ghidra program.search_c64_textsearches an inclusive program range by exact raw bytes or exact decoded Unicode code points.define_c64_textdecodes first, then sends one flat contiguous region to Ghidra with byte typing, an optional label/namespace, and a complete plate comment. It defaults todry_run=true.
Every decode uses exactly one of a positive fixed length, a one-byte
terminator, or a one/two-byte little-endian prefix_size. Terminators are
consumed but excluded from text. Prefixes are consumed and excluded from
text, and may either describe payload length or include themselves.
high_bit accepts exact, strip, or annotate_reverse; the latter is
screen-code-only. controls accepts names, escaped, or unicode.
Lossless payload output retains every original text byte as a stable fragment
such as {A:$41}, {CLR:$93}, or {REV A:$81}. Prefix and terminator bytes
remain available in consumed_bytes and the per-byte records even though
framing bytes are excluded from both decoded text renderings.
Caller token maps use unprefixed decimal keys ("129") or explicitly
hexadecimal keys ("0x81"). Expansion is single-pass by default. Recursive
mode recognizes two-digit hexadecimal references such as {81}, enforces a
caller-selected depth, detects cycles, and fails rather than truncating when
the aggregate rendering cap is exceeded.
All reads and inline inputs have a 1 MiB hard cap. Search defaults to 64 KiB and 100 results, with hard caps of 1 MiB and 1,000 results. Ghidra reads must be complete; partial or unmapped reads are errors.
The normative mapping source is Appendices B and C of the official Commodore 64 Programmer's Reference Guide. The generated package data records the source URL and printed page references.
C64 graphics tools
Five per-mode decoders turn C64 graphics memory into an indexed PNG:
decode_c64_hires_bitmaptakesbitmapandscreen; a set bit uses the screen byte's high nybble and a clear bit its low nybble.decode_c64_multicolor_bitmapaddscolor; the bit pairs selectbackground, the screen high nybble, the screen low nybble, and the colour-RAM low nybble.decode_c64_charsetrenders a character set as a sheetsheet_columnsglyphs wide, optionally in multicolor.decode_c64_char_screenrenders text mode fromscreenandcharset. Withmulticolor=true,coloris required because colour-RAM bit 3 selects each cell's mode; only glyphs up to the highest screen code present must be supplied.decode_c64_spritesrenders 24x21 hires or 12x21 multicolor definitions onto a sheet.sprite_stridedefaults to 64, the padded definition-block size; 63 is accepted for packed records. Transparent pixels composite ontobackground.
Every byte input takes one discriminated source:
{"kind": "inline", "bytes": "00ff"}
{"kind": "ghidra", "program": "name", "start": "ram:2000"}
{"kind": "vice", "bank_id": 1, "start": 8192}
bank_id is mandatory for a VICE source: the same address holds different
bytes in different banks. A VICE read that would run past $FFFF is refused
rather than wrapped. Naming more than one VICE source while the emulator is
running is refused unless allow_non_atomic_vice_reads=true, which then
reports a non_atomic_vice_reads warning.
A source shorter than the geometry requires is an error before any rendering
and before any remote read; extra inline bytes are ignored and counted in the
summary. Colours are Pepto PAL unless a palette of #rrggbb strings or
[r, g, b] triples is supplied; indices past a short palette extend PLTE
with black and are reported as unmapped_indices. output_path writes the
PNG atomically and refuses an existing file unless overwrite=true.
Cell geometry is capped at 64 columns, 64 rows, and 2,048 cells; glyph and sprite counts at 256; sheet width at 64. These tools are read-only: nothing is written into a program or into VICE.
These decoders render bytes, wherever they came from; vice_capture_screen,
in the VICE group above, renders what the emulator is actually showing. Use the
decoders for an off-screen buffer or a program's data, and capture for the
composited result.
Configuration
GHIDRA_MCP_URLdefaults tohttp://127.0.0.1:8089.GHIDRA_MCP_AUTH_TOKENoptionally supplies a bearer token.GHIDRA_MCP_TIMEOUTdefaults to 30 seconds.C64_MCP_TOOL_PROFILEacceptsminimal,static,vice, orfull; the default isstatic.
The --tool-profile command-line option overrides the environment setting.
VICE method calls accept a caller-visible timeout_ms from 1 through 55,000.
The wrapper reserves an additional five seconds for generic TraceRMI
invocation and another five seconds for HTTP transport.
Metadata
Release files for c64-mcp 0.100.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| c64_mcp-0.100.0.tar.gz | 209.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| c64_mcp-0.100.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 291.2 kB
Release files / c64_mcp-0.100.0.tar.gz
| Download URL | c64_mcp-0.100.0.tar.gz |
|---|---|
| Size | 209.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d53a7fe17d446fe1fc09b18b715dcc986d3e2f8bfbcaf0f30ab5eac853a01a63
|
|
BLAKE2b-256 checksum How to use checksums |
f6ab9cd6e4b8e9e7880e83d23f3572c14d4e87ae19ede0c89c83d2d63e47c02d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / c64_mcp-0.100.0-py3-none-any.whl
| Download URL | c64_mcp-0.100.0-py3-none-any.whl |
|---|---|
| Size | 81.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6db22ead70159a8d95d24e7b6cecb4244c9a8d06394c4f3610d8ab2d3c95e4cb
|
|
BLAKE2b-256 checksum How to use checksums |
6cc46270e1674a48fb600a5de94069f900cc59016c10b938310cf8f5c3bc1b06
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|