dnSpy MCP扩展
 
Chinese / 中文说明: see README.zh-CN.md.
特性
MCP工具(共15个)
分析与导航
- 列表_组件 --列出所有加载的程序集及其元数据
- get_assembly_info --特定程序集的详细信息(分页命名空间)
- list_types --程序集或命名空间中的所有类型(分页)
- get_type_info --类型的字段、属性和分页方法(方法包括
token/MDToken用于明确识别) - list_方法 --a类型的方法
token+parameter_types每个条目,分页 - get_type_fields --按通配符模式过滤字段(例如。
*Bonus*) - get_type_属性 --关于属性的详细信息,包括getter/setter
- 搜索类型 --跨所有程序集的通配符/子字符串类型搜索
- find_path_to_type --BFS通过字段/属性连接两种类型
- 反编译方法 --将方法反编译为C#(接受
parameter_types/method_token消除过载的歧义)
IL查看和编辑(0.1.3中的新功能)
- get_method_il --指令(索引、偏移、操作码、操作数)+本地值+异常处理程序+正文标志
- patch_method_il --订购
replace/insert/delete/set_init_locals编辑;第一个补丁上的快照 - revert_method_il --恢复贴片前的身体形状
- save_assembly --将模块写入磁盘(覆盖时带时间戳的备份,
NativeWrite保留本机存根/Win32资源/延迟加载导入,GAC拒绝)
代码生成
- generate_bepinex插件 --带有Harmony钩子的BepInEx插件模板
MCP资源(共6个)
嵌入式BepInEx文档已送达 resources/list / resources/read:
- 插件结构
- 和谐修补 (前缀/后缀/转译器)
- 配置
- 常见场景
- il2cpp指南
- 单乙烯基二氯乙烯基聚丙烯
所有文档都包含在DLL中,不需要网络。
IL查看和编辑
从AI客户端查看、修补和保存字节码。镜像dnSpy *编辑方法体* 对话。
运算符语法
每条指令的操作数都是一个带标签的字符串;使用相同的语法 get_method_il (阅读)和 patch_method_il (写入),因此操作数往返不变。
| 标签 | 示例 | 操作码 |
|---|---|---|
int: / int8: / uint8: / long: | int:42 | ldc.i4, ldc.i4.s, ldc.i8 |
float: / double: | double:3.14 | ldc.r4, ldc.r8 |
str: *(引用JSON)* | str:"hello\n" | ldstr |
method: *(dnlib全名)* | method:System.Void Ns.T::M(System.Int32) | call, callvirt, newobj, ldftn, ldvirtftn, jmp |
field: | field:System.Int32 Ns.T::F | ldfld, stfld, ldsfld, stsfld, ldflda, ldsflda |
type: | type:System.String | castclass, isinst, box, unbox, newarr, initobj, ldelem*, stelem*, … |
token:method:… / token:field:… / token:type:… | token:type:System.String | ldtoken |
label: | label:7 | br, brtrue.s, blt, … |
switch:[,,…] | switch:[3,7,12] | switch |
local: | local:0 | ldloc*, stloc* |
arg: | arg:1 | ldarg*, starg* |
| *(空)* | "" | 无操作数(ldarg.0, add, ret, …) |
calli / InlineSig 0.1.3中不支持。
端到端:修补一个常量并持久化
假设 TestIL.dll 包含 public static int AddOne(int x) => x + 1;.
# 1. Find the method (parameter_types disambiguates overloads).
curl -s -X POST http://localhost:3000/ -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":1,"method":"tools/call","params":{
"name":"list_methods",
"arguments":{"assembly_name":"TestIL","type_full_name":"TestIL.Simple"}}}'
# 2. Read the IL.
curl -s -X POST http://localhost:3000/ -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":1,"method":"tools/call","params":{
"name":"get_method_il",
"arguments":{"assembly_name":"TestIL","type_full_name":"TestIL.Simple","method_name":"AddOne"}}}'
# Instructions include: {"index":1,"opcode":"ldc.i4.1","operand":""}
# 3. Replace the +1 with +41.
curl -s -X POST http://localhost:3000/ -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":1,"method":"tools/call","params":{
"name":"patch_method_il",
"arguments":{"assembly_name":"TestIL","type_full_name":"TestIL.Simple","method_name":"AddOne",
"edits":[{"op":"replace","index":1,"opcode":"ldc.i4","operand":"int:41"}]}}}'
# 4. Save. Original file is backed up to
..bak first.
curl -s -X POST http://localhost:3000/ -H "Content-Type: application/json" -d '{
"jsonrpc":"2.0","id":1,"method":"tools/call","params":{
"name":"save_assembly",
"arguments":{"assembly_name":"TestIL"}}}'在新进程中重新加载保存的DLL,然后 AddOne(10) 回报 51 而不是 11.
注意事项
- 没有Ctrl+Z。
patch_method_il不通过dnSpy的撤消堆栈路由。使用revert_method_il--快照是在第一次修补给定方法时拍摄的,并在还原或成功保存后删除。 - dnSpy的内存视图在保存后不会刷新。 在dnSpy中重新打开程序集,查看运行实例中保存的状态。
- GAC路径被拒绝。 储蓄
mscorlib等等返回a-32602错误。 - 仅限于指令级别。 添加/删除本地值或异常处理程序超出了0.1.3的范围;
get_method_il以只读方式公开它们。
安装
推荐:一体式拉链
前往 发布 并下载与您的系统匹配的捆绑包-- 扩展已放置在内部,没有路径可供查找:
| 文件 | 内容 | 运行时间要求 |
|---|---|---|
dnSpy-MCP-win-x64.zip | dnSpy。NET 10自包含的x64+MCP扩展 | 无--运行时已捆绑 |
dnSpy-MCP-win-x86.zip | dnSpy。NET 10自包含的x86+MCP扩展 | 无--运行时捆绑在一起 |
dnSpy-MCP-net48.zip | dnSpy。NET Framework 4.8内部版本+MCP扩展 | 。NET Framework 4.8(Windows 10+上的默认设置) |
- 在任何地方下载并解压缩。
- 双击
dnSpy.exe. - 打开 Edit → 设置→ MCP服务器,勾选 启用服务器,单击“确定”。
就是这样。如果您已经使用dnSpy并且只想要插件,请参阅下面的“仅插件”。
仅限插件(适用于已安装dnSpy的用户)
- 下载与dnSpy运行时匹配的DLL:
- dnSpy.Extension.MCP-net48.dll — .NET框架4.8 dnSpy - dnSpy.Extension.MCP-net10.0-windows.dll — .NET 10 dnSpy
- 重命名为
dnSpy.Extension.MCP.x.dll(the.xdnSpy的扩展加载器需要后缀)。 - 创建文件夹
dnSpy.Extension.MCP在...之下\bin\Extensions\并将DLL放入其中。 - 重新启动dnSpy。
最后的路径必须完全像这样 --与DLL茎相同的文件夹名称, .x.dll 后缀存在,下一级 Extensions\:
\
└── bin\
└── Extensions\
└── dnSpy.Extension.MCP\ ← folder (create if missing)
└── dnSpy.Extension.MCP.x.dll ← DLL with the .x suffix安装dnSpy的具体示例 C:\Tools\dnSpy:
C:\Tools\dnSpy\bin\Extensions\dnSpy.Extension.MCP\dnSpy.Extension.MCP.x.dll如果DLL直接位于 bin\Extensions\ (无子文件夹),或没有 .x 后缀,dnSpy会自动跳过它,MCP服务器设置页面也不会出现。
来源
# Clone dnSpyEx (submodules are required)
git clone --recursive https://github.com/dnSpyEx/dnSpy.git
cd dnSpy
# Clone this extension into the Extensions directory
git clone https://github.com/KernelErr/dnSpy.Extension.MCP.git Extensions/dnSpy.Extension.MCP
# Build (both TFMs)
cd Extensions/dnSpy.Extension.MCP
dotnet build -c Release
# Deploy
cp bin/Release/net10.0-windows/dnSpy.Extension.MCP.x.dll \
/bin/Extensions/dnSpy.Extension.MCP/配置
设置在以下位置 Edit → 设置→ MCP服务器:
- 启用服务器 --当切换和应用时,立即启动/停止HTTP服务器。
- 港口 --首选TCP端口(默认
3000).如果端口已在使用中,服务器会自动尝试port + 1,最多20次尝试,并记录它实际绑定到的端口。检查服务器日志窗格中已解析的端口。 - 主机 --绑定地址(默认
localhost).
运输
所有三种运输方式都在同一条线上运行 HttpListener 服务器通过检查路径、HTTP方法和 Accept 每个请求的头部。
可流式HTTP(MCP 2025-03-26)
codex和其他现代MCP客户端使用的单端点传输。客户端POST JSON-RPC请求 Accept: application/json, text/event-stream;服务器将JSON-RPC响应内联返回为 application/json 并在上分配会话 initialize 通过 Mcp-Session-Id 响应标头。后续的POST必须回显该标头。服务器也荣誉 GET 在服务器启动的SSE的同一端点上,以及 DELETE 拆卸。
两者 / 和 /mcp 被接受为端点路径。
# 1. Initialize — server returns the session ID in the Mcp-Session-Id header.
curl -i -X POST http://localhost:3000/ \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
# HTTP/1.1 200 OK
# Mcp-Session-Id:
# Content-Type: application/json
# {"jsonrpc":"2.0","id":1,"result":{...}}
# 2. Subsequent calls echo the session header.
curl -X POST http://localhost:3000/ \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: " \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# 3. Tear down explicitly (optional — the server also drops the session on shutdown).
curl -X DELETE http://localhost:3000/ -H "Mcp-Session-Id: "法典 ~/.codex/config.toml:
[mcp_servers.dnspy-mcp]
type = "streamable-http"
url = "http://localhost:3000"普通HTTP JSON-RPC
一次性请求/响应——将JSON-RPC POST到 / 没有 text/event-stream 在 Accept 并从同一HTTP响应体中读取响应。适用于快速 curl 测试和仅使用纯HTTP的MCP客户端。
curl -s http://localhost:3000/health
# {"status":"ok","service":"dnSpy MCP Server"}
curl -s -X POST http://localhost:3000/ \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'服务器发送事件(MCP 2024-11-05)
保留了传统的两个端点传输,以与MCP Inspector和旧客户端向后兼容:一个长期的SSE流,以及一个用于客户端消息的POST端点。
GET /sse--打开text/event-stream.第一件事(event: endpoint)携带客户端应POST到的URL(/message?sessionId=).POST /message?sessionId=--接受JSON-RPC请求,返回202 Accepted,并将真实的JSON-RPC响应作为event: message.
# Terminal A: open the stream and keep it open
curl -N http://localhost:3000/sse
# event: endpoint
# data: /message?sessionId=
# ... (later, once POST arrives) ...
# event: message
# data: {"jsonrpc":"2.0","id":1,"result":...}
# Terminal B: send a request on that session
curl -X POST "http://localhost:3000/message?sessionId=" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
# HTTP 202 Accepted — the response appears on Terminal A's SSE stream客户端配置
克劳德代码
使用CLI注册服务器一次——它在以下位置获取Streamable HTTP传输 /:
claude mcp add --transport http dnspy http://localhost:3000
# verify:
claude mcp list或将其添加到已签入 .mcp.json 在项目根目录(范围到项目):
{
"mcpServers": {
"dnspy": {
"type": "http",
"url": "http://localhost:3000"
}
}
}跑 /mcp 内部克劳德代码确认 dnspy 已连接并列出其工具。
克劳德桌面版
{
"mcpServers": {
"dnspy": {
"command": "http",
"args": ["http://localhost:3000"]
}
}
}法典
请参阅上面的Streamable HTTP部分以了解 ~/.codex/config.toml 片段。
发展
# Single-TFM builds for fast iteration
dotnet build -c Debug -f net48
dotnet build -c Debug -f net10.0-windows项目布局
dnSpy.Extension.MCP/
├── .github/workflows/ GitHub Actions (build, release)
├── McpServer.cs HttpListener HTTP + SSE + Streamable HTTP + port fallback
├── McpProtocol.cs JSON-RPC 2.0 / MCP DTOs
├── McpTools.cs Analysis tools + MEF export + dispatch (sealed partial)
├── McpTools.IL.cs IL view/patch/revert/save + operand renderer & parser
├── McpSettings.cs Settings view-model + persistence + log (disk log in Debug only)
├── McpSettingsPage.cs IAppSettingsPageProvider for dnSpy settings dialog
├── BepInExResources.cs Embedded BepInEx docs (6 resources)
├── TheExtension.cs IExtension entry point; starts server on Loaded
├── tests/fixtures/ TestIL.cs + build-fixture.ps1 + run-tests.ps1 (E2E harness)
└── dnSpy.Extension.MCP.csproj建筑说明
- 目标:
net48和net10.0-windows(继承自DnSpyCommon.props). - 运输:单
HttpListenerKestrel在一个端口上提供普通HTTP JSON-RPC、2024-11-05 SSE和2025-03-26流式HTTP路径 不 已使用——dnSpy的自包含功能。NET捆绑包不附带ASP。NET Core,所以任何Microsoft.AspNetCore.*引用会导致沉默TypeLoadException在MEF组成和扩展过程中IExtension部分永远不会实例化。 - 陆战队远征部队:服务使用
[Export(typeof(T))]+[ImportingConstructor]不要new上McpServer/McpSettings/McpTools. - UI线程编组:中的每个工具处理程序
ExecuteTool在WPF调度程序上运行。IDocumentTreeView节点是DispatcherObjects,如果从HTTP worker读取,则抛出“调用线程无法访问此对象”,因此必须进行编组;已经采用调度器路径(补丁、恢复、保存)的处理程序无害地进行双重包装。 - 错误代码:
ArgumentException工具处理器内部→ JSON-RPC-32602(无效参数);任何其他例外情况→-32603(内部错误)。 - 日志记录:
McpSettings.Log(...)始终写入UI内日志窗格,以及D:\dnspy-mcp.log只有在 调试 建筑。发布版本将所有内容保存在内存中;不可写D:最终用户机器上需要驱动器。
协议
实现 主控程序 版本 2024-11-05 通过JSON-RPC 2.0。
支持的方法: initialize, ping, tools/list, tools/call, resources/list, resources/read,以及 notifications/*.
CI/发布
.github/workflows/build.yml--在每次推送/PR上构建两个TFM。.github/workflows/release.yml--构建发布DLL,并在标签推送时将其附加到GitHub发布中(v*.*.*).
git tag v1.0.0
git push origin v1.0.0技术细节
- 依赖项:
dnSpy.Contracts.DnSpy,dnSpy.Contracts.Logic,dnlib,System.Text.Json(包装上net48,在盒子上net10.0-windows). - BFS路径查找:
find_path_to_type对每种类型的字段和属性进行广度优先搜索。 - 反编译:通过以下方式使用dnSpy的默认反编译器(通常是C#)
IDecompilerService. - IL写作:
save_assembly电话((ModuleDefMD)module).NativeWrite(path, NativeModuleWriterOptions)用于从磁盘加载的模块(保留本机存根、Win32资源、延迟加载的导入、混合模式代码)以及module.Write(path, ModuleWriterOptions)对于新构建的模块。通过以下方式禁用内存映射I/OpeImage as dnlib.PE.IInternalPEImage在写入之前——内部IMmapDisabler在dnSpy.AsmEditor是内联的,以避免依赖AsmEditor。 - 交叉方法参考 在
patch_method_il操作数(method:,field:,type:)通过遍历每个加载的模块来解决FullName匹配,然后通过导入到目标模块中new Importer(module, ImporterOptions.TryToUseDefs).
故障排除
显示设置页面,但服务器从未启动
最常见的是MEF合成失败 IExtension 部分同时 IAppSettingsPageProvider (设置页面)组成良好。症状:MCP服务器页面存在,允许您切换启用服务器,但单击时不会发生任何事情,也不会出现任何日志。根本原因通常是缺少运行时依赖关系——请先检查磁盘上的回退日志,并确保部署了与dnSpy TFM匹配的DLL。
端口已在使用中
服务器自动回退到 port + 1 (最多20次尝试)。寻找 Port N is in use; falling back to M 在日志中,客户端应连接到回退端口。
构建错误
- 确保您克隆了dnSpyEx
--recursive(子模块必须初始化)。 - 跑
dotnet restore在dnSpyEx回购根目录中。 - 要求。NET 10 SDK(以前的dnSpy版本使用.NET 8;
DnSpyCommon.props是真理的源泉)。
许可证
与dnSpyEx相同-请参阅 dnSpyEx存储库.
