Repository navigation
Add MCP debugger server for REVM - #2
Merged
Merged
Conversation
sevm mcp serves the debugger over MCP stdio as a third frontend, shaped
for a consumer that cannot scroll panes or watch them change:
- every windowed read takes offset/size and returns {items, total,
truncated}; every navigation tool returns the same stop report (pc,
opcode, gas, sp, location, stack top, stack delta since the previous
stop); sevm_diff_since_last_stop reports stack pushes/pops with
values, changed memory ranges and gas spent
- 37 tools: session lifecycle (web3.py driver scripts and .t.sol
Foundry tests, restart with new args), navigation, windowed state
reads, decoded storage/locals/arguments/logs, source and disassembly
windows, breakpoints and watchpoints, Solidity evaluation against the
paused frame, live mutation (stack/gas/memory/storage/pc), and a raw
gdb-verb passthrough (vm.* cheatcodes, Yul, jump, reseat)
- failures return {"error": ...} dicts with the fix in the message
Both targets and a new find HEX command share a fresh find_needle
inspect op: every offset of a byte pattern in the RUNNING code, with
instruction alignment and the nearest preceding JUMPDEST — the address
an indirect jump can reach. bytes(CodeStream) iterates from the current
pc, so the op reads _raw_code_bytes to search the whole program.
Verified: full suite 802 passed; stdio JSON-RPC smoke (initialize,
tools/list, call_tool); in-memory client round trip; and a TokyoPayload
gadget hunt through the driver locating POP4/CALLDATALOAD/DELEGATECALL/
STOP gadgets in the optimized runtime.
The AI-review package: the reviewer's top asks, built for a consumer
that needs ground truth on 'why did this operand get this value' and
cheap branching from a deep stop.
Checkpoints (snap/restore, sevm_save/restore_checkpoint): capture a
stop — per-frame stack/memory/gas/pc/logs, the py-evm journal
(state.snapshot()/revert(), the mechanism the evaluator already
exercised), cheat state, gas profiles, watchpoint baselines — then
experiment and roll everything back without re-running the prefix.
Restoring re-arms the consumed journal checkpoint so a save restores
any number of times; a skip-flag in the opcode loop cancels the stale
iteration after any pc write, which also makes jump/set $pc exact;
restoring discards later checkpoints (journal nesting) and refuses
when the frame stack changed or the program finished.
Provenance (provenance on, why N, sevm_why_stack): opt-in per-opcode
recording (before/after stacks, gas, pc) and a concrete backward
slice driven by an opcode arity table: PUSH resolves to constants,
DUP/SWAP to their copies, consumers fan in, MLOAD/SLOAD chain to the
last same-offset MSTORE/SSTORE, CALLDATALOAD names its calldata
window, survivors are frame-entry slots. A checkpoint restore
truncates the record to stay consistent.
Batch experiments (sevm_run_experiments): a list of
{set_stack, set_gas, write_memory, run_until_pc, read_stack} runs,
each from one saved base checkpoint — 32 variants for one prefix; a
run that finishes ends the batch with a named cause.
Bytecode parity (parity verb, sevm_check_parity,
start_session(reference_runtime_hex=...) hard-fail): metadata-stripped,
immutable-masked comparison reporting the first divergence.
structLog export (export, sevm_export_trace): anvil/geth
debug_traceTransaction-shaped rows from the provenance recording, to
a file or as a windowed slice.
Also: set $stack[N] = 0x... now parses hex literals directly (bare
0x literals are not valid Solidity expressions); script tracebacks
are surfaced by all three frontends and a crashed script exits 1.
Full suite 813 passed; storage-level equivalence proven for
restore-then-continue vs natural runs; TokyoPayload's FMP corruption
traces to calldata via why.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
mainintomcp_serverand wiresevm mcpto the REVM debugger.NEXTthrough the loop body.Verification
GitHub Actions Verify run passed: Ruff lint/format, mypy, the focused stepping regression, 857 passed / 5 skipped in the full Python suite, and
cargo test --workspace --locked. The five skipped tests require network access.