Example prompts
Eleven things you can type to an agent that has the server registered, with the tools each one triggers. The first four build in complexity; the rest are there for when you need them.
Start here
1. The minimal loop
“Set a breakpoint at TFoo.Bar and show me the locals when it’s
hit.”
launch_debuggee (or launch_from_config) →
set_breakpoint at the source line → continue_and_wait
→ get_locals.
The shortest useful session, and the one everything else is a variation on. If the agent
guesses the file name wrong, get_source_files gives it the spelling
set_breakpoint expects.
2. Crash triage
“Launch Foo.exe and tell me why it’s crashing.”
launch_debuggee → set_exception_filters(["unhandled"])
(usually already the default) → continue_and_wait → on the stop,
get_exception_details and get_call_stack — or
get_compact_debug_snapshot for state, exception, top frames and top-frame
locals in one call.
3. Watching a value evolve
“Set a breakpoint atTOrderProcessor.ProcessBatch, run to it, then step over 10 times and show meOrder.Totalafter each step.”
set_breakpoint → continue_and_wait → then ten times:
step_over followed by
evaluate_expression("Order.Total").
4. Attach and ask
“Attach to the already-runningMyApp.exe, tell me exactly where it’s stopped right now, and evaluateCustomer.Orders.Count.”
attach_to_process(processName="MyApp.exe") →
get_current_source_location →
evaluate_expression("Customer.Orders.Count").
If more than one instance is running the attach fails and lists the candidates with their command lines, so the agent can pick a pid rather than guess.
Finding out who wrote that
5. A field that keeps getting corrupted
“Watch TCustomer(FCustomer).FBalance and tell me which thread writes it
and what the old and new values are each time.”
set_data_breakpoint(expression="TCustomer(FCustomer).FBalance", size=8, access="write")
→ continue_and_wait, repeatedly. On each hit,
dataBreakpointDescription in the snapshot names the old value, the new value
and the writing thread directly — no manual diffing.
6. Checking the slot budget
“Watch the global ActiveConnection for both reads and writes, then show
me how many of the 4 hardware watchpoint slots are still free.”
set_data_breakpoint(expression="ActiveConnection", size=8, access="readWrite")
→ list_data_breakpoints, which reports the slot each watchpoint holds.
Worth knowing before you ask: readWrite also fires on plain writes. There is
no watch-reads-only mode on x86 or x64.
Below the source level
7. Registers and instructions at a crash
“Run until it crashes with an access violation, then show me the registers and the instructions around the crash point.”
set_exception_filters(["av"]) → continue_and_wait →
get_registers and disassemble(address=<crash RIP>, count=20).
8. Reading a structure by hand
“Evaluate Self.FBuffer to get its address, then dump the first 64 bytes
and tell me what the header fields look like.”
evaluate_expression("Self.FBuffer") — or @Self.FBuffer for the
address explicitly — → read_memory(address, count=64), which returns hex
plus little-endian integer views.
Bigger targets
9. Which package exports this?
“LaunchHydra2.exe, wait for the business-logic packages to load, and tell me which BPL exportsTInvoiceEngine.Calculate.”
launch_from_config → continue_and_wait until the packages
are loaded → get_loaded_modules, checking each module’s symbol state
and loaded debug-info formats → cross-reference with
get_source_files, or with a breakpoint that resolves against the right
module.
10. Quieting handled exceptions
“I keep getting interrupted by EFileNotFound that the app catches
itself. Only stop me on exceptions that actually crash the program.”
set_exception_filters(filters=["unhandled"]) — turns off the first-chance
delphi, av and all breaks and leaves only the
second-chance stop. For anything finer-grained than a whole category, the rule engine in
launch.json is the right tool; see
Exception handling.
Finishing cleanly
11. Detach, do not kill
“When you’re done inspecting, detach cleanly — don’t kill the process, it’s attached, not launched by you.”
detach_debugger, not terminate_debuggee. Detaching leaves the
process running, which is the default for an attached session.
INT3 bytes
patched into the target, and only the debugger that planted them can put the originals
back. A clean detach does that; an agent that kills the session instead leaves those bytes
behind, and the program later dies with a mystifying
External exception 80000003 that nothing connects back to the debugging
session. See
chapter 10.
Two things not to ask for
Neither of these exists over MCP, however reasonably an agent might attempt them:
Set Next Statement, and writing a variable by name.
Mutating state over MCP means write_memory or set_register and
nothing else. Both are available in the VS Code debugger — see
chapter 5.