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提取, 云安全监控, 代码导航, 代码理解, 元数据分析, 反编译, 多人体追踪, 属性查看, 方法签名, 程序集浏览器, 请求拦截, 调用图, 错误基检测, 静态代码分析, 静态分析