ShippedDebugging platformSeptember 2026
Umbra
Windows debugging as typed objects, with an MCP front end.
Rust · dbgeng · COM · Zydis · ETW · MCPSource
The problem
Every debugger speaks to humans in console text. That is fine at a keyboard and useless for anything programmatic: a script, an IDE plugin, or an agent has to scrape output that was formatted for eyes, and every change to the formatting breaks the scraper. Windows makes this worse because the capable engine, dbgeng, is a COM surface that few languages wrap safely.
Umbra is a Rust server that wraps dbgeng and exposes debugging as structured, typed objects over the Model Context Protocol. Addresses are hex strings, registers are decoded integers, stack frames carry resolved symbols, and every response has a schema. The same backend serves a CLI, a GUI, a REST layer, or an agent, because none of them ever see console text.
Architecture
Four layers, each a crate boundary:
umbra, the MCP server binary. Session manager, TTD manager, tool router, JSON serialisation. Speaks JSON-RPC over stdio.debugger, the orchestrator. Attach and detach, break, step, memory and registers, stack, modules, symbols, kernel driver and handle enumeration.dbgeng, safe wrappers over the COM interfaces:IDebugClient,IDebugControl,IDebugSymbols3,IDebugDataSpaces,IDebugRegisters,IDebugSystemObjects.dbgeng.dllitself, reaching a live process, a dump file, a kernel target, or a remote.
Around those sit disassembler (Zydis, x86 and x64), symbols (offline PDB type resolution through the pdb crate, so a type layout such as nt!_EPROCESS can be resolved without a live session), etw (real-time Event Tracing for Windows through ferrisetw), extensions (extension output capture and gated command invocation), and ttd (Time Travel Debugging replay through Microsoft’s ReplayApi FFI).
The tool surface
Attach to a process, dump, or kernel target and get a session. From there: break, resume, single-step, read and write memory, get registers, walk the stack with symbols, list modules, processes, and threads, resolve a symbol to an address, resolve a type’s layout with field offsets, disassemble at an address, set and list breakpoints with pass counts, and poll for debugger events. Multiple sessions run side by side.
Security
The free-form command path reaches IDebugControl::Execute, which can run anything the debugger can. Because agents can reach the tool surface, that path is treated as a security boundary rather than a convenience. Every command is validated in two stages:
- Structural rejection of the characters that enable chaining, nesting, scripting, and redirection: semicolons, pipes, angle brackets, braces, quotes, backticks, and newlines. This alone defeats
.shelltricks, script sourcing, and output redirection. - A default-deny allowlist for dot-commands, where every host-affecting verb lives, plus rejection of the
!!shell alias and of alias-definition verbs, sincedbgengexpands aliases at execution time.
Host code execution, process spawning, file writes, and script sourcing are denied. Read-only inspection and debuggee-scoped commands remain available. Loading extension DLLs is not exposed to agents at all, since a DLL’s entry point is arbitrary native code.
Known limitations
- Disassembly is x86 and x64 only. ARM64 targets are rejected before decode.
- Float and vector registers come back as raw little-endian bytes; integer registers are decoded.
- The event channel is best-effort. Breakpoint and exception notifications share a bounded channel with module-load events, and a burst of DLL loads at startup can drop events. Execution status remains the ground truth for stops.
- ETW is system-global. One real-time trace can run at a time; a session’s trace is stopped when the session is destroyed and force-stopped at process exit so nothing is orphaned.
- Kernel driver and handle enumeration still needs validation against a live kernel target.
- TTD replay is experimental and has not been verified against a live trace.
Status
Shipped and in use. The dbgeng wrappers, the orchestrator, disassembly, symbols, ETW, and the MCP server are complete. TTD and the kernel walks are the open edges.