Skip to main content
Glama
RAD Debugger MCP

RAD Debugger MCP

by cc8887

RAD Debugger MCP

独立的 Windows x64 原生调试 MCP 服务。通过 RAD Debugger 进行启动、附加、断点、单步、调用栈和表达式检查。

不需要 Unreal Editor、UnrealEditor MCP、UE 插件、PythonScriptPlugin 或正在运行的编辑器。 普通带 PDB 的 C/C++ EXE、UnrealEditor、游戏客户端和 Dedicated Server 都使用同一个原生调试流程。通用表达式格式化由 RAD 提供,服务另补充显式布局验证的 UE 结构化读取;兼容性需要在目标引擎版本验证。

当前实现使用 MCP stdio。每个调试会话拥有一个无图形 RAD 后端、随机回环端口、独立认证令牌和配置目录。认证令牌不通过 MCP 返回,也不写入配置文件。不暴露原始 RAD 命令、shell 或内存写入工具;rad_launch 会执行指定的本地 EXE,应只用于明确授权的目标。

构建与启动

要求:Windows x64、Python 3.11+、Git、MSVC x64 Build Tools 与 Windows SDK。当前验证环境为 Python 3.14、MCP Python SDK 1.26.0、MSVC 19.38。

先克隆本项目和官方 RAD 源码,再构建独立后端:

git clone https://github.com/cc8887/raddebugger-mcp.git
cd raddebugger-mcp
git clone https://github.com/EpicGames/raddebugger.git ../raddebugger
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e .
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-backend.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/start.ps1

已经存在源码目录时跳过相应 clone。build-backend.ps1 默认从相邻的本地仓库创建 .build/raddebugger 构建副本,并固定在 771f63dd35d3d17f0c7914c5031959282802be5f;不会改动原始 RAD 仓库。可用 -Upstream ../your-rad-checkout 指定其他源码位置。构建后的来源与 SHA-256 写入 .build/backend-manifest.json。

start.ps1 会设置模块路径,因此开发阶段也可以使用已有 MCP SDK 的 Python 启动,不要求 editable install。stdio 启动后没有命令提示符;它等待 MCP 客户端。

支持 MCP stdio 的客户端配置示例(安装包后;将 <absolute-repo-path> 替换成实际检出目录的绝对路径):

{
  "mcpServers": {
    "raddebugger": {
      "command": "<absolute-repo-path>/.venv/Scripts/python.exe",
      "args": ["-m", "raddebugger_mcp"]
    }
  }
}

也可以将 command 指向 powershell.exe,args 设置为 -NoProfile -ExecutionPolicy Bypass -File <absolute-repo-path>/scripts/start.ps1 的各个独立参数。其他位置的后端使用 --backend <exe> 或 RAD_MCP_BACKEND。会话目录使用 --session-root <directory>。

Related MCP server: qwen-dap-mcp

调试流程

  1. rad_create_session 得到 session_id。这一步仅启动 RAD 后端。

  2. rad_set_breakpoint 设置函数、行或地址断点;可以在目标启动前设置。

  3. rad_launch 启动 EXE,默认停在入口;或通过 rad_list_processes 找到明确的 PID,再 rad_attach。

  4. rad_continue 返回 wait_after_run_gen 和 wait_after_stop_count;传给 rad_wait_for_stop 等待新的停点或退出。

  5. 在停点调用 rad_get_stack、rad_get_state、rad_evaluate;用 rad_select_context 选择线程或栈帧。

  6. rad_step 支持源码 into/over/out 及指令 into/over;rad_run_to_line 运行到行。

  7. rad_close_session 默认分离并恢复应用。只有显式 terminate_debuggee=true 才终止目标。

例如启动 UE 项目,参数仍然是普通 EXE 参数:

{
  "session_id": "<rad_create_session 返回的 ID>",
  "program": "<absolute-engine-path>/Engine/Binaries/Win64/UnrealEditor.exe",
  "args": ["<absolute-project-path>/MyGame.uproject", "-log"],
  "stop_at_entry": true
}

这里没有向编辑器发送 MCP 请求。现有 Editor、客户端或 Server 也可以独立附加。目标必须允许原生调试,并有与二进制匹配的符号;首次 PDB → RDI 转换可能耗时。debug_subprocesses 默认关闭,可在 launch 中明确开启。

工具

工具

功能

rad_create_session, rad_list_sessions, rad_close_session

会话生命周期

