pedrosakuma/dotnet-assembly-mcp
GitHub: pedrosakuma/dotnet-assembly-mcp
一个静态分析.NET程序集的MCP服务器,以token高效的方式导航和反编译已编译二进制,解决AI代理理解代码结构而无需源代码的问题。
Stars: 0 | Forks: 0
# dotnet-assembly-mcp
一个用于 *静态* 导航已编译 .NET 程序集的 **MCP 服务器** —— 可分析类型、方法、特性、签名、IL 代码、交叉引用并按需反编译 —— 设计为 **token 高效的方案,用以替代将源代码输入 LLM 上下文**。
## 为什么需要它
当 AI 代理需要理解一个方法的功能时,默认做法是读取源文件。对于一个 1000 行的类,这大约需要 4000-8000 个 token,而其中大部分内容是无关的。
此服务器让代理能够**深入探究**:
```
load_assembly(path) → moduleVersionId + method count (~30 tokens)
get_method(mvid, token) → signature, attributes, IL size (~30 tokens)
get_method_il(mvid, token, format='raw') → raw IL hex, instruction count (~80 tokens)
get_method_il(mvid, token, format='scan') → outbound calls / fields / types (~150 tokens)
decompile_method(mvid, token) → C# body, hard-capped (~200–500 tokens)
find_callers(mvid, token) → reverse call graph (intra+cross) (~100 tokens)
get_method_source(mvid, token) → PDB file/lines + SourceLink URL (~40 tokens)
```
封闭泛型实例被作为一等公民处理:`get_method` / `find_callers` 接受 `genericTypeArguments`,因此代理获得的是 `int Echo(int)` 而非 `T Echo(T)`,而 `find_callers` 会将范围缩小到 `MethodSpec` 与请求的实例化匹配的调用方。如果生产者在调用方的模块中已经存在 `MethodSpec` 行,可以跳过字符串渲染步骤,直接提供 `methodSpecModuleVersionId` + `methodSpecMetadataToken` 作为快速路径;当两种形式都存在时,它们会相互交叉检查,不匹配则会返回 `generic_instantiation_mismatch`。参见 [`docs/handoff-contract.md §3.5`](./docs/handoff-contract.md#35-generic-instantiations)。
代理只需为实际需要查看的内容付费。
## 安装
有关完整指南(单文件二进制、systemd / launchd / Scheduled Task 监控器、Kubernetes 部署清单),请参阅 [`docs/consumer-install.md`](./docs/consumer-install.md)。
### 作为全局 `dotnet 工具`(stdio — 本地 MCP 客户端)
```
dotnet tool install -g dotnet-assembly-mcp
dotnet-assembly-mcp --stdio # speak MCP over STDIN/STDOUT
```
需要 .NET 10 运行时。日志输出到 STDERR,因此 STDOUT 保持为干净的 JSON-RPC 通道。
### 作为 Docker 镜像(HTTP — sidecar / 多客户端)
```
docker run --rm -p 8788:8080 \
-v /path/to/assemblies:/assemblies:ro \
ghcr.io/pedrosakuma/dotnet-assembly-mcp:latest
# MCP 端点: http://localhost:8788/mcp
# 健康检查: http://localhost:8788/health
```
或本地构建:`docker build -t dotnet-assembly-mcp:dev -f deploy/Dockerfile .`。
### 与 `dotnet-diagnostics-mcp` 联合使用(推荐,可选)
诊断服务器会发出 `MethodIdentity` / `TypeIdentity` 句柄。自
[`dotnet-diagnostics-mcp` #28](https://github.com/pedrosakuma/dotnet-diagnostics-mcp/issues/28),
诊断服务器已在本地解析 PDB,并将 `SourceLocation` 直接
附加到每个 CPU 采样热点标识上 —— 因此对于源代码树
在编辑器中打开的开发工作流,诊断服务器本身已足够。
将 **此** 服务器与诊断服务器配对使用,适用于您同时需要以下功能的场景:
- 被剥离的二进制文件 / NativeAOT(无 PDB,无内联源代码)。
- 您没有源代码的第三方程序集。
- 反编译(`decompile_method`)、反向交叉引用(`find_callers`、`find_type_references` 等)。
同时运行两者:
```
export ASSEMBLIES_DIR=/abs/path/to/your/published/binaries
docker compose -f deploy/docker-compose.yml up -d
# 诊断端点: http://localhost:8787/mcp
# 程序集端点: http://localhost:8788/mcp
```
相同的 `docker-compose.yml` 包含在
[`pedrosakuma/dotnet-diagnostics-mcp:deploy/docker-compose.yml`](https://github.com/pedrosakuma/dotnet-diagnostics-mcp/blob/main/deploy/docker-compose.yml)
中 —— 从任一检出目录启动它。在主机上设置 `MCP_BEARER_TOKEN`
以使用一个共享令牌来控制这两个服务器的访问。
## 验证发布版本
每个发布产物(NuGet 包、自包含二进制压缩包、GHCR
容器镜像)都附带一个由 [`actions/attest-build-provenance`](https://github.com/actions/attest-build-provenance)
生成的 **SLSA 构建来源证明**,
并通过 GitHub 的 OIDC 签发者由 Sigstore 签名。该证明证实
该产物是由 GitHub 托管的运行器在此仓库的特定提交上构建的 ——
无需单独安装证书,无需轮换密钥。
使用 GitHub CLI 进行验证:
```
# NuGet 包
gh attestation verify dotnet-assembly-mcp.0.18.0.nupkg \
--repo pedrosakuma/dotnet-assembly-mcp
# 自包含二进制 tarball / zip 文件
gh attestation verify dotnet-assembly-mcp-0.18.0-linux-x64.tar.gz \
--repo pedrosakuma/dotnet-assembly-mcp
# 容器镜像(attestation 与镜像一同发布至注册表)
gh attestation verify oci://ghcr.io/pedrosakuma/dotnet-assembly-mcp:0.18.0 \
--repo pedrosakuma/dotnet-assembly-mcp
```
验证通过即确认构建来自 `pedrosakuma/dotnet-assembly-mcp`
的预期提交和标签。
## 客户端配置
### Claude Desktop / Cursor / VS Code / Copilot CLI (stdio)
`mcp.json`(Claude Desktop: `~/Library/Application Support/Claude/claude_desktop_config.json`):
```
{
"mcpServers": {
"dotnet-assembly-mcp": {
"command": "dotnet-assembly-mcp",
"args": ["--stdio"]
}
}
}
```
如果该工具不在 `PATH` 中,请将 `command` 指向绝对路径(例如 `~/.dotnet/tools/dotnet-assembly-mcp`)。
### 可流式传输的 HTTP
```
{
"mcpServers": {
"dotnet-assembly-mcp": {
"url": "http://localhost:8788/mcp"
}
}
}
```
## 工具
所有工具共享相同的响应信封结构(`summary`、`data`、`hints`、`error`);`hints` 会提示建议的下一步工具,因此代理可以链式调用而无需重新发现 API。跨模块的交叉引用工具(`find_callers`、`find_type_references`、`find_member_references`、`find_string_references`、`find_attribute_targets`、`list_derived_types`)都使用相同的匹配约定:同模块的命中项通过元数据令牌匹配,跨模块的命中项通过 `(程序集简单名称,类型全名,成员签名)` 与子模块的 `TypeRef` / `MemberRef` 行进行匹配。
### 发现与加载
| 工具 | 用途 |
|---|---|
| `load_assembly` | 从磁盘加载 `.dll`/`.exe`(按 MVID 幂等) |
| `list_assemblies` | 列出当前已加载的模块 |
| `list_assembly_references` | 一个模块的出站 `AssemblyRef` 行 |
| `import_assembly_manifest` | 在配置的根目录下批量注册路径列表 |
### 类型与方法枚举(第一层)
| 工具 | 用途 |
|---|---|
| `list_types` | 分页 TypeDef 列表,可按命名空间 / 名称 / 种类筛选 |
| `get_type` | 将 `(mvid, token)` 解析为类型摘要(基类型、接口、种类) |
| `list_derived_types` | 遍历所有已加载模块的子类 **和** 接口实现者(`directOnly` / 可传递) |
| `list_members` | 枚举类型的字段 / 属性 / 事件 |
| `list_methods` | 分页 MethodDef 列表,可按声明类型筛选 |
| `find_method` | 通过名称/签名的正则表达式进行模块范围内的 MethodDef 搜索 |
| `list_attributes` | 模块 / 类型 / 方法 / 参数 / 字段 / 属性 / 事件上的自定义特性 |
### 单方法解析(第二层 / 第三层)
| 工具 | 用途 |
|---|---|
| `get_method` | 将 `(mvid, token)` 解析为方法摘要;接受 `genericTypeArguments` / `genericMethodArguments` 以获得封闭签名视图 |
| `get_method_il` | 方法的 IL 读取器,通过 `format` 分派:`raw`(十六进制 IL 字节 + 最大栈 + 计数)、`text`(ildasm 风格的文本转储,有上限且 LRU 缓存)、`scan`(结构化的出站引用 —— 调用、字段、类型、字符串) |
| `decompile_method` | 通过 ICSharpCode.Decompiler 获得的 C# 方法体(有硬上限,LRU 缓存) |
| `get_method_source` | PDB 解析的文件/行号以及 SourceLink URL(内嵌 PDB 或同目录下的 `.pdb`) |
### 反向交叉引用(第四层)
| 工具 | 用途 |
|---|---|
| `find_callers` | 每个 IL 调用了给定方法的方法;当提供 `genericMethodArguments` 时,会按实例化缩小范围 |
| `find_type_references` | 每个引用了 TypeDef 的位置(字段/参数/返回/局部类型 + `newobj` / `castclass` / `isinst` / `box` / `ldtoken` / 泛型参数) |
| `find_member_references` | 字段、属性或事件的入站交叉引用 —— 根据句柄前缀(`f:` / `p:` / `e:`)分派;`accessor` 将属性范围缩小到 getter/setter,将事件范围缩小到 add/remove/raise |
| `find_string_references` | 每个 IL 对给定字面量发出 `ldstr` 的方法(精确/包含/正则) |
| `find_attribute_targets` | 反向自定义特性索引:每个承载了给定特性的程序集/类型/方法/参数/字段/属性/事件 |
## 配套项目
与 [`pedrosakuma/dotnet-diagnostics-mcp`](https://github.com/pedrosakuma/dotnet-diagnostics-mcp) 在作用域上互补,后者对正在运行的 .NET 进程执行 **动态** 诊断(附加、EventPipe 采样、GC、异常)。两者共同形成一个闭环:
```
[dotnet-diagnostics-mcp] [dotnet-assembly-mcp]
────────────────────── ──────────────────────
list_dotnet_processes load_assembly
collect_cpu_sample ──┐ ┌─→ get_method
collect_exceptions │ │ get_method_il (format='scan')
│ │ decompile_method
▼ │ find_callers
(MethodIdentity)
```
交接契约 —— `MethodIdentity = (moduleVersionId, metadataToken)` 加上可选的 `genericTypeArguments`(§3.5)—— 位于 [`docs/handoff-contract.md`](./docs/handoff-contract.md),同时也作为 MCP 资源在 `assembly://contract/method-identity` 上提供。
### MCP 资源
除了工具接口,服务器还发布了一小组只读 **资源**,MCP 客户端可以订阅或直接获取。它们都不需要工具调用:
| URI | 内容 |
|---|---|
| `assembly://contract/method-identity` | [`docs/handoff-contract.md`](./docs/handoff-contract.md) 的完整文本 —— `MethodIdentity` 的生产者/消费者线协议。 |
| `assembly://manifest/loaded` | 当前每个已加载模块的 JSON 数组(`mvid`、`path`、`methodCount`)。是 `list_assemblies` 的镜像,不消耗工具调用额度。 |
| `assembly://manifest/loaded/{mvid}` | 按 MVID 获取单个模块的 JSON 对象。当 MVID 未加载时,返回类似 404 的空响应体。 |
支持资源订阅的客户端会在已加载模块集发生变化时收到通知(例如,在 `load_assembly` 之后或文件监视器重新加载后)。
## 它如何补充 SourceLink
此服务器 **不** 替代 SourceLink / TraceLog 源代码解析。它是当以下情况发生时代理所寻求的方案:
- 部署的二进制文件没有 PDB 或没有 SourceLink,
- 目标是第三方 NuGet 依赖项,
- 运行时是经过裁剪的 NativeAOT,运行时的元数据稀疏,
- 或者代理只想要一个结构概览,而不想拉取 8 KB 的源代码。
`get_method_source` 是第二次机会的源代码解析器:它读取磁盘上的 PDB(优先使用内嵌的可移植 PDB,然后是同目录下的 `.pdb`),因此当本地有可用 PDB 时,代理不需要单独获取 SourceLink。
## 构建块
- [`System.Reflection.Metadata`](https://learn.microsoft.com/dotnet/standard/metadata-and-self-describing-components) —— 仅读取元数据,从不使用 `Assembly.Load`
- [`ICSharpCode.Decompiler`](https://github.com/icsharpcode/ILSpy) —— ILSpy 使用的完整反编译引擎
- [`ModelContextProtocol`](https://github.com/modelcontextprotocol/csharp-sdk) C# SDK 1.3.0
## 许可证
MIT —— 参见 [`LICENSE`](./LICENSE)。
标签:AI 代理, Amass, C# 分析, dotnet 工具, IL 分析, MCP 协议, MCP 服务器, .NET 程序集, PDB 符号, SourceLink, token 效率, URL提取, 云安全监控, 代码导航, 代码理解, 元数据分析, 反编译, 多人体追踪, 属性查看, 方法签名, 程序集浏览器, 请求拦截, 调用图, 错误基检测, 静态代码分析, 静态分析