
すべてのpybag Windowsデバッガ機能をネイティブMCPツールに変換するMCP (Model Context Protocol) サーバーです。MCP互換クライアント (Claude Desktop、Claude Code、Cowork、OpenAI Codex CLI、Cursor、カスタムエージェント) が、構造化JSON呼び出しを介してユーザーモードプロセス、カーネルセッション、クラッシュダンプ分析を制御できるようにします。
すべての pybag Windows デバッガー関数をネイティブ MCP ツールとして公開する MCP (Model Context Protocol) サーバーです。任意の 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 をダウンロードし、セットアップ中に Debugging Tools for 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.jsonClaude Desktop を再起動してください。55 個のデバッガツールが自動的に表示されます。
---
### Claude Code (CLI)
サーバーを登録するには、次のコマンドを一度実行してください。Claude Code はエントリを自身の MCP config に保存し、以降のセッションでツールを利用できるようにします。```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
CoworkにWinDbg MCPを追加する方法は2つあります: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) または `%USERPROFILE%\.codex\config.json` (Windows)。```json
{
"mcpServers": {
"windbg-mcp": {
"command": "python",
"args": ["C:\\path\\to\\windbg-mcp\\windbg_mcp.py"]
}
}
}
保存後、新しいCodexセッションを開始します。WinDbgツールがモデルから呼び出せるようになります。
4. 保存します。Cursor は次回の 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"]
}
}
]
}
}
Reload the Continue extension. The 55 debugger tools will appear in the tool list.
If you are building your own agent or automation pipeline, connect to WinDbg MCP over the standard MCP stdio transport. The server speaks JSON-RPC 2.0 over stdin/stdout.
mcp SDK)```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)
#### stdio 経由の直接 JSON-RPC (言語非依存)
サーバーは改行区切りの 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 — 次の命令をステップオーバーし、呼び出しを1ステップとして扱います。
step_out — 現在の関数が戻るまで実行します。
goto — 指定されたシンボルまたは16進アドレスに達するまで実行します。例:"Kernel32!ExitProcess" または "0x7fff12340000"。
trace — N回のシングルステップ反復を実行し、各命令を記録します。
bp — シンボルまたはアドレスにソフトウェア(コード)ブレークポイントを設定します。
expr: シンボル("ntdll!NtCreateFile")または16進アドレス("0x7ff800001234")capture: true(デフォルト)の場合、このブレークポイントが発生するたびに、レジスタ、スタック、メモリを含む完全な状態をキャプチャバッファに自動的に保存しますaction: "go"(デフォルト)はキャプチャ後に実行を継続します。"break"は停止します。oneshot: ブレークポイントが一度発生した後、削除されます。passcount: その位置をN回通過した後にのみ発生します。hw_bp — ハードウェア/データブレークポイント(ウォッチポイント)を設定します。
addr: 監視する16進アドレスsize: 監視幅(バイト単位) — 1、2、4、8(デフォルト 4)access: "e" 実行、"w" 書き込み(デフォルト)、"r" 読み取り/書き込みcapture、action、oneshot:bpと同じセマンティクスlist_bps — 現在アクティブなすべてのブレークポイントを、ID、式、タイプ、設定とともに返します。
remove_bp / enable_bp / disable_bp — bpまたはhw_bpから返されたidでブレークポイントを管理します。
capture: true(デフォルト)のブレークポイントは、発火するたびにデバッガの完全なスナップショットを自動的に保存します。スナップショットには、すべてのレジスタ、コールスタック、RSPの64バイトのスタックメモリ、RIPの32バイトのコードが含まれます。スナップショットはバッファに蓄積され、get_capturesでいつでも取得できます。
get_captures — 最後のclear_captures以降に収集されたすべてのキャプチャを返します。各キャプチャには以下が含まれます:
registers — {name: "0x..."} の16進文字列としてのすべてのレジスタ値rip — キャプチャ時の命令ポインタsymbol_at_rip — RIPに最も近いシンボルinstruction — RIPの命令の逆アセンブルstack — アドレスとリターンアドレスを含む上位10のコールスタックフレームcontext_memory.stack_at_rsp — RSPの64バイトを16進数、フォーマット済み、ASCIIで表示context_memory.code_at_rip — RIPの32バイトを16進数とフォーマット済みで表示clear_captures — キャプチャバッファをクリアします。新しい実行を開始する前に便利です。
capture_state — 現在の状態の即時オンデマンドスナップショットを取得します。ブレークポイントの発火を待つ代わりに、すでに停止している場合にこれを使用します。
read_mem — addrからsizeバイトの生データを読み取ります。データをhex(コンパクト)、formatted(スペース区切りバイト)、ascii(表示可能文字、非表示は.)として返します。
write_mem — メモリにバイトを書き込みます。dataは16進文字列です。スペースや\xプレフィックスは自動的に除去されます。例:"90909090"、"\\x90\\x90\\x90\\x90"、"90 90 90 90"。
read_ptr — addrからcount個の連続したポインタサイズの値(32ビットでは4バイト、64ビットでは8バイト)を読み取ります。
poi — addrの単一のポインタをデリファレンスします(対象ポインタ)。
read_str — NULL終端文字列を読み取ります。UTF-16LE(Windows WCHAR)の場合はwide=trueを設定します。
dump_mem — フォーマットされたDWORD/ポインタダンプ。WinDbgのdd/dpに相当します。
mem_info — addrを含むページのメモリ領域プロパティ(ベースアドレス、サイズ、タイプ、状態、保護フラグ)を返します。
mem_list — ターゲットプロセスのアドレス空間内のすべての仮想メモリ領域を一覧表示します。
get_regs — 利用可能なすべてのレジスタを{name: "0x..."}として返します。正確なセットはターゲットアーキテクチャ(x86 vs x64)に依存します。
get_reg — 1つのレジスタを返します。例:name="rax"、name="eflags"。
set_reg — レジスタを上書きします。valueは16進文字列("0x1234")または10進整数文字列を受け入れます。
get_pc — シンボル解決およびそのアドレスのデコードされた命令テキストとともに命令ポインタを返します。
get_sp — 現在のスタックポインタ値を返します。
resolve — シンボル名を仮想アドレスに解決します。モジュール!関数形式を使用します。例:"Kernel32!WriteFile"、"ntdll!NtCreateFile"。
find_symbols — ワイルドカードシンボル検索。例:"ntdll!*Alloc*"、"kernel32!*File*"。一致するすべてのシンボル文字列を返します。
addr_to_symbol — 仮想アドレスを最も近いシンボル名に逆解決します。
disasm — addrからcount個の命令を逆アセンブルします。アドレスが指定されない場合は現在のRIPがデフォルトになります。
whereami — 指定されたアドレスのモジュール、関数、オフセットを人間が読める形式で返します。
list_modules — ターゲットにロードされているすべてのモジュールを、ベースアドレスとサイズとともに一覧表示します。
module_info — 特定のモジュール(例:"kernel32.dll"、"ntdll.dll")のエントリポイントとセクションリスト(名前、仮想アドレス、サイズ)を返します。
get_exports — モジュールの完全なエクスポートテーブルを文字列のリストとして返します。
get_imports — モジュールの完全なインポートテーブルを文字列のリストとして返します。
list_threads — ターゲットプロセス内のすべてのスレッドを一覧表示します。
get_thread — 現在アクティブなスレッドコンテキストを返します。
set_thread — スレッドID(list_threadsから)でアクティブなスレッドコンテキストを切り替えます。
get_stack — コールスタックを構造化データとして返します。各フレームには命令アドレス、リターンアドレス、フレームポインタが含まれます。
get_teb — 現在のスレッドのスレッド環境ブロック(TEB)のアドレスを返します。
get_peb — プロセス環境ブロック(PEB)のアドレスを返します。
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" — あなたは 'A' バイトで RIP を制御していますcaptures[0].context_memory.stack_at_rsp.formatted を確認して、スタック上のパディング、リターンアドレス、またはシェルコードバイトを確認します。
### ヒープスプレー検証```
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
---
## ヒント
**シンボルパス** — シンボル解決で結果が返されない場合は、Microsoft シンボルサーバーを構成してください:```
raw(cmd=".sympath srv*C:\\symbols*https://msdl.microsoft.com/download/symbols")
raw(cmd=".reload")
Timeout tuning — go() デフォルトは30秒です。ブレークポイントに達するまでに時間がかかる対象の場合:```
go(timeout=120000) # 2 minutes
go(timeout=300000) # 5 minutes
**アドレス形式** — すべての `addr` パラメータは16進文字列 (`"0x1234abcd"`, `"7fff12340000"`) またはプレーンな整数を受け入れます。16進値の場合、`0x` プレフィックスは省略可能です。
**シェルコードの検証** — キャプチャ後、シェルコードが配置されるべきアドレスで `read_mem` と `disasm` を使用します。`disasm` が意図した命令を表示する場合、ペイロードは完全に到着しています。
**`terminate` または `detach` の後** — すべてのキャプチャとブレークポイントは自動的にクリアされます。新しいセッションを開始するには `create` または `attach` を呼び出します。
**`capture_state` と `get_captures` の比較** — ブレークポイントで停止しているときにオンデマンドのスナップショットを取得するには `capture_state` を使用します。`go` 呼び出し中にブレークポイントが発動するたびに自動的に保存された状態を取得するには `get_captures` を使用します。
**カーネル `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(必須、16進文字列) | {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} |