rad_list_processes, rad_launch, rad_attach

选择、启动、附加目标

rad_get_state, rad_wait_for_stop

状态、停点代际与有界等待

rad_set_breakpoint, rad_list_breakpoints, rad_remove_breakpoint

行、函数、地址断点

rad_continue, rad_pause, rad_step, rad_run_to_line

原生执行控制

rad_get_stack, rad_select_context

调用栈、线程及栈帧选择

rad_evaluate, rad_address_to_line

类型/值与地址到源码映射

rad_read_value

有界结构化读取 FString、FText、TArray 与稀疏 TMap(显式 UE4.26 Win64 布局)

rad_read_object

通过运行时 UClass/FProperty 读取蓝图专属属性,递归展开结构体、TArray/TMap

rad_open_crash_dump

本地 dump 装载;受 dump/PDB 数据覆盖限制

返回值的含义

  • requested:命令已发送,应使用返回的基线等待停点;不代表已经停住。

  • stopped:观察到了比基线更新的停点。

  • exited:观察到目标进程集合已清空;具体退出码需要结合输出/停点原因确认。

  • timeout:截止时间前没有新的停点,不会自动终止、暂停或重放命令。

  • 断点的 resolution=configured 只表示 RAD 配置已存在;不能据此宣称机器地址已解析或断点已命中。

  • 表达式返回 ok、messages、read_failed、run_gen、stop_count、线程/帧、时间戳和读取方式。补丁后端的 memory_freshness=direct_process_read 表示进程内存绕过异步页面缓存;读取不完整或失败会令 ok=false。寄存器、栈展开和符号仍由 RAD 提供,consistency=same_stop_epoch 不代表整个进程的原子快照。显示上限为 512 UTF-8 字节,按完整 Unicode 序列截断,并返回 possibly_truncated、type_truncated、value_encoding_valid、type_encoding_valid、invalid_encoding。截断不是完整成功;旧字段 display_limit_chars 仅为兼容保留,请使用 display_limit_bytes。

UE 值的结构化读取

在已停止、具有匹配 PDB 的目标上调用:

{"session_id":"<id>","expression":"this->SettingsByName","kind":"tmap","layout":"ue4_26","start":0,"count":16,"slot_scan_budget":256}

表达式中的成员名仅为示例,以目标的实际 PDB 为准。kind 可为 auto、fstring、ftext、tarray、tmap。本工具不需要 UE 插件或编辑器接口,不调用目标函数,也不修改目标内存。

  • FString/FText 使用精确 UTF-16 数值读取并严格解码,保留嵌入 NUL,支持中文与非 BMP 字符。start / next_index 是 UTF-16 单元偏移,单页 max_string_units 默认及最大 4096;不会从代理对中间续读。complete=false / truncated=true 表示部分结果。

  • FText 只读取 PDB 已验证的 localized shared string 或 generated display string;未知 history/layout 明确失败,不调用 ToString()、本地化解析或强制刷新文本。

  • 常规 rad_evaluate 遇到 FText 也复用这一语义路径,返回带引号的显示文本及 representation=ue4_26_ftext_display_string;原生通用结构展开的诊断单独保存在 native_display_diagnostics。显式 raw(...) / typeof(...) 保留原生行为。语义读取失败不会退回看似成功的通用展开;512 字节上限仍适用,全文请用 rad_read_value。

  • TMap 按稀疏槽位的占用位图跳过空洞,由 PDB 推导槽位地址,不猜测 sizeof(Key)+sizeof(Value)。start / next_index 是物理槽位索引,count 限制返回条目,slot_scan_budget 限制扫描槽位;扫描预算耗尽仍有明确续页位置。支持的叶值包括 FName、FString/FText、标量与对象指针;未知结构体返回 opaque,不伪装成完整反射树。

  • 单次最多 512 个求值探针、60 秒;所有探针与最终检查使用同一锁定停点/进程/线程/帧。任何代际变化立即失败,不拼接跨停点数据。该一致性仍不是整个进程的原子快照。

布局目前仅为显式 ue4_26 Windows x64 profile;UE5、定制 allocator/name pool 和任意 FText history 未作普遍兼容承诺。更新 Python 服务后,需要客户端重新连接以刷新新增工具清单。

  • 使用先前快照作决策时,传 expected_run_gen/expected_stop_count。过期快照返回 STALE_SNAPSHOT;运行中的值检查返回 TARGET_RUNNING。

