Skip to main content
Glama
simen
by simen

setWatchpoint

Set memory watchpoints in C64 emulation to debug program execution by halting when specific memory addresses are read or written.

Instructions

Set a memory watchpoint to stop when memory is read or written.

Watchpoints are powerful for debugging:

  • "Why is this value changing?" → Use store watchpoint

  • "What's reading this address?" → Use load watchpoint

  • "Track all access to this region" → Use both

Range can be single address or address range (e.g., $D800-$DBFF for color RAM).

Related tools: deleteBreakpoint, listWatchpoints, continue

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
startAddressYesStart address of watched range (0x0000-0xFFFF)
endAddressNoEnd address of watched range (default: same as start for single address)
typeYesWatch type: 'load' (read), 'store' (write), or 'both'
enabledNoWhether watchpoint is active (default: true)
temporaryNoAuto-delete after hit (default: false)

Implementation Reference

  • MCP server tool handler for setWatchpoint: validates args, calls ViceClient.setWatchpoint, formats success/error response with metadata
    async (args) => { try { const endAddr = args.endAddress ?? args.startAddress; const id = await client.setWatchpoint(args.startAddress, endAddr, args.type, { enabled: args.enabled ?? true, temporary: args.temporary ?? false, }); const isSingleAddress = args.startAddress === endAddr; return formatResponse({ success: true, watchpointId: id, startAddress: { value: args.startAddress, hex: `$${args.startAddress.toString(16).padStart(4, "0")}`, }, endAddress: { value: endAddr, hex: `$${endAddr.toString(16).padStart(4, "0")}`, }, type: args.type, enabled: args.enabled ?? true, temporary: args.temporary ?? false, message: isSingleAddress ? `Watchpoint ${id} set at $${args.startAddress.toString(16).padStart(4, "0")} (${args.type})` : `Watchpoint ${id} set for $${args.startAddress.toString(16).padStart(4, "0")}-$${endAddr.toString(16).padStart(4, "0")} (${args.type})`, hint: "Use continue() to run until watchpoint is triggered", }); } catch (error) { return formatError(error as ViceError); } }
  • Zod input schema defining parameters for setWatchpoint tool: startAddress, endAddress (opt), type (load/store/both), enabled (opt), temporary (opt)
    inputSchema: z.object({ startAddress: z.number().min(0).max(0xffff).describe("Start address of watched range (0x0000-0xFFFF)"), endAddress: z .number() .min(0) .max(0xffff) .optional() .describe("End address of watched range (default: same as start for single address)"), type: z.enum(["load", "store", "both"]).describe("Watch type: 'load' (read), 'store' (write), or 'both'"), enabled: z.boolean().optional().describe("Whether watchpoint is active (default: true)"), temporary: z.boolean().optional().describe("Auto-delete after hit (default: false)"), }),
  • src/index.ts:690-749 (registration)
    MCP server registration of the setWatchpoint tool including description and input schema
    server.registerTool( "setWatchpoint", { description: `Set a memory watchpoint to stop when memory is read or written. Watchpoints are powerful for debugging: - "Why is this value changing?" → Use store watchpoint - "What's reading this address?" → Use load watchpoint - "Track all access to this region" → Use both Range can be single address or address range (e.g., $D800-$DBFF for color RAM). Related tools: deleteBreakpoint, listWatchpoints, continue`, inputSchema: z.object({ startAddress: z.number().min(0).max(0xffff).describe("Start address of watched range (0x0000-0xFFFF)"), endAddress: z .number() .min(0) .max(0xffff) .optional() .describe("End address of watched range (default: same as start for single address)"), type: z.enum(["load", "store", "both"]).describe("Watch type: 'load' (read), 'store' (write), or 'both'"), enabled: z.boolean().optional().describe("Whether watchpoint is active (default: true)"), temporary: z.boolean().optional().describe("Auto-delete after hit (default: false)"), }), }, async (args) => { try { const endAddr = args.endAddress ?? args.startAddress; const id = await client.setWatchpoint(args.startAddress, endAddr, args.type, { enabled: args.enabled ?? true, temporary: args.temporary ?? false, }); const isSingleAddress = args.startAddress === endAddr; return formatResponse({ success: true, watchpointId: id, startAddress: { value: args.startAddress, hex: `$${args.startAddress.toString(16).padStart(4, "0")}`, }, endAddress: { value: endAddr, hex: `$${endAddr.toString(16).padStart(4, "0")}`, }, type: args.type, enabled: args.enabled ?? true, temporary: args.temporary ?? false, message: isSingleAddress ? `Watchpoint ${id} set at $${args.startAddress.toString(16).padStart(4, "0")} (${args.type})` : `Watchpoint ${id} set for $${args.startAddress.toString(16).padStart(4, "0")}-$${endAddr.toString(16).padStart(4, "0")} (${args.type})`, hint: "Use continue() to run until watchpoint is triggered", }); } catch (error) { return formatError(error as ViceError); } } );
  • Core ViceClient.setWatchpoint method: validates addresses, builds CheckpointSet command packet for VICE binary monitor protocol, sends via sendCommand, parses ID, tracks locally
    async setWatchpoint( startAddress: number, endAddress: number, type: "load" | "store" | "both", options: { enabled?: boolean; stop?: boolean; temporary?: boolean; } = {} ): Promise<number> { const { enabled = true, stop = true, temporary = false } = options; if (startAddress < 0 || startAddress > 0xffff) { throw this.makeError( "INVALID_ADDRESS", `Start address 0x${startAddress.toString(16)} is outside C64 memory range`, "C64 addresses are 16-bit (0x0000-0xFFFF)" ); } if (endAddress < 0 || endAddress > 0xffff) { throw this.makeError( "INVALID_ADDRESS", `End address 0x${endAddress.toString(16)} is outside C64 memory range`, "C64 addresses are 16-bit (0x0000-0xFFFF)" ); } if (startAddress > endAddress) { throw this.makeError( "INVALID_RANGE", `Start address (0x${startAddress.toString(16)}) is greater than end address (0x${endAddress.toString(16)})`, "Swap the addresses or check your range" ); } // Determine operation type let op: number; let checkpointType: CheckpointType; if (type === "load") { op = CheckpointOp.Load; checkpointType = "load"; } else if (type === "store") { op = CheckpointOp.Store; checkpointType = "store"; } else { op = CheckpointOp.Load | CheckpointOp.Store; checkpointType = "load"; // Will track as load for simplicity } // Build request: start(2) + end(2) + stop(1) + enabled(1) + op(1) + temp(1) const body = Buffer.alloc(8); body.writeUInt16LE(startAddress, 0); body.writeUInt16LE(endAddress, 2); body[4] = stop ? 1 : 0; body[5] = enabled ? 1 : 0; body[6] = op; body[7] = temporary ? 1 : 0; const response = await this.sendCommand(Command.CheckpointSet, body); const id = response.body.readUInt32LE(0); // Track locally this.checkpoints.set(id, { id, startAddress, endAddress, enabled, temporary, type: checkpointType, }); return id; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/simen/vice-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server