neuron-explorer
Steering-first neuron explorer for Qwen3.5-4B: push every MLP neuron, keep every rollout, browse the results
MCP server exposing WinDbg/DbgEng (live user-mode, kernel, crash dumps, Time Travel Debugging) to AI agents over stdio or over HTTP with --listen
Developer toolsRust · PythonGitHub @glslangSelf-installOwner unconfirmed
Paste into Claude or ChatGPT for installation instructions suited to your environment.
Have you tried it? One tap is enough. No sign-in needed.
Loading the full README. The saved excerpt is shown below.
An MCP server that exposes WinDbg/DbgEng to AI agents
(Claude Code, Claude Desktop, Cursor, …) — over stdio, or over HTTP with --listen, which
serves the same tools to clients that are not on the machine DbgEng runs on. It drives a live
debugger engine for user-mode, kernel-mode, crash-dump, and
Time Travel Debugging (TTD) workflows — and reads a VBS guest's Secure Kernel (VTL1) out
of a Hyper-V checkpoint or controls one selected VP in an exact disposable VBS VM through
operator-supplied providers.Read the full README ↗An MCP server that exposes WinDbg/DbgEng to AI agents
(Claude Code, Claude Desktop, Cursor, …) — over stdio, or over HTTP with --listen, which
serves the same tools to clients that are not on the machine DbgEng runs on. It drives a live
debugger engine for user-mode, kernel-mode, crash-dump, and
Time Travel Debugging (TTD) workflows — and reads a VBS guest's Secure Kernel (VTL1) out
of a Hyper-V checkpoint or controls selected VPs in an exact disposable VBS VM through
operator-supplied providers.
The low-level engine bindings live in dbgscope
(src/dbgeng.rs); this crate adds process-per-session engine supervision and the rmcp tool
surface on top.
This repository — github.com/glslang/windbg-mcp — is
the project's only official home. If you are reading this anywhere else, you are reading a copy:
a mirror can carry this README word for word, so the address it is served from is the check, not
what it says.
It is published through these channels and no others:
glslang/dbgscope for
the engine bindings..mcpb bundle, both listed in SHA256SUMS.txt and both covered by a signed
build-provenance attestation.io.github.glslang/windbg-mcp
in the official registry, whose io.github.glslang
namespace only this GitHub account can publish to. The entry points at the .mcpb above./plugin marketplace add glslang/windbg-mcp — the marketplace is this
repository.The Scoop bucket is community-maintained and outside this project; that section says what trusting it involves.
MCP directories and marketplaces list public repositories without asking. None of them is affiliated with this project or acts for it, so before using windbg-mcp from one:
It is free, and there is no paid edition. It is MIT-licensed, with no subscription, licence key or premium tier. A listing that charges for it is not a channel of this project, and the money does not reach it.
There is no hosted version. The server drives DbgEng on the Windows machine it runs on,
against targets that machine can reach, so it belongs on yours or on one you control — --listen
exists to serve your clients. An endpoint offering it as a service is running someone else's
code, and your agent would be sending it what you debug: dumps, memory, traces.
A binary from anywhere else is a debugger you have not vetted. This one runs elevated — a
kernel attach and TTD recording need Administrator, and --install-service runs it as
LocalSystem — and it reads and writes other processes and the kernel. A tampered build in that
seat owns the machine and every target it reaches. Take binaries from the releases above and
check them before running them: the hash against SHA256SUMS.txt, and the provenance with
gh attestation verify <file> --repo glslang/windbg-mcp `
--signer-workflow glslang/windbg-mcp/.github/workflows/release.yml
This file is the map. Each topic is one document, and each document is the whole of that topic.
| Install and engine setup | Requirements, prebuilt binaries, Scoop, and the one-time WinDbg engine copy that TTD replay, !analyze, the driver tools and 32-bit .NET SOS need |
| Use with an MCP client | Client config, running the server on another machine (--listen), the two Claude Code plugins (the server, and the WinDbg pane that draws its calls), the MCP registry |
| Architecture | Why a supervisor process and one engine worker per session, what each source file owns, and which MCP revisions are served |
| The tool surface | Serving fewer tools with --tools, what a typed operand may contain, and how the control-flow and TTD tools behave |
| Sessions and session handles | session_id routing, the four-session cap, interrupt, progress notifications, and recovering a parked attach |
| Kernel connection profiles | Keeping a KDNET debug key out of tool arguments and out of the client's transcript |
| Hypervisor debugging | Attach to the Microsoft hypervisor through KDNET, with target identity, limitations, and a separate live test |
| Secure Kernel research | Capture inspection, live VTL1 reads, the initialized kernel stop/step result, and the operator-provider control contract |
Operator and reference material: remote listener, driving it with ollama, driving it with Apple's on-device model, disassembler coordinates, smoke test, token budget, releasing.
Secure Kernel (VTL1) has five routes. The opt-in securekernel group contains four tools for
a fixed capture, eleven tools for selected-VP live control, the managed KD facade, two
tools that trace VTL0 secure-service entries in an ordinary kernel session, and two tools for a
separate hypervisor transition trace; the session contracts
are in
docs/sessions.md. The separate --sk-live command-line role decodes a running
guest without controlling it, and the --sk-kd-target role puts an installed WinDbg in front of the
live-control session over a local named pipe, within the limits
docs/secure-kernel/kd-facade.md records. Live decode, live
control and the facade require operator-supplied transports this repository does not ship. The
VTL0 trace and guest harness are documented in
docs/secure-kernel/vtl0-call-trace.md; the intervening
hypervisor trace is in
docs/secure-kernel/hypervisor-transition-trace.md. The evidence, controls and dead ends are
recorded gate by gate.
Windows x64, with dbgeng.dll from System32 — enough for live user-mode, kernel and crash-dump
work. TTD .run replay, !analyze and the driver tools each need files that engine does not ship;
docs/install.md is the one-time copy.
Download a prebuilt windbg-mcp-vX.Y.Z-windows-x64.zip from a
release, or build it:
cargo build --release
Then point a client at the binary:
// .mcp.json (or claude_desktop_config.json under "mcpServers")
{
"mcpServers": {
"windbg": {
"command": "C:\\workspace\\windbg-mcp\\target\\release\\windbg-mcp.exe"
}
}
}
The client and the model do not have to run where DbgEng does: --listen <addr> serves the same
tools over HTTP, one bearer token per client, so a Mac can drive a Windows VM — and the model
itself can be a local one. Driving it
below has the configurations.
cargo test covers the unit tests plus an end-to-end smoke test that drives the built binary over
stdio; run it after a dependency bump or an MCP spec revision — docs/smoke-test.md.
One debug session per process. dbgeng.dll holds a single debuggee session per process, so this server runs the MCP protocol in a supervisor and each open target in its own engine worker child process. Two things follow: a session that cannot be unwound — a live-kernel attach waiting on a guest that never dials in — costs a process rather than the server, and sessions are concurrent (triage a crash dump while a kernel attach is live, up to four at once).
Every tool that touches a target takes the session_id an opener returned, and that is what routes
the call. Omit it and the call goes to the current session. docs/architecture.md
has the process model and the file-by-file breakdown; docs/sessions.md has the
handle rules, the cap, and what to do when a session is stuck.
A 32-bit target gets a 32-bit worker. An extension DLL is loaded into the debugger's own
process, so .NET's SOS on a 32-bit target is reachable only from a 32-bit host — which a process
cannot become after its image has loaded. So the release ships a second build of this same server
at x86\windbg-mcp.exe, and a 32-bit dump or a WoW64 attach_process is opened by that worker
instead of by a re-execution of the x64 one. A client cannot tell: one server, one handle, one tool
surface. Where that worker or its 32-bit engine is absent the target still opens on the x64 build —
native analysis of it works and always has — and says so in the opener's limitation.
Eighty-nine tools in nine --tools groups; the rows below split some of those groups by theme. The
--tools column is the name that selects one — see
Serving fewer tools.
| Group | --tools | Tools |
|---|---|---|
| Session | session | open_dump, open_trace, attach_kernel_local, attach_kernel, attach_process, launch, interrupt, end_session, session_status |
| Server | session | server_log — the server's own log: the supervisor's records, plus those of the sessions you opened, tagged with the session each belongs to |
| State | inspect | current_location (instruction pointer, execution context, and PE coordinate), registers, read_memory, backtrace (the stack as typed frames, each carrying module+RVA where the engine can place it, as well as its symbol), modules (refresh: true resynchronises the debugger's inventory with the target first — what a fresh kernel attach needs before "not loaded" means anything), threads, disassemble (instructions as records, each with its encoding and, where the engine can place it, its RVA), dx, set_symbol_path |
| Crash | crash | crash_triage — a bug check as fields: code and parameters, crashing process, the stack as module+RVA, and the faulting driver frame; exception_triage — the user-mode counterpart: the exception record decoded, what kind of fault it is, the thrown C++ object and the HRESULT it carries, and the stack walked from the crash context; decode_error_reporting — an HRESULT, NTSTATUS or Win32 error as fields, with the message the system's own tables give it |
| Control | exec | go, step_over, step_into, set_breakpoint, breakpoints (the session's whole inventory, as records — what to check before resuming or detaching a live target), clear_breakpoints (by ids, or all: true), run_to_address |
| Async control | exec | continue_async (resume and return a handle), (collect the stop; running out of the wait is a poll, not a failure), |
The ordinary eight groups are served by default; the securekernel extra is opt-in. Explicit
--tools all serves all eighty-nine. --tools session,inspect,crash cuts the surface to twenty-three
tools, and a --listen client can be given a different surface from the run's default. The exact
byte figures are not restated here: they live in the
docs/tool-surface.md tables, which
every_documented_surface_figure_matches_the_served_surface checks against a running server, while
the copy that used to sit in this sentence went stale on the first day the figure moved twice. That
page also has the arithmetic, the rule that session is always included, and what a typed operand
may not contain.
Most of the tools also answer with MCP structuredContent, so a program can read a field
instead of parsing prose, and a failure carries a stable category (invalid_argument, debugger,
timeout, stale_session, …) rather than wording —
docs/structured-results.md.
Worked sessions with the real outputs and the gotchas — the long form is in
docs/walkthroughs.md.
0x9F DRIVER_POWER_STATE_FAILURE traced to
nvlddmkm.sys, and a 0x13A in a driver with no PDB..run, forward/reverse navigation, and counting
printf calls with symbols.crash_triage frame to a function in
an image fetched on another machine.Anything that speaks MCP can hold this server, and DbgEng is the only part pinned to Windows. So the model may be a hosted one inside an editor, a local one in ollama, or an ollama cloud model, and it does not have to run on the machine being debugged.
| What drives it | Where that runs | The server | Reached over |
|---|---|---|---|
| An MCP client — Claude Code, Cursor, Claude Desktop | the Windows machine | launched by the client | stdio |
| An MCP client | a Mac, or any other machine | a Windows host, --listen, usually as a service | HTTP through an ssh forward |
| A model in ollama | the Windows machine | the same machine, --listen on loopback | HTTP on loopback |
| A model in ollama | a Mac | a Windows host, --listen as a service | HTTP through an ssh forward |
| A model in ollama's cloud | wherever ollama runs | either of the above | unchanged — the tag is all that differs |
One machine needs no configuration at all: the client launches the binary and talks to it over stdio, which is the Quick start above.
Two machines need a listener. For a session you are driving anyway, run it in the foreground on the Windows host — this works wherever the binary happens to live:
$env:WINDBG_MCP_LISTEN_TOKEN = "<a long random string>" # this shell only
windbg-mcp.exe --listen 127.0.0.1:8765
For anything longer-lived, install it as a service — from a protected directory. The SCM stores
that exact path for a LocalSystem auto-start service, so whoever can write the directory, or drop
an engine DLL beside the exe, gets their code run as SYSTEM at the next start.
--install-service therefore refuses an exe outside %ProgramFiles%, %ProgramFiles(x86)% or
%SystemRoot% — which a downloaded zip, a Scoop shim or a target\release build all are — so move
the whole deployment first: the exe, the engine DLLs beside it, and x86\. Then, elevated:
$env:WINDBG_MCP_LISTEN_TOKEN = "<a long random string>" # this shell only
& "$env:ProgramFiles\windbg-mcp\windbg-mcp.exe" --install-service --listen 127.0.0.1:8765
Start-Service windbg-mcp # --install-service only *registers* it
On a machine that is entirely yours, --allow-unprotected-path says so out loud and installs in
place; that is a development install, not a deployment.
Either way, from the machine you are actually working on, for as long as you want the link:
ssh -N -L 8765:127.0.0.1:8765 <windows-host>
The listener refuses to start without a token, because it serves execute, launch and
debug_batch — an open port here is arbitrary code on the host holding your kernel debugger. Bind
loopback and forward over ssh rather than exposing it. Each client authenticates as itself, and can
be served a narrower --tools surface than the run's default, which is how a local model and an
editor share one listener without sharing sessions.
docs/remote-listener.md is the operator's reference.
Pointing ollama at it is the client's job, not this server's. An MCP client that drives an
ollama model holds the listener exactly as an editor does — nothing here has to be installed, and
this server never learns which kind of model answered. ollama ships integrations for a number of
those clients; ollama launch lists them, and ollama launch claude --model <tag> is one. A local
tag and an ollama cloud tag are the same route, differing only in the model name.
docs/local-model.md is the runbook: the arrangements, choosing a model that
can actually run, which of two clocks a quiet model loses its sessions to, and what a cloud tag can no longer
tell you about its own run.
The tool surface is paid on every turn, so "can a model that runs on a laptop actually drive
this?" is a question about this server as much as about the model. The repo ships the
benchmark rather than the assertion: tools/local_model_eval.py runs a grid of model × tool
surface × context window, tools/bench_listener.ps1 serves all three surfaces from one listener as
three separately-budgeted clients, and the answer key is read off the checked-in crash dumps with
this server's own tools before any model sees them. Claude is in the grid as the control, not as a
competitor. docs/local-model-eval.md is the write-up.
Running the grid yourself needs a development environment rather than a release: the release
zip is windbg-mcp.exe, the x86\ worker and LICENSE, so tools/ comes from a checkout, and the
driver and grader are Python 3. Nothing above this section needs either — driving the server with a
local model is a client's job, and the driver here exists to measure that, one task list at a
time, with no interactive mode.
agent-sandbox-vm is the Hyper-V / Parallels VM
setup this project is developed and benchmarked in.
docs/local-model.md, and it was wrong; ask ollama ps what your own
runtime serves rather than generalising either result.instructions
sent at connect time, and in the descriptions of the tools it does serve. Both are narrowed per
client now, and re-running the narrow cells took those calls from 17 to 6, with every
server-taught name at zero.The Tool Surface Grid is the visual write-up — 33 cells, five models, the three axes, and what the two fixes it produced did and did not buy.
The full list, with what each one means for a workflow, is in
docs/limitations.md. The four that catch people first:
msdia140.dll beside the binary, a symbol
path, and (for TTD) a reload at a stopped position. Without them, address-based queries still work.heap_* tools whichever worker holds it, because its
heaps are 32-bit structures — SOS's own !dumpheap/!eeheap are the managed equivalent, and
reaching those is what the 32-bit worker and its x86\ engine payload
(docs/install.md) are for.| Structured results | Which tools answer with structuredContent, what each carries, and the error categories a caller can branch on |
| Transactional batches | debug_batch: a mutating sequence whose cleanup runs on every path it can be aimed at, including a timeout or a disconnect |
| Walking a structure | walk_memory: lists, arrays and chains where an unreadable node is a row rather than the end of the walk |
| Session transcripts | WINDBG_MCP_TRANSCRIPT: a JSONL record of every call, what is redacted, and rendering one as an asciicast |
| Limitations & notes | The honest edges — TTD is user-mode only, static reachability is best-effort, pool walks need a stopped x64 kernel and heap walks a stopped x64 or ARM64 process |
| Walkthroughs | Worked sessions end to end: crash-dump triage, TTD, a Flare-On solve, driver IOCTL surfaces |
| The local-model eval | A grid of model × tool surface × context window against a verified answer key: what a laptop-sized model can drive, and the two defects it found in this server |
wait_for_stopbreak_in| Transaction | batch | debug_batch — an ordered sequence with assertions and a rollback the engine process runs on every path where it can still identify the target it would aim at |
| TTD nav | ttd | step_back (t-), step_over_back (p-), reverse_go (g-), goto_position (!tt) |
| TTD analysis | ttd | ttd_calls, ttd_memory, ttd_events, index_trace, record_trace |
| Driver IOCTL | ioctl | decode_ioctl, driver_object, device_object, irp_stack, ioctl_trace, reachable_from_dispatch, driver_hazards, ioctl_map — the control codes a dispatch routine accepts, recovered from its own code and decoded; xrefs_to — which sites in an image call or branch to one address, read off decoded control flow, with module+RVA and section on each; device_security — who may open a device: its descriptor as principals and access masks, FILE_DEVICE_SECURE_OPEN, and the symbolic links that reach it; driver_surface — one driver in one call: its dispatch table, its devices with the gate on each (no symbolic links), ioctl_map's answer and driver_hazards', each section reporting its own status |
| Kernel pool | allocator | pool_find_tag, pool_chunk, pool_census, pool_diagnostics; pool_trace — one driver's pool allocations recorded as a live kernel runs, from breakpoints on that driver's own call sites, so no other caller of the allocator stops the target; pool_trace_read — what it recorded: size, tag, flags or pool type, the address returned and the thread |
| User Segment Heap | allocator | heap_list, heap_allocations, heap_chunk, heap_census, heap_diagnostics |
| Structure walk | allocator | walk_memory |
| Raw | inspect | execute — run any debugger command, returns full text output |
| Secure Kernel (extra) | securekernel | Capture: open_sk_capture, sk_modules, sk_read_memory, sk_symbol. Live selected-VP control: open_sk_live_control, sk_live_arm, sk_live_wait, sk_live_break, sk_live_registers, sk_live_read_memory, sk_live_write_memory, sk_live_step, sk_live_continue_to_breakpoints, sk_live_continue_to_software_breakpoints, sk_live_continue, plus the manifest-pinned sk_service_trace / sk_service_trace_read lifecycle, the managed open_sk_kd facade, and the one-handle open_sk_debugger composite. VTL0 call tracing on an ordinary kernel session: sk_call_trace, sk_call_trace_read. Hypervisor transitions in a distinct hypervisor KD session: hv_transition_trace, hv_transition_trace_read. A live session may arm additional selected VPs through independently validated providers. This extra group is omitted by default; name it or use --tools all. Capture needs an admitted Windows SDK saved-state provider root; live control needs startup policy, an operator-supplied privileged provider and an exact-build vmwp profile. Writes and software breakpoints additionally need explicit startup-policy authority and a bounded instruction-coherent transport capability; the first software-breakpoint slice and semantic tracer require a Hyper-V VM proved to have one vCPU. |