蓝图与 UObject 属性树

rad_read_object 接收 UObject 指针表达式,从目标进程的 ClassPrivate → ChildProperties/SuperStruct → FProperty 获取实际字段名、声明类、偏移、类型及容器布局,PDB 只提供元数据结构的成员偏移。蓝图专属变量不需要出现在 C++ PDB 成员表中。blueprint_defined 来自声明类的 CLASS_CompiledFromBlueprint 标志;declared_by 保留声明来源。它不依赖 UnrealEditor MCP、编辑器 RPC、UE Python 或目标函数调用。

{"session_id":"<id>","expression":"this","include_inherited":false,"metadata_only":true,"count":128}
{"session_id":"<id>","expression":"this","property_path":["Inventory",2,"Attributes"],"max_depth":5,"count":16}

先用 metadata_only=true 发现字段,再用 properties=["实际字段名"] 或 property_path 选择读取。路径由精确运行时字段名、数组下标、Map 物理槽位下标加 "key"/"value" 组成;用户自定义蓝图结构体的字段可能带 GUID,不擅自重命名。结构体及固定数组、TArray、TMap 可递归嵌套,Map 使用 FMapProperty.MapLayout 与稀疏位图推导地址。支持标量、布尔位域、枚举底层整数、FName、FString、FText 及对象引用;软/弱引用、Set、委托和未知属性类明确报告不支持。

对象引用默认只返回地址、名称和运行时类身份;follow_objects=true 才递归读取,循环引用返回地址引用标记。深度耗尽、分页和元素上限返回 complete=false,不是完整成功。顶层 start/count 控制属性页或选中容器的页,嵌套 max_elements/max_properties 限制展开,返回的 property_path/next_index 可用于继续读取;Map 下标不是条目序号。默认深度 3(最大 8)、节点 256(最大 1024)、元数据字段 1024(最大 2048)、字符串单页 256 个 UTF-16 单元(最大 4096);单次最多 4096 个求值探针、60 秒、512 KiB 输出。所有探针及最终校验仍属于同一停点/进程/线程/帧,不是整个进程的原子快照。仅承诺有匹配 PDB 的 UE4.26 Win64 已支持布局,不承诺任意引擎版本或任意 UObject 图完整展开。

会话状态、目标参数、stdout/stderr 和 RAD 日志保存在本地会话目录,不会自动上传。普通关闭与 MCP stdin EOF 会尝试先分离目标,再退出后端;后端还禁用了 Windows 的 debugger-exit-kills-debuggee 行为。断电、强制结束主机、目标自身异常等不属于正常清理验收。

验证

$env:PYTHONPATH = "$PWD/src"
.\.venv\Scripts\python.exe -m unittest discover -s tests -v
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-types-fixture.ps1
.\.venv\Scripts\python.exe scripts/regression_types.py
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-fixture.ps1
.\.venv\Scripts\python.exe -u scripts/smoke.py
.\.venv\Scripts\python.exe -u scripts/regression_detach.py

smoke 测试使用官方 Python MCP SDK,通过真实 stdio 协议调用本服务,再经认证 TCP 控制 RAD,调试项目内自带的 MSVC/PDB 测试程序。结果写入 artifacts/smoke-*/result.json。在禁止本机 socket/Windows 异步 I/O 的沙箱中,需要在主机权限环境运行测试。

regression_types.py 使用独立 UE4.26 布局 C++/PDB fixture,经真实 MCP stdio 验证直接 Unicode 显示、有界 UTF-16 解码、FText 存储、容器分页、稀疏位图和不同槽位大小。它不是 Unreal 运行时验收;可用 --backend <old-backend.exe> 做旧后端负对照。记录位于 artifacts/types-layout-regression-*/result.json。

regression_detach.py 专门覆盖源码单步、指令单步、函数断点、行断点、暂停和运行中关闭这六类直接分离路径,默认各重复两次。有限程序必须在分离后通过原始 Windows 进程句柄确认退出码为 0,且输出正确;不会把“短暂存活”当作通过。循环程序还必须无调试器且计数继续增长。可用 --backend <old-backend.exe> --cases source_step --repeat 1 做旧后端负对照。结果位于 artifacts/detach-regression-*/result.json。

详细能力边界与验收记录见 docs/verification.md。运行时只依赖 RAD 和 MCP SDK;这些测试不需要 UE 安装。

真实 UE 项目验收(可选,需要已有项目、UE 5.8.1 和匹配插件 DLL/PDB):

