Aragorn
Aragorn
Direct kernel debugger MCP server for Windows security research. Attaches to a Windows VM kernel in-process via IDebugClient5::AttachKernelWide (no kd.exe subprocess) and exposes 72 tools over the Model Context Protocol.
This process is the debugger. There's no WinDbg GUI and no kd.exe in the loop — Aragorn loads dbgeng.dll directly via ctypes COM and drives the kernel attach itself (direct transport, the default). A legacy kd_server transport that shells out to kd.exe is kept as a fallback. Either way you get full DbgEng COM access — memory, registers, breakpoints, symbols, events — exposed as MCP tools.
MCP Client ──stdio/http──► Aragorn ──┬─► (direct, default) AttachKernelWide ──► VM kernel
└─► (kd_server) DebugConnect(TCP) ──► kd.exe ──► VM kernelThe net:port=…,key=…,target=… connection string is the standard Windows kernel-debug network (kdnet) format — that's the wire protocol, not the transport. Both direct and kd_server use it.
Architecture
Aragorn runs as a two-process system:
Supervisor — the MCP server that talks to your client. Stays alive across debugger crashes/wedges.
Worker — a child Python subprocess that owns
dbgeng.dlland the kernel connection.
The worker exists because dbgeng.dll enforces a one-direct-attach-per-process limit. After a wedge or a transport reset, the only reliable fix is a fresh process. Doing that in a worker means the supervisor (and your MCP pipe) keeps running. restart_worker() kills and respawns the worker — your client never has to reconnect.
Each multi-session debugger instance gets its own dedicated COM thread (DbgEng has thread affinity), and all blocking COM calls are wrapped in asyncio.to_thread() so the MCP stdio loop stays responsive.
Related MCP server: procmem
Quick Start
# 1. Install dependencies
pip install -r requirements.txt
# 2. Drop DbgEng DLLs into dbgeng_bin/ (see "DbgEng Binaries" below)
# 3. Configure
cp .env.example .env
# Edit .env: set KD_CONNECTION, KD_EXE_PATH, etc.
# 4. Run (stdio mode — for MCP clients like Claude Code)
python server.py
# Or HTTP mode (for remote/shared access)
python server.py --http.mcp.json integration
{
"aragorn": {
"type": "stdio",
"command": "python",
"args": ["path/to/Aragorn/server.py"]
}
}Configuration
All settings are via environment variables (or .env file):
Variable | Default | Description |
|
| kdnet connection string |
| WinDbg Preview's kd.exe | Path to kd.exe (only used by |
|
| Local TCP port for kd.exe debug server |
|
|
|
|
| First WaitForEvent timeout after AttachKernel |
|
| SetInterrupt timeout when |
|
| Path to DbgEng DLL |
| Microsoft symbol server | Symbol search path |
|
| HTTP mode bind address |
|
| HTTP mode port |
|
| VM agent URL (for workflow tools) |
| (empty) | VM agent API key |
DbgEng Binaries
The dbgeng_bin/ directory is gitignored. Copy these DLLs from your WinDbg Preview installation:
C:\Program Files\WindowsApps\Microsoft.WinDbg_*\amd64\
├── dbgeng.dll
├── dbghelp.dll
├── dbgmodel.dll
├── dbgcore.dll
├── symsrv.dll
└── srcsrv.dllVM Agent
The vm_agent/ directory contains a lightweight Flask server that runs inside the target VM. It exposes process execution, file I/O, and driver service management over HTTP. Aragorn's workflow tools (breakpoint_and_run, vm_exec, etc.) use it to coordinate kernel debugging with VM-side actions.
# On the VM:
cd vm_agent
pip install -r requirements.txt
cp .env.example .env
# Edit .env: set VM_AGENT_API_KEY
python server.pyThe VM agent is optional — all pure debugger tools work without it. You only need it for the coordinated workflow tools.
Tools
Session & Connection (12)
Tool | Description |
| Connect to kernel debugger (in-process AttachKernel by default) |
| Cleanly disconnect |
| Get connection state and config |
| Get debug target info (class, processors, page size) |
| Atomic: break in, verify thread context, reload symbols (retries 5x) |
| Lightweight probe without breaking into target |
| Kill the worker subprocess and spawn a fresh one (use after wedge) |
| Soft reset of the in-process engine state |
| Force full reconnect |
| Diagnostic kd.exe connection test |
| Full tracked state for cross-agent coordination |
| Resolve a Hyper-V VM name to its current IPv4 + update KD_CONNECTION |
Multi-Session (6)
Run multiple isolated debugger sessions in one Aragorn process — one per VM. Each gets its own kd.exe / COM thread / state. Tools take an optional session_id; the active session is used if omitted.
Tool | Description |
| Create an isolated debugger session for a VM |
| Connect a session's debugger |
| Disconnect without destroying |
| Destroy and clean up a session |
| List all sessions with status |
| Set the active session for tool routing |
Command Execution (3)
Tool | Description |
| Execute raw debugger command (e.g., |
| Execute multiple commands sequentially |
| Evaluate an expression, return numeric value |
Memory (7)
Tool | Description |
| Read virtual memory (hex / qwords / dwords / ascii) |
| Write bytes to virtual memory |
| Search for byte pattern |
| Read physical memory |
| Write to physical memory |
| Translate virtual to physical address |
| Read Model-Specific Register |
Registers (2)
Tool | Description |
| Read all general-purpose registers |
| Write a register value |
Stack (1)
Tool | Description |
| Structured stack trace with symbols |
Breakpoints (4)
Tool | Description |
| Set code, data, or hardware breakpoint (with optional MASM |
| Remove breakpoint by ID |
| List all breakpoints with status |
| Configure exception handling (break / ignore / output) |
Execution Control (4)
Tool | Description |
| Resume execution (robust — drains spurious kdnet breaks, retries up to 10x) |
| Single-step into calls |
| Single-step over calls |
| Interrupt running target |
Inspection (4)
Tool | Description |
| List loaded modules with base / size / name |
| List threads with engine / system IDs |
| List processes with engine / system IDs |
| Switch to process context ( |
Symbols (4)
Tool | Description |
| Bidirectional symbol / address resolution |
| Struct field byte offset |
| Type size in bytes |
| Disassemble instructions at address |
Events (3)
Tool | Description |
| Block until next debug event |
| Return queued events without blocking |
| Discard all queued events |
Kernel Objects (8)
Tool | Description |
| Read typed structure ( |
| Page table entry info |
| Pool allocation metadata |
| Driver object + dispatch table |
| Device object info |
| Kernel object from object directory |
| System Service Descriptor Table |
| Interrupt Descriptor Table |
Structured Context (6)
One-shot context dumps via direct COM (no Execute() text parsing). Safe to call any time the target is broken in.
Tool | Description |
| All GPRs + control regs + execution status in one call |
| Disassemble at address with structured output |
| Read N qwords with symbol resolution per slot |
| Current |
| Current |
| Combined CPU + process + thread + module snapshot |
Workflow (8)
Coordinated debugger + VM operations. Require a running VM agent.
Tool | Description |
| Atomic: set BP, resume, run VM command, wait for hit, capture state |
| Set logging BPs at multiple addresses, run command, capture trace |
| Batch post-breakpoint inspection commands |
| Execute command on VM |
| Read file from VM |
| Write file to VM |
| Upload file from host to VM |
| Check VM reachability |
Conditional breakpoints
Aragorn passes MASM .if conditions through to dbgeng natively:
set_breakpoint(
expression="<module>!<function>",
condition=".if (poi(@rcx+0x10) == 0x1234) {} .else {gc}",
)Two non-obvious gotchas (each one looks like a "spurious break" until you find it):
Use bitwise
&and|, not logical&&/||..if (1 && 0)returnsHRESULT 0x80040205; the engine falls back to its default action (break). Bitwise&/|work correctly on the0/1booleans that==produces.Inline all reads. Don't try to cache subexpressions with
r @$tN=expr. The pseudo-register assignment also triggers fallback-to-break.
See Claude-Docs/SKILL.md for the full breakpoint playbook (rate-budget reasoning, JS predicates via bp /w, validation workflow, common patterns).
Layout
Aragorn/
├── server.py # FastMCP entry point, registers all tool modules
├── supervisor.py # Owns the worker subprocess; survives crashes
├── worker.py # Child process that owns dbgeng + COM state
├── debugger.py # High-level Debugger class (lifecycle, commands, reconnect)
├── dbgeng.py # Pure ctypes COM interface definitions (6 interfaces)
├── callbacks.py # IDebugOutputCallbacks + IDebugEventCallbacks
├── sessions.py # Multi-session registry (parallel VM debugging)
├── vm_client.py # Async HTTP client to VM agent
├── config.py # Environment-variable configuration
├── bp_helpers.js # JS predicates for `bp /w` conditional breakpoints
├── start_engine.bat # Launch HTTP-mode server (must be admin)
├── dbgeng_bin/ # DbgEng DLLs (gitignored, ~15MB)
├── vm_agent/ # REST agent for the target VM (Flask + psutil)
│ ├── server.py
│ └── requirements.txt
├── Claude-Docs/
│ └── SKILL.md # Skill for kernel debug-assisted tracing
├── tests/
│ └── test_supervisor_methods_present.py
└── tools/
├── _state.py # State-snapshot wrapper applied to every tool
├── core.py # execute, execute_batch, evaluate
├── session.py # connect, disconnect, status, ensure_ready, restart_worker, ...
├── multi_session.py # session_create / connect / destroy / list
├── memory.py # read/write virtual + physical memory, MSR
├── registers.py # read/write registers
├── stack.py # get_stack
├── breakpoints.py # set/remove/list breakpoints, exception filters
├── execution.py # continue, step_into, step_over, break_in
├── inspection.py # list modules/threads/processes, switch context
├── symbols.py # resolve symbols, field offsets, disassemble
├── events.py # wait/poll/clear debug events
├── kernel.py # read_struct, PTE, pool, driver/device objects, SSDT, IDT
├── context.py # one-shot structured context dumps via direct COM
└── workflow.py # breakpoint_and_run, run_and_trace, VM proxy toolsCOM Interface Stack
Aragorn wraps six DbgEng COM interfaces via ctypes (no C++ extension needed):
IDebugClient — Session lifecycle, callback registration
IDebugControl — Command execution, breakpoints, execution status
IDebugDataSpaces2 — Virtual / physical memory, address translation
IDebugRegisters — Register read / write
IDebugSymbols2 — Symbol resolution, type info, disassembly
IDebugSystemObjects — Process / thread / module enumeration
License
This server cannot be deployed
Maintenance
Related MCP Connectors
Self-hosted MCP server: 26 deterministic dev, security, and EVM tools.
Security scanner for MCP servers. Detect vulnerabilities, prompt injection, and tool poisoning.
2,000+ MCP servers read at source level. Know what one does before you connect. Free, no key.
Security research canary remote MCP server for owned-account testing.
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP server for controlling a Windows guest VM over WinRM, enabling PowerShell/CMD execution, file transfer, reboot, and KDNET debug configuration, typically paired with kd-mcp.12MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server for Windows process memory inspection/editing and crash dump analysis, enabling live memory scanning, patching, pointer resolution, disassembly, and offline dump examination via structured tool calls.MIT
- AlicenseNot gradedqualityAmaintenanceMCP server for reverse engineering Windows executables and related binary formats, offering static analysis, Ghidra-assisted function recovery, plugin-driven tooling, and optional isolated Windows runtime execution.3 npm242MIT
- FlicenseNot gradedqualityCmaintenanceMCP server that exposes pwndbg and GDB for binary debugging, enabling memory inspection, exploit development, remote debugging, and kernel analysis.-