Skip to main content
Glama

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 kernel

The 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.dll and 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.

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

KD_CONNECTION

net:port=55555,key=...,target=...

kdnet connection string

KD_EXE_PATH

WinDbg Preview's kd.exe

Path to kd.exe (only used by kd_server transport)

KD_SERVER_PORT

14500

Local TCP port for kd.exe debug server

ARAGORN_TRANSPORT

direct

direct (in-process AttachKernel) or kd_server (legacy)

KD_SYNC_TIMEOUT_MS

30000

First WaitForEvent timeout after AttachKernel

INITIAL_BREAK_TIMEOUT_MS

10000

SetInterrupt timeout when initial_break=True

DBGENG_PATH

./dbgeng_bin/dbgeng.dll

Path to DbgEng DLL

SYMBOL_PATH

Microsoft symbol server

Symbol search path

ARAGORN_HOST

127.0.0.1

HTTP mode bind address

ARAGORN_PORT

14401

HTTP mode port

VM_AGENT_URL

http://YOUR_VM_IP:8080

VM agent URL (for workflow tools)

VM_AGENT_API_KEY

(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.dll

VM 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.py

The 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

Connect to kernel debugger (in-process AttachKernel by default)

disconnect

Cleanly disconnect

status

Get connection state and config

target_info

Get debug target info (class, processors, page size)

ensure_ready

Atomic: break in, verify thread context, reload symbols (retries 5x)

health_check

Lightweight probe without breaking into target

restart_worker

Kill the worker subprocess and spawn a fresh one (use after wedge)

reset_engine

Soft reset of the in-process engine state

reconnect_debugger

Force full reconnect

test_kd_connection

Diagnostic kd.exe connection test

get_debugger_state

Full tracked state for cross-agent coordination

resolve_vm_target

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

session_create

Create an isolated debugger session for a VM

session_connect

Connect a session's debugger

session_disconnect

Disconnect without destroying

session_destroy

Destroy and clean up a session

session_list

List all sessions with status

session_set_active

Set the active session for tool routing

Command Execution (3)

Tool

Description

execute

Execute raw debugger command (e.g., lm, !process 0 0)

execute_batch

Execute multiple commands sequentially

evaluate

Evaluate an expression, return numeric value

Memory (7)

Tool

Description

read_memory

Read virtual memory (hex / qwords / dwords / ascii)

write_memory

Write bytes to virtual memory

search_memory

Search for byte pattern

read_physical

Read physical memory

write_physical

Write to physical memory

virtual_to_physical

Translate virtual to physical address

read_msr

Read Model-Specific Register

Registers (2)

Tool

Description

read_registers

Read all general-purpose registers

write_register

Write a register value

Stack (1)

Tool

Description

get_stack

Structured stack trace with symbols

Breakpoints (4)

Tool

Description

set_breakpoint

Set code, data, or hardware breakpoint (with optional MASM .if condition)

remove_breakpoint

Remove breakpoint by ID

list_breakpoints

List all breakpoints with status

set_exception_filter

Configure exception handling (break / ignore / output)

Execution Control (4)

Tool

Description

continue_exec

Resume execution (robust — drains spurious kdnet breaks, retries up to 10x)

step_into

Single-step into calls

step_over

Single-step over calls

break_in

Interrupt running target

Inspection (4)

Tool

Description

list_modules

List loaded modules with base / size / name

list_threads

List threads with engine / system IDs

list_processes

List processes with engine / system IDs

switch_process

Switch to process context (.process /i)

Symbols (4)

Tool

Description

resolve_symbol

Bidirectional symbol / address resolution

get_field_offset

Struct field byte offset

get_type_size

Type size in bytes

disassemble

Disassemble instructions at address

Events (3)

Tool

Description

wait_for_event

Block until next debug event

poll_events

Return queued events without blocking

clear_events

Discard all queued events

Kernel Objects (8)

Tool

Description

read_struct

Read typed structure (dt equivalent)

get_pte

Page table entry info

pool_info

Pool allocation metadata

get_driver_object

Driver object + dispatch table

get_device_objects

Device object info

get_object_info

Kernel object from object directory

dump_ssdt

System Service Descriptor Table

get_idt

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

get_cpu_state

All GPRs + control regs + execution status in one call

disasm_at

Disassemble at address with structured output

read_qwords

Read N qwords with symbol resolution per slot

get_current_process

Current _EPROCESS summary (image name, PID, etc.)

get_current_thread

Current _ETHREAD summary

get_full_context

Combined CPU + process + thread + module snapshot

Workflow (8)

Coordinated debugger + VM operations. Require a running VM agent.

Tool

Description

breakpoint_and_run

Atomic: set BP, resume, run VM command, wait for hit, capture state

run_and_trace

Set logging BPs at multiple addresses, run command, capture trace

inspect_at_breakpoint

Batch post-breakpoint inspection commands

vm_exec

Execute command on VM

vm_read_file

Read file from VM

vm_write_file

Write file to VM

vm_upload_file

Upload file from host to VM

vm_status

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) returns HRESULT 0x80040205; the engine falls back to its default action (break). Bitwise & / | work correctly on the 0/1 booleans 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 tools

COM 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

WTFPL

A
license - permissive license
-
quality - not tested
C
maintenance

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/alfarom256/Aragorn'

If you have feedback or need assistance with the MCP directory API, please join our Discord server