.\.venv\Scripts\python.exe -u scripts/smoke_ue.py --project ../RmlUiUnrealTest/RmlUiUnrealTest.uproject --engine "<path-to-UE_5.8>"

该脚本通过 MCP 启动现有项目内的 RmlUi.Animation.MovieSceneRuntime.Lifecycle 自动化,验证函数/行断点、源码单步、局部结构体与完成计数;分离后再附加同一个正在运行的 UE PID,验证引擎 Tick 地址断点、指令单步和帧计数。测试使用 NullRHI,不作为画面验收;不安装插件、不编译或改写目标源码,也不调用 UnrealEditor MCP。结束时仅清理本脚本启动并保留了原始句柄的 UE 进程。结果位于 artifacts/ue-smoke-*/result.json。外部 UE 工程和原始私有验收产物不随本仓库发布,普通单元测试与 C/PDB smoke 不需要它们。

源码与维护

  • src/raddebugger_mcp/:MCP 工具、会话、分帧与 Metadesk 回复解析。

  • native/upstream.patch:固定提交的少量桥接改动;新增代码在 native/mcp_extension.c。

  • scripts/build-backend.ps1:独立源码副本、补丁和后端构建。

  • tests/、scripts/smoke.py、scripts/regression_detach.py:协议、分离契约回归与真实调试验收。

  • scripts/smoke_ue.py、scripts/ue_pe.py:可选现有 UE 项目验收及引擎导出地址解析,均不属于服务运行时依赖。

RAD 补丁提供:回环绑定、每会话认证、TCP 请求重组、正常断连处理、较大的回复队列、无图形链接修复、进程/线程数值选择、调用栈/配置证据、独立目标配置输入,以及直接内存求值和读取失败报告。启动时不覆盖 RAD 自动保存的活动项目文件,已有断点 ID 保持有效。升级上游时需要重新核对补丁和协议,不能直接替换为任意官方 release EXE。

Win32 分离还会保留独立线程句柄,在目标线程保持调试器显式挂起时,先处理属于该 PID 的待续行调试事件,再请求 Windows 分离并恢复线程。调试器自身的单步/断点事件与程序自身异常采用不同续行状态;续行或分离请求失败时保留会话用于重试。此前“单步后直接分离”可导致目标以 0x80000003 退出,旧构建应重新构建,不能只更新 Python 服务。

当前没有 Blueprint VM、Actor/Component 枚举、资产编辑、PIE 操作、GPU 调试、Android/主机调试、远程调试、内存写入或目标函数调用 API。rad_evaluate 使用 RAD 表达式语言,不承诺任意 C++ 表达式兼容性。Shipping/优化构建可能缺失局部变量。

表达式示例:g_counter 读取变量;hex(cast(uint64)(&g_counter)) 获取地址;*(cast(int32*)0xADDRESS) 读取明确地址。优先使用 RAD 的 cast(type),一元运算的操作数再加一层括号;内置整数类型为 int32/uint64 等。不要把 (uint64)&value 当作可靠的 C++ 转换写法。求值失败时以 ok=false 和 messages 为准,不使用显示出的占位数值。

项目采用 MIT 许可;RAD Debugger 的版权与 MIT 声明保存在 native/UPSTREAM_LICENSE。MCP 使用 官方 Python SDK。

Available Tools

20 tools
rad_address_to_lineB
Read-only

Resolve a virtual address to source lines in the selected process.

Inputs: address (required), session_id (required). Returns: object

rad_attachA

Attach to an existing local application PID and wait for a debug stop. May pause the application.

Inputs: pid (required), session_id (required), timeout. Returns: object

rad_close_sessionA
Destructive

Close RAD and detach/resume applications by default. terminate_debuggee=true explicitly terminates attached processes.

Inputs: session_id (required), terminate_debuggee. Returns: object

rad_continueB

Resume attached processes and return a baseline for rad_wait_for_stop.

Inputs: session_id (required), expected_run_gen, expected_stop_count. Returns: object

rad_create_sessionB

Create an isolated, authenticated headless RAD backend. Does not start an application.

Inputs: name, startup_timeout. Returns: object

rad_evaluateB
Read-only

Evaluate a RAD read expression while stopped. Returns type, formatted value, messages and explicit cache/epoch evidence.

Inputs: expression (required), session_id (required), expected_run_gen, expected_stop_count. Returns: object

rad_get_stackB
Read-only

