
An MCP (Model Context Protocol) server that turns all pybag Windows debugger functions into native MCP tools. It lets MCP-compatible clients (Claude Desktop, Claude Code, Cowork, OpenAI Codex CLI, Cursor, and custom agents) control user-mode processes, kernel sessions, and crash dump analysis via structured JSON calls.
Сервер MCP (Model Context Protocol), предоставляющий каждую функцию отладчика Windows pybag в виде нативного инструмента MCP. Он предоставляет любому MCP-совместимому клиенту (Claude Desktop, Claude Code, Cowork, OpenAI Codex CLI, Cursor и кастомные агенты) полный контроль над пользовательскими процессами, сеансами ядра и анализом дампов памяти — всё через типизированные вызовы инструментов со структурированными JSON-ответами.
git clone https://github.com/your-username/windbg-mcp.git cd windbg-mcp
### 2. Установите зависимости Python```bat
pip install pybag mcp
Загрузите Windows SDK и выберите Средства отладки для Windows в процессе установки: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/
Сервер запускается как локальный процесс stdio. Все клиенты, перечисленные ниже, запускают его одинаково — python <path-to>/windbg_mcp.py — но у каждого свой формат конфигурации.
Отредактируйте файл конфигурации Claude Desktop и добавьте запись windbg-mcp:
Расположение файла конфигурации:
%APPDATA%\Claude\claude_desktop_config.jsonПерезапустите Claude Desktop. Все 55 инструментов отладки появятся автоматически.
---
### Claude Code (CLI)
Выполните следующую команду один раз, чтобы зарегистрировать сервер. Claude Code сохраняет запись
в своей конфигурации MCP и делает инструменты доступными в каждом последующем сеансе.```bash
claude mcp add windbg-mcp python C:\path\to\windbg-mcp\windbg_mcp.py
Чтобы проверить, был ли зарегистрирован сервер:```bash claude mcp list
Чтобы удалить его позже:```bash
claude mcp remove windbg-mcp
Есть два способа добавить WinDbg MCP в Cowork: через JSON-конфигурацию (быстро) или
установкой в виде пакета плагина .mcpb (переносимый, доступный для общего использования).
3. Сохраните и перезапустите Cowork. Инструменты будут доступны в вашем следующем сеансе.
#### Вариант B — Установка в виде `.mcpb`-пакета плагина
Файл `.mcpb` представляет собой zip-архив каталога плагина, который Cowork может установить
напрямую. Это рекомендуемый подход при совместном использовании сервера с командой или
на разных машинах.
**Шаг 1 — Сборка файла `.mcpb`**
Из корня клонированного репозитория выполните:```bat
powershell -Command "Compress-Archive -Path '.\*' -DestinationPath 'windbg-mcp.zip'; Rename-Item 'windbg-mcp.zip' 'windbg-mcp.mcpb'"
Это создаёт windbg-mcp.mcpb в текущем каталоге, объединяя windbg_mcp.py,
manifest.json и любые другие файлы проекта.
Шаг 2 — Установка в Cowork
windbg-mcp.mcpb.manifest.json из пакета, регистрирует MCP-сервер и
делает все инструменты доступными немедленно — ручная настройка пути не требуется.manifest.json, входящий в этот репозиторий, уже настроен правильно:```json
{
"manifest_version": "0.2",
"name": "windbg-mcp",
"version": "1.0.0",
"description": "WinDbg MCP — full Windows debugger control via MCP tools",
"server": {
"type": "python",
"entry_point": "windbg_mcp.py",
"mcp_config": {
"command": "python",
"args": ["${__dirname}/windbg_mcp.py"]
}
}
}
`${__dirname}` разрешается во время установки в каталог, куда Cowork распаковал пакет, поэтому вам не нужно жестко прописывать пути.
---
### OpenAI Codex CLI
Добавьте сервер в файл конфигурации Codex CLI. Обычно файл находится по пути
`~/.codex/config.json` (Linux/macOS) or `%USERPROFILE%\.codex\config.json` (Windows).```json
{
"mcpServers": {
"windbg-mcp": {
"command": "python",
"args": ["C:\\path\\to\\windbg-mcp\\windbg_mcp.py"]
}
}
}
После сохранения запустите новый сеанс Codex. Инструменты WinDbg будут доступны для вызова моделью.
4. Сохраните. Курсор подключится к серверу при следующем сеансе Composer.
---
### Continue.dev
Добавьте следующее в ваш `~/.continue/config.json` (или в `.continue/config.json` на уровне рабочей области):```json
{
"experimental": {
"modelContextProtocolServers": [
{
"transport": {
"type": "stdio",
"command": "python",
"args": ["C:\\path\\to\\windbg-mcp\\windbg_mcp.py"]
}
}
]
}
}
Перезагрузите расширение Continue. В списке инструментов появятся 55 отладочных инструментов.
Если вы создаете собственного агента или конвейер автоматизации, подключитесь к WinDbg MCP через стандартный транспорт MCP stdio. Сервер использует JSON-RPC 2.0 через stdin/stdout.
mcp)```pythonimport asyncio from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client
server_params = StdioServerParameters( command="python", args=[r"C:\path\to\windbg-mcp\windbg_mcp.py"], )
async def main(): async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize()
# List all available tools
tools = await session.list_tools()
print([t.name for t in tools.tools])
# Load a crash dump
result = await session.call_tool(
"load_dump",
arguments={"path": r"C:\crashes\crash.dmp"},
)
print(result.content)
# Read 64 bytes at RSP
result = await session.call_tool(
"read_mem",
arguments={"addr": "0x00000000001FF000", "size": 64},
)
print(result.content)
asyncio.run(main())
#### TypeScript / Node.js (используя пакет `@modelcontextprotocol/sdk`)```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "python",
args: ["C:\\path\\to\\windbg-mcp\\windbg_mcp.py"],
});
const client = new Client({ name: "my-agent", version: "1.0.0" }, {});
await client.connect(transport);
// Call a tool
const result = await client.callTool({
name: "load_dump",
arguments: { path: "C:\\crashes\\crash.dmp" },
});
console.log(result.content);
await client.close();
from langchain_mcp_adapters.tools import load_mcp_tools from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client
server_params = StdioServerParameters( command="python", args=[r"C:\path\to\windbg-mcp\windbg_mcp.py"], )
async def get_tools(): async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() return await load_mcp_tools(session)
#### Прямой JSON-RPC через stdio (языконезависимый)
Сервер обменивается сообщениями в формате JSON-RPC 2.0, разделёнными символами новой строки. Вы можете управлять им из любого языка, записывая данные в stdin процесса и читая из stdout:```
→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"my-client","version":"1.0"}}}
← {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{...},"serverInfo":{"name":"WinDbg MCP","version":"1.0.0"}}}
→ {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"load_dump","arguments":{"path":"C:\\crashes\\crash.dmp"}}}
← {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"{\"status\": \"ok\", ...}"}]}}
create — Запускает новый процесс под отладчиком. Установите initial_break=True (по умолчанию), чтобы остановиться на точке входа процесса.
attach — Подключается к запущенному процессу. Укажите либо pid (целое число), либо name (имя файла процесса). Не указывайте оба.
kernel_attach — Подключается к удаленному отладчику ядра. connect_string использует синтаксис KD, например "net:port=55000,key=1.2.3.4".
load_dump — Открывает файл .dmp для посмертного анализа. Сразу возвращает адрес сбоя и ближайший символ.
connect — Подключается к серверу процессов для удаленной отладки в пользовательском режиме. options использует синтаксис подключения DbgEng, например "tcp:server=192.168.1.10,port=5555".
go — Возобновляет выполнение и блокируется до следующего события отладки (точка останова, исключение или тайм-аут). Возвращает новый RIP и все захваты, собранные во время выполнения.
step_into — Выполняет шаг с заходом в следующую инструкцию, следуя вызовам в вызываемые функции.
step_over — Выполняет шаг через следующую инструкцию, рассматривая вызовы как один шаг.
step_out — Выполняется до возврата из текущей функции.
goto — Выполняется до достижения определённого символа или шестнадцатеричного адреса, например "Kernel32!ExitProcess" или "0x7fff12340000".
trace — Выполняет N итераций по одному шагу и записывает каждую посещённую инструкцию.
bp — Устанавливает программную (кодовую) точку останова на символе или адресе.
expr: символ ("ntdll!NtCreateFile") или шестнадцатеричный адрес ("0x7ff800001234")capture: если true (по умолчанию), автоматически сохраняет полное состояние — регистры, стек, память — в буфер захвата каждый раз при срабатывании этой точки остановаaction: "go" (по умолчанию) продолжает выполнение после захвата; "break" останавливаетoneshot: удаляет точку останова после её однократного срабатыванияpasscount: срабатывает только после N проходов через местоположениеhw_bp — Устанавливает аппаратную точку останова / точку наблюдения (watchpoint) для данных.
addr: шестнадцатеричный адрес для наблюденияsize: ширина наблюдения в байтах — 1, 2, 4 или 8 (по умолчанию 4)access: "e" выполнение, "w" запись (по умолчанию), "r" чтение/записьcapture, action, oneshot: имеют ту же семантику, что и у bplist_bps — Возвращает все активные в данный момент точки останова с их ID, выражениями, типами и настройками.
remove_bp / enable_bp / disable_bp — Управление точками останова по id, возвращённому из bp или hw_bp.
Точки останова с capture: true (по умолчанию) автоматически сохраняют полный снимок отладчика каждый раз при срабатывании. Снимок включает все регистры, стек вызовов, 64 байта памяти стека по адресу RSP и 32 байта кода по адресу RIP. Снимки накапливаются в буфере, и их можно получить в любое время с помощью get_captures.
get_captures — Возвращает все захваты, собранные с момента последнего clear_captures. Каждый захват содержит:
registers — все значения регистров в виде {name: "0x..."} (шестнадцатеричные строки)rip — указатель инструкции на момент захватаsymbol_at_rip — ближайший символ к RIPinstruction — дизассемблированная инструкция по адресу RIPstack — 10 верхних кадров стека вызовов с адресами и адресами возвратаcontext_memory.stack_at_rsp — 64 байта по адресу RSP в шестнадцатеричном, форматированном и ASCII видеcontext_memory.code_at_rip — 32 байта по адресу RIP в шестнадцатеричном и форматированном видеclear_captures — Очищает буфер захвата. Полезно перед началом нового прогона.
capture_state — Создаёт немедленный снимок текущего состояния по запросу. Используйте это, когда уже остановились, вместо ожидания срабатывания точки останова.
read_mem — Читает size сырых байтов по адресу addr. Возвращает данные как hex (компактный), formatted (байты, разделённые пробелами) и ascii (печатаемые символы, . для непечатаемых).
write_mem — Записывает байты в память. data — шестнадцатеричная строка; пробелы и префиксы \x автоматически удаляются, например "90909090", "\\x90\\x90\\x90\\x90" или "90 90 90 90".
read_ptr — Читает count последовательных значений размером с указатель (4 байта для 32-битных, 8 байт для 64-битных) начиная с addr.
poi — Разыменовывает единственный указатель по адресу addr (указатель интереса).
read_str — Читает строку, завершающуюся нулевым символом. Установите wide=true для UTF-16LE (Windows WCHAR).
dump_mem — Форматированный дамп двойных слов/указателей, эквивалентно dd/dp в WinDbg.
mem_info — Возвращает свойства региона памяти для страницы, содержащей addr: базовый адрес, размер, тип, состояние и флаги защиты.
mem_list — Перечисляет все регионы виртуальной памяти в адресном пространстве целевого процесса.
get_regs — Возвращает все доступные регистры в виде {name: "0x..."}. Точный набор зависит от архитектуры цели (x86 vs x64).
get_reg — Возвращает один регистр, например name="rax", name="eflags".
set_reg — Перезаписывает регистр. value принимает шестнадцатеричные строки ("0x1234") или строки с десятичными целыми числами.
get_pc — Возвращает указатель инструкции с разрешением символа и декодированным текстом инструкции по этому адресу.
get_sp — Возвращает текущее значение указателя стека.
resolve — Разрешает имя символа в его виртуальный адрес. Используйте формат Module!Function, например "Kernel32!WriteFile", "ntdll!NtCreateFile".
find_symbols — Поиск символов с подстановочными знаками, например "ntdll!*Alloc*", "kernel32!*File*". Возвращает все соответствующие строки символов.
addr_to_symbol — Обратное разрешение виртуального адреса в ближайшее имя символа.
disasm — Дизассемблирует count инструкций начиная с addr. По умолчанию используется текущий RIP, если адрес не указан.
whereami — Возвращает читаемое описание модуля, функции и смещения по заданному адресу.
list_modules — Перечисляет все модули, загруженные в целевой процесс, с их базовым адресом и размером.
module_info — Возвращает точку входа и список секций (имя, виртуальный адрес, размер) для конкретного модуля, например "kernel32.dll", "ntdll.dll".
get_exports — Возвращает полную таблицу экспорта модуля в виде списка строк.
get_imports — Возвращает полную таблицу импорта модуля в виде списка строк.
list_threads — Перечисляет все потоки в целевом процессе.
get_thread — Возвращает контекст текущего активного потока.
set_thread — Переключает контекст активного потока по идентификатору потока (из list_threads).
get_stack — Возвращает стек вызовов в виде структурированных данных. Каждый кадр включает адрес инструкции, адрес возврата и указатель кадра.
get_teb — Возвращает адрес блока среды потока (Thread Environment Block) для текущего потока.
get_peb — Возвращает адрес блока среды процесса (Process Environment Block).
get_handles — Перечисляет все открытые дескрипторы в целевом процессе.
get_bitness — Возвращает 32 или 64 в зависимости от архитектуры цели.
raw — Выполняет любую командную строку WinDbg и возвращает вывод в виде текста. Используйте это как запасной вариант для всего, что не охвачено другими инструментами:```
raw(cmd="!heap -stat")
raw(cmd="dt _PEB @$peb")
raw(cmd="!locks")
raw(cmd="lm")
raw(cmd="!address @rsp")
## Типичные рабочие процессы
### Проверка эксплойта```
1. create(path="C:/target/vuln.exe", args="exploit_input.bin")
2. bp(expr="vuln!processInput+0x2A", action="break")
3. go(timeout=15000)
4. get_captures()
В get_captures, проверьте captures[0].registers.rip:
"0x4141414141414141" — вы управляете RIP с помощью байтов 'A'Проверьте captures[0].context_memory.stack_at_rsp.formatted, чтобы увидеть выравнивание, адреса возврата или байты шеллкода на стеке.
### Heap spray верификация```
1. attach(name="target.exe")
2. hw_bp(addr="0x1001F000", size=8, access="w", action="break")
3. go()
4. get_captures() → see what wrote to the spray address
5. read_mem(addr="0x1001EFC0", size=128) → surrounding memory context
### Удаленная отладка ядра```
1. kernel_attach(connect_string="net:port=55000,key=1.2.3.4")
2. list_modules() → all loaded kernel modules
3. module_info(name="ntoskrnl.exe") → entry point and sections
4. raw(cmd="!process 0 0") → list all processes from kernel context
5. raw(cmd="!pcr") → processor control region
---
## Советы
**Symbol path** — Если разрешение символов не дает результатов, настройте сервер символов Microsoft:```
raw(cmd=".sympath srv*C:\\symbols*https://msdl.microsoft.com/download/symbols")
raw(cmd=".reload")
Настройка тайм-аута — go() по умолчанию составляет 30 секунд. Для целей, которые выполняются дольше перед достижением точки останова:```
go(timeout=120000) # 2 minutes
go(timeout=300000) # 5 minutes
**Формат адреса** — Все параметры `addr` принимают hex-строки (`"0x1234abcd"`, `"7fff12340000"`) или целые числа. Префикс `0x` необязателен для hex-значений.
**Проверка шеллкода** — После захвата используйте `read_mem` и `disasm` по адресу, где должен располагаться ваш шеллкод. Если `disasm` показывает ваши предполагаемые инструкции, полезная нагрузка доставлена без повреждений.
**После `terminate` или `detach`** — Все захваты и точки останова автоматически очищаются. Вызовите `create` или `attach`, чтобы начать новый сеанс.
**`capture_state` против `get_captures`** — Используйте `capture_state` для снимка по запросу, когда вы уже остановлены на точке останова. Используйте `get_captures` для получения состояния, которое автоматически сохранялось каждый раз при срабатывании точки останова во время вызова `go`.
**Команды ядра `raw`** — Распространенные расширения отладки ядра, которые хорошо работают через `raw`:```
raw(cmd="!process 0 0") → list all processes
raw(cmd="!thread") → current thread details
raw(cmd="!irql") → current IRQL
raw(cmd="!pcr") → processor control region
raw(cmd="!pte <addr>") → page table entry for an address
raw(cmd="dt nt!_EPROCESS @$proc") → dump EPROCESS structure
MIT
| Инструмент | Параметры | Возвращаемое значение |
|---|
status | — | {connected, type, pid, bitness} |
list_processes | — | [{pid, name, description}] |
create | path (обязательный), args, initial_break | {status, pid, bitness} |
attach | pid или name (не оба), initial_break | {status, pid, bitness} |
kernel_attach | connect_string (обязательный), initial_break | {status, type, connect_string} |
load_dump | path (обязательный) | {status, bitness, rip, symbol_at_rip} |
connect | options (обязательный) | {status, options} |
detach | — | {status} |
terminate | — | {status} |
| Инструмент | Параметры | Возвращаемое значение |
|---|
go | timeout (мс, по умолчанию 30000) | {status, rip, symbol, new_captures, captures} |
step_into | count (по умолчанию 1) | {rip, instruction, symbol} |
step_over | count (по умолчанию 1) | {rip, instruction, symbol} |
step_out | — | {rip, instruction, symbol} |
goto | expr (обязательный) | {rip, symbol} |
trace | count (по умолчанию 10) | {instructions: [{rip, instruction, symbol}], count} |
| Инструмент | Параметры | Возвращаемое значение |
|---|
bp | expr (обязательный), capture, action, oneshot, passcount | {id, expr, addr, capture} |
hw_bp | addr (обязательный), size, access, capture, action, oneshot | {id, addr, size, access} |
list_bps | — | [{id, expr, type, capture, action, ...}] |
remove_bp | id (обязательный) | {status, id} |
enable_bp | id (обязательный) | {status, id} |
disable_bp | id (обязательный) | {status, id} |
| Инструмент | Параметры | Возвращаемое значение |
|---|
get_captures | — | {count, captures: [{bp_id, expr, timestamp, registers, rip, symbol_at_rip, instruction, stack, context_memory}]} |
clear_captures | — | {status} |
capture_state | — | {timestamp, registers, rip, symbol_at_rip, instruction, disasm_5, stack_at_rsp, call_stack} |
| Инструмент | Параметры | Возвращаемое значение |
|---|
read_mem | addr (обязательный), size (по умолчанию 16) | {addr, size, hex, formatted, ascii} |
write_mem | addr (обязательный), data (обязательный, шестнадцатеричная строка) | {status, addr, bytes_written} |
read_ptr | addr (обязательный), count (по умолчанию 1) | {addr, values: ["0x..."]} |
poi | addr (обязательный) | {addr, value} |
read_str | addr (обязательный), wide (по умолчанию false) | {addr, value, wide} |
dump_mem | addr (обязательный), count (по умолчанию 8) | {addr, output} |
mem_info | addr (обязательный) | {addr, info} |
mem_list | — | [region_description_strings] |
| Инструмент | Параметры | Возвращаемое значение |
|---|
get_regs | — | {rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp, rip, r8–r15, eflags, ...} |
get_reg | name (обязательный) | {name, value} |
set_reg | name (обязательный), value (обязательный) | {status, name, value} |
get_pc | — | {value, symbol, instruction} |
get_sp | — | {value} |
| Инструмент | Параметры | Возвращаемое значение |
|---|
resolve | name (обязательный) | {name, addr} или {name, addr: null, error} |
find_symbols | pattern (обязательный) | [symbol_strings] |
addr_to_symbol | addr (обязательный) | {addr, symbol} |
disasm | addr (по умолчанию: текущий RIP), count (по умолчанию 10) | {addr, output} |
whereami | addr (необязательный, по умолчанию: текущий RIP) | {description} |
| Инструмент | Параметры | Возвращаемое значение |
|---|
list_modules | — | [{name, base, size}] |
module_info | name (обязательный) | {name, entry_point, sections} |
get_exports | name (обязательный) | [export_strings] |
get_imports | name (обязательный) | [import_strings] |
| Инструмент | Параметры | Возвращаемое значение |
|---|
list_threads | — | [thread_description_strings] |
get_thread | — | {current_thread} |
set_thread | id (обязательный) | {status, thread} |
get_stack | frames (по умолчанию 20) | {frames: [{frame, addr, return_addr, frame_ptr}], count} |
get_teb | — | {addr} |
get_peb | — | {addr} |
| Инструмент | Параметры | Возвращаемое значение |
|---|
get_handles | — | [handle_description_strings] |
get_bitness | — | {bits} |
raw | cmd (обязательный) | {output} |