Read the selected thread's native call stack, symbol names and source locations. At most 128 backend frames.

Inputs: session_id (required), count, start. Returns: object

rad_get_stateB
Read-only

Return current run_gen, stop_count, stop reason, processes, threads and local names. Optional full module/stack lists.

Inputs: session_id (required), include_stack, include_modules. Returns: object

rad_launchB

Launch a local x64 executable with PDBs. Arguments are a list; no shell is used. Stops at entry by default.

Inputs: program (required), session_id (required), args, timeout, +3 more. Returns: object

rad_list_breakpointsB
Read-only

Read actual RAD breakpoint configuration and observed hit counts.

Inputs: session_id (required). Returns: object

rad_list_processesA
Read-only

List local Windows PIDs, executable names and parent PIDs. Select the exact application PID before attaching.

Inputs: name_contains. Returns: object

rad_list_sessionsA
Read-only

List this MCP service's active debug sessions.

Inputs: no named parameters. Returns: object

rad_open_crash_dumpB

Load a local native crash dump in an empty session. Symbol and memory coverage depend on the dump and matching PDBs.

Inputs: path (required), session_id (required), timeout. Returns: object

rad_pauseB

Pause running processes and wait for the resulting stop.

Inputs: session_id (required), timeout. Returns: object

rad_remove_breakpointA

Remove a breakpoint ID returned by this session. Does not accept arbitrary config IDs.

Inputs: session_id (required), breakpoint_id (required). Returns: object

rad_run_to_lineB

Run from the current stop to a source line, another stop, or exit.

Inputs: file (required), line (required), session_id (required), timeout. Returns: object

rad_select_contextA

Select a thread and/or reported stack frame before evaluating locals. Frame indices come from rad_get_stack.

Inputs: session_id (required), thread_id, frame_index, expected_stop_count. Returns: object

rad_set_breakpointB

Configure one breakpoint: file+line, function name, or address string. Configuration does not prove symbol resolution.

Inputs: kind (required), session_id (required), file, line, +2 more. Returns: object

rad_stepB

Step the selected stopped thread at source/instruction level. Returns a new stop, exit or timeout.

Inputs: session_id (required), kind, timeout, expected_run_gen, +1 more. Returns: object

rad_wait_for_stopB
Read-only

Wait at most 60 seconds for a NEW stop/exit. Timeout does not cancel execution. Defaults to the last execution baseline.

Inputs: session_id (required), timeout, after_run_gen, after_stop_count. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 20 tools

    Disambiguation4/5

    Most tools target clearly distinct actions: session lifecycle, process control, breakpoints, and inspection are well separated. Minor overlap exists between rad_create_session and rad_launch/rad_attach, and between rad_continue and rad_wait_for_stop, but descriptions clarify the relationship.

    Naming Consistency5/5

    All tools use the rad_ prefix with snake_case and follow a predictable verb_noun or single-verb pattern (create_session, set_breakpoint, step, continue). The convention is uniform and immediately readable.

    Tool Count4/5

    Twenty tools is above the typical 3-15 range, but for a full debugger domain each tool maps to a necessary operation. The set is comprehensive rather than padded, though it is on the heavy side.

    Completeness4/5

    The surface covers session management, launch/attach, execution control, breakpoints, stack/expression inspection, and crash dumps. Notable gaps remain around raw memory/register read-write and disassembly, which are common debugger needs but not strictly blocking for many workflows.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables step-through debugging for C#, Node.js/TypeScript, Python, and Dart applications on Windows through a unified MCP interface. Acts as a bridge between MCP clients and various debug adapters, providing consistent debugging workflows with breakpoints, variable inspection, and process attachment capabilities.
      8 npm
      ISC
    • A
      license
      A
      quality
      A
      maintenance
      Enables coding agents to connect to Debug Adapter Protocol debuggers over MCP, allowing them to launch or attach to native targets, control execution, set breakpoints and watchpoints, inspect stacks, variables, memory, and exceptions, and capture agent-friendly debugger snapshots.
      18
      1,216 npm
      3
      Apache 2.0
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables launching and controlling a debugpy debug session through MCP, including setting breakpoints, stepping, evaluating expressions, and observing debugger state and events.
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Enables any MCP client to debug programs through the Debug Adapter Protocol, supporting launch/attach, breakpoints, stepping, variable inspection, evaluation, and memory operations via a single debug tool.
      1
      13 npm
      MIT