mcpField
R
RoselineMCP

RoselineMCP

本地服务
atypical-consulting.github.io开发工具62 周前更新

关于 RoselineMCP

RoselineMCP 是基于 Roslyn 的 MCP 服务,为 AI 编码 Agent 提供 C# 解决方案的结构化视图和定向编辑能力。它还能检查分析器诊断,并以预览优先的方式应用修复。

主要功能

  1. 01导航符号、引用和调用图
  2. 02查看类型层次与文件大纲
  3. 03编辑成员并重命名符号
  4. 04查找诊断并应用代码修复
  5. 05写入前预览更改

适用场景

  1. 01查找 C# 符号的调用方或实现
  2. 02跨解决方案重命名符号
  3. 03审查并修复分析器诊断
  4. 04无需通读整个文件即可检查代码结构

MCP 相关

通过 stdio 向 MCP 客户端提供基于 Roslyn 的 C# 导航、分析和编辑工具。写入操作需明确关闭预览模式。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库
安装包
nugetRoselineMCP3.2.1

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

RoselineMCP 横幅

RoselineMCP

通过 MCP 为 AI 编码 Agent 提供 Roslyn 代码智能。让 Claude、Cursor 和 Copilot 能够从语义层面查看你的 C# 解决方案——符号、引用、调用图、精准编辑——从而按结构导航,而不是反复阅读源代码。实测 token 数中位数减少 85% →

Atypical-Consulting - RoselineMCP 许可证:MIT .NET 10 星标 - RoselineMCP 复刻 - RoselineMCP

GitHub 标签 问题 - RoselineMCP GitHub 拉取请求 GitHub 最近提交

CI

NuGet Docker

文档与基准测试 节省的 token

📖 文档、工具参考与真实基准测试 →


目录

为什么选择 RoselineMCP

你的编码 Agent 不该为了修改一个方法而读取一个 700 行的文件。源代码占用了 Agent 的大部分令牌预算,因此最省成本的改进就是不再向它提供整个文件。

RoselineMCP 将 Roslyn 编译器平台封装为 MCP 服务。它不会把源代码倾倒给模型,而是准确回答结构性问题——此符号在哪里使用、哪些类型实现了此接口、谁调用了此方法、此文件的结构如何——并以精准方式编辑:只生成成员级差异,而不是重写整个文件。

在 RoselineMCP 自身的源代码上,只读导航工具每项任务返回的令牌数中位数减少了 85%(按大小加权汇总后为 93%),相比之下,读取对应文件需要更多令牌—— 诚实测量,也包括表现较弱的情况。

search_symbols 在 Program.cs 上的结果:2,093 个令牌 → 120 个(−94%)。Agent 能了解文件结构;你则无需通读整份文件。

快速开始

任何支持 dnx(.NET 对应 npx)的 MCP 客户端都能按需运行它,无需安装。 需要 .NET 10 SDK。

// claude_desktop_config.json  ·  .vscode/mcp.json  ·  ~/.cursor/mcp.json
{
  "mcpServers": {
    "roseline": { "command": "dnx", "args": ["RoselineMCP", "--yes"] }
  }
}

然后让你的 Agent “找出 OrderService.Checkout 的所有调用方”,或 “在整个解决方案中将 Foo 重命名为 Bar”。想使用固定版本的 NuGet 安装包或 Docker?请参阅 入门指南。

功能

  • 令牌高效的代码导航 -- 通过 Roslyn 获取符号、引用、调用关系图、类型层次结构和文件大纲,而非读取整个文件。每项任务的令牌数实测中位数减少 85%(按大小加权汇总后为 93%)-- 查看基准测试。
  • 精准代码编辑 -- 替换/添加/删除成员,或在整个解决方案中重命名符号,并输出统一差异,而非重写整个文件。默认仅预览。
  • 全面分析与自动修复 -- 分析整个解决方案的诊断问题(Roslyn + Roslynator),并提供自动修复和便于审查的补丁。
  • 默认只读 -- 七种导航工具以及诊断/补丁工具绝不会写入磁盘;三种写入工具需要显式设置 previewOnly: false。
  • 编译保护(可选) -- PostToolUse 钩子会在每次文件写入后检查编译器的判定,不只针对 RoselineMCP 自身的写入——详见下方的编译保护。
  • 兼容你的客户端 -- 支持 Claude Desktop、VS Code(Copilot / MCP)和 Cursor。可通过 dnx、NuGet 全局工具或 Docker 安装。
  • 诚实、可复现的基准测试 -- 可在自己的解决方案上运行:dotnet run --project RoselineMCP.TokenBenchmark -c Release。

技术栈

层级技术
运行时.NET 10.0
编译器平台Roslyn (Microsoft.CodeAnalysis) 5.6.0
分析器Roslynator 4.15.0
MCP SDKModelContextProtocol 2.2.0
差异引擎DiffPlex 1.9.0
构建系统MSBuild 18.8.2
托管Microsoft.Extensions.Hosting 10.0.10

上述版本与 RoselineMCP/RoselineMCP.csproj 保持同步——如果此表中的信息有出入,请以该文件为准。

入门指南

前置条件
  • NuGet 全局工具:.NET 10.0 SDK 或更高版本
  • Docker:Docker Desktop 或 Docker Engine
  • 从源代码构建:.NET 10.0 SDK + MSBuild(随 Visual Studio 或 .NET SDK 提供)
  • MCP 客户端:Claude Desktop 或任何兼容 MCP 的客户端
安装

Claude Desktop,一键安装: 从最新版本下载 RoselineMCP.mcpb 并打开—— Claude Desktop 会显示安装对话框,无需编辑配置。(它在底层通过 dnx 启动, 因此仍需安装 .NET 10 SDK。)想自己编辑配置,或使用其他客户端? 请使用以下选项之一。

选项 1 -- dnx(无需安装步骤) (推荐)

RoselineMCP 提供了 MCP 服务注册表清单,因此任何支持 dnx 启动器的 MCP 客户端 (.NET 对应于 npx 的工具——可按需解析并运行 NuGet 打包的工具,无需单独执行 dotnet tool install) 都能直接启动它。需要 .NET 10.0 SDK。

{
  "mcpServers": {
    "roseline": {
      "command": "dnx",
      "args": ["RoselineMCP", "--yes"]
    }
  }
}

将以下内容添加到 Claude Desktop 或 VS Code 的 MCP 配置中(各客户端的确切文件位置,请参阅下文的 MCP 客户端兼容性)。 dnx 会在首次使用时下载并缓存该工具,因此无需预先全局安装。


选项 2 -- NuGet 全局工具 (离线/固定版本安装)

需要 .NET 10.0 SDK 或更高版本。

dotnet tool install -g RoselineMCP

安装后,roseline-mcp 命令即可全局使用。

Claude Desktop 配置(NuGet 全局工具)

将以下内容添加到 Claude Desktop 配置文件(claude_desktop_config.json)中:

{
  "mcpServers": {
    "roseline": {
      "command": "roseline-mcp"
    }
  }
}

配置文件位置:

  • macOS:~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows:%APPDATA%\Claude\claude_desktop_config.json

选项 3 -- Docker

无需 SDK。适用于任何安装了 Docker 的平台。

docker run -i --rm phmatray/roseline-mcp:latest
Claude Desktop 配置(Docker)
{
  "mcpServers": {
    "roseline": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "phmatray/roseline-mcp:latest"
      ]
    }
  }
}

注意: stdio 传输需要 -i 标志。--rm 标志会在会话结束后删除容器。


选项 4 -- 从源代码构建

git clone https://github.com/Atypical-Consulting/RoselineMCP.git
cd RoselineMCP
dotnet build
dotnet test
Claude Desktop 配置(从源代码构建)
{
  "mcpServers": {
    "roseline": {
      "command": "dotnet",
      "args": ["run", "--project", "/path/to/RoselineMCP/RoselineMCP.csproj"]
    }
  }
}

MCP 客户端兼容性

RoselineMCP 使用标准的 stdio MCP,因此应该适用于任何兼容 MCP 的客户端。以下片段是有文档记录,但并未在所有情况下逐一独立验证的——我们已确认协议层面的行为(stdio 传输、工具发现、JSON 响应)正常工作,但没有亲自端到端测试每个客户端自身的配置界面或文件。如果以下配置对你的客户端版本不起作用,请提交 issue。

Claude Desktop

编辑 claude_desktop_config.json(文件位置见上文安装部分),并在 mcpServers 下添加一个 roseline 条目,使用上文所示的四种安装选项之一(dnx、全局工具、Docker 或从源代码构建)。

VS Code(GitHub Copilot / MCP 扩展)

在工作区或用户的 mcp.json 中添加一个条目(命令面板 → “MCP: Open User Configuration”,或工作区中的 .vscode/mcp.json):

{
  "servers": {
    "roseline": {
      "command": "dnx",
      "args": ["RoselineMCP", "--yes"]
    }
  }
}

如果通过 NuGet 全局工具安装,请将 "command": "roseline-mcp"(不带 args)替换进去。

Cursor

在 ~/.cursor/mcp.json(全局)或 .cursor/mcp.json(项目本地)中添加一个 roseline 条目, 使用与上文 VS Code 代码片段相同的 command/args 格式。

可用工具

每个工具的描述——即 MCP 客户端在工具选择时向模型展示的文本——都会说明自身的 Limitations:,并提供一个 Example: 调用,且字数不超过测试强制执行的上限;十三个带有可选 project 参数的工具共用下文所述的一种工作树注意事项表述,而 resolvedPath 可用于确认实际响应的是哪个检出目录。请参阅 docs/API.md § 工具描述约定。

1. AnalyzeSolution

分析整个 C# 解决方案中的诊断。只读——绝不修改磁盘上的文件。 pathOrGit 也接受 http(s):// Git URL:系统会将其浅克隆到临时目录中, 分析后再删除。

analyzeSolution({
  pathOrGit: "/path/to/solution.sln",
  include: "Core",              // Optional: only project names containing this substring
  exclude: "Test",              // Optional: skip project names containing this substring
  severity: "warning",          // Optional: minimum severity (Error|Warning|Info|Hidden)
  maxDiagnostics: 100           // Optional: Maximum diagnostics to return (default: 100)
})

**返回:**解决方案文件名、项目数、diagnosticSummary(按严重性统计的数量)、包含每条诊断的项目/文件/行/列/ID/严重性/消息的 topDiagnostics 数组,以及 analyzerLoad——仅当某个分析器引用加载失败或加载后未包含任何 C# 分析器时才会出现(合并统计所有已分析项目):失败项会列出名称和原因,无问题项则只计数(referencesWithoutAnalyzers)。

2. ListDiagnostics

获取特定项目的详细诊断信息。只读——绝不修改磁盘上的文件。 project 可选,接受与导航工具相同的引用形式(名称、 目录、.csproj、.sln 或 .slnx 路径);省略时,会根据工作目录自动发现解决方案/项目。

listDiagnostics({
  project: "MyProject.csproj",     // Optional: name, directory, .csproj, .sln, or .slnx; auto-discovered if omitted
  ids: ["CS0168", "CS0219"],       // Optional: Filter by diagnostic IDs
  files: ["Controller.cs"],        // Optional: substring match against each diagnostic's file path (case-insensitive; NOT a glob pattern)
  max: 50                          // Optional: Maximum results
})

返回:项目名称、resolvedPath(实际加载的 .sln/.csproj 的绝对路径)、 totalDiagnostics 诊断总数、筛选后的 diagnostics 列表、stats(按 ID 和 严重性分组的计数)、suggestedFixableIds——已实际注册代码修复提供程序的诊断 ID,无论该提供程序来自 Roslyn、随附的 Roslynator 目录,还是项目自己的某个分析器引用——以及 analyzerLoad,其中会列出每个加载失败的分析器引用(及原因),包括其代码修复器加载失败的引用;此外还会显示不含 C# 分析器的引用数量。仅在有相关信息时才会出现。

3. ApplyFixes

对指定诊断应用自动代码修复。默认处于预览模式: previewOnly 默认为 true,因此调用此工具而不设置该参数绝不会写入磁盘——必须显式传入 previewOnly: false 才会应用更改。project 可选,接受与导航工具相同的引用形式(名称、目录、.csproj、.sln 或 .slnx 路径); 省略时,会根据工作目录自动发现解决方案/项目。执行写入 (previewOnly: false)时,请使用绝对路径——参见下方的工作树说明。

applyFixes({
  ids: ["CS0168", "RCS1001"],   // Diagnostic IDs to fix
  project: "/repo/src/MyProject/MyProject.csproj",  // Optional; absolute for a write (see the worktree note)
  previewOnly: false             // Optional (default: true). Set false to write changes to disk.
})

**返回:**项目名称、resolvedPath(实际加载的 .sln/.csproj 的绝对路径)、 fixedCount、fixersApplied(实际修复的诊断 ID)、changedFiles (相对于 resolvedPath 所在目录的路径,使用正斜杠——与导航工具采用相同的路径基准)、统一 差异 patch、notes(范围——修复了哪个项目、解决方案中哪些项目未分析,以及写入任何链接文件是否会影响同级项目——还有跳过/失败的 ID 和状态消息)、回显调用方请求值的 previewOnly、applied(是否有任何更改实际写入磁盘)、verification(编译器对修复后代码的判定)以及 analyzerLoad(仅当某个引用加载失败或加载后未包含分析器时才会出现,以便区分“未发现 X 的诊断”和“报告 X 的分析器从未加载”,以及“没有修复器”和“修复器无法加载”)。修复器的查找顺序为 Roslyn 内置项、随附的 Roslynator 目录,然后是项目自己的分析器引用;如果两者都提供同一 ID 的修复器,则优先使用随附的提供程序。

以 .sln 为目标时,只会修复一个项目——其主项目;这一范围会在写入路径上强制执行,而不只是通过确认提示告知:只会验证并写入锚定项目的文档;即使调用方看不到提示(预览模式、不支持交互的客户端、无人值守的主机),也仍可通过 notes 查看哪些项目被跳过。传入 .csproj 可修复指定项目——此时不会报告任何跳过的项目,因为这正是请求的范围。

14. CheckCompilation

针对磁盘上的当前状态回答 “现在能否编译,以及哪里出了问题”——替代 Agent 编辑循环中的 dotnet build 往返操作。此工具只读,且只检查编译器诊断:分析器的开销是单纯编译的数倍,因此本工具的速度足以在每次编辑后运行。

无论代码由谁编写,它都会检查磁盘上的内容,因此同样适用于其他工具所做的编辑。它的速度来自服务已持有的热 MSBuildWorkspace:会话的首次调用需要冷加载,此后的每次调用都会复用增量 Roslyn 编译。

checkCompilation({
  project: "MyApp.sln",  // Optional: name, directory, .csproj, .sln, or .slnx; auto-discovered if omitted
  max: 20                 // Optional (default: 20). The rest are counted in `omitted`.
})

返回值: resolvedPath、compiles、errors(编译成功时省略)、omitted、scope(已编译的项目)、scopeComplete 和 notes。

check_compilation 与 list_diagnostics: check_compilation 回答 “它还能通过编译吗?”——快速检查编译器错误,适用于编辑循环。list_diagnostics 回答 “我应该清理哪些问题?”——提供分析器诊断、统计信息,以及哪些 ID 可以自动修复。编辑后使用前者,探索代码时使用后者。

15. SuggestFixExamples

对于无法通过代码修复程序修复的诊断,此工具会返回 关键示例:同一解决方案中,语法和符号结构相同但不会触发该诊断的位置,以及规则说明和帮助链接。此工具只读,并且有意不纳入编译验证流程:它不会提出修改方案,由 Agent 编写编辑内容,而 edit_member/apply_fixes 仍会验证修改。

suggestFixExamples({
  id: "CS0121",           // Required: the diagnostic ID
  project: "MyApp.sln",   // Optional: auto-discovered if omitted
  file: "Foo.cs",         // Optional: anchor on one occurrence (with line)
  line: 42,
  maxExamples: 3,         // Optional (default: 3)
  maxCandidates: 2000     // Optional (default: 2000)
})

返回值: resolvedPath、rule、hasFixer、alert(未触发该 ID 时不存在)、examples、candidatesScanned、truncated 和 notes。

4. CreatePatch

生成两个文本版本之间的统一差异。此工具只读——仅处理提供的字符串,不会触碰文件系统。

createPatch({
  before: "original code",
  after: "modified code",
  fileName: "Example.cs",        // Optional: For display in diff
  ignoreWhitespace: false,       // Optional: ignore whitespace-only differences
  ignoreCase: false              // Optional: ignore case differences
})

返回值: 统一差异 patch、hasChanges、linesAdded、linesRemoved,以及差异标头中使用的 fileName/summary。

代码导航工具(只读)

这些工具返回精确的结构,而非完整文件,让 AI Agent 能够熟悉代码库,同时比直接阅读源代码消耗少得多的 Token。所有工具均为只读,并接受一个可选的 project(名称、目录、.csproj 路径、.sln 或 .slnx 路径)——未提供时,RoselineMCP 会从其工作目录自动发现解决方案/项目。如果项目属于某个解决方案,则会加载整个解决方案,并在其中的每个项目(包括所请求项目未引用的同级项目)中搜索/解析符号,因此引用/重命名会跨项目进行。完整的请求/响应格式见 docs/API.md。

在 git worktree 中工作? 自动发现以服务端的工作目录为基准——也就是 MCP 客户端启动 RoselineMCP 时所在的目录,该目录在进程生命周期内固定不变,而不是你所在的目录。重要的只是两者不同,无论是你切换到了另一个检出目录,还是服务端启动时就在另一个检出目录中:worktree(例如 .claude/worktrees/<name>)位于发现遍历范围之外,因此省略 project 时会解析到主检出目录。所有接受可选 project 的工具——七个导航工具、两个编辑工具、listDiagnostics 和 applyFixes——都会返回 resolvedPath,即实际处理请求的 .sln/.csproj 绝对路径:如果加载了包含该项目的解决方案,则返回 .sln;否则返回直接打开的 .csproj(例如,未列在最近的上级 .sln 中的项目)。请检查该值,并传入绝对路径作为 project,以指定特定检出目录。(analyzeSolution 是例外:它必须提供 pathOrGit,因此不会自动发现任何内容。)

具体表现取决于你是在读取还是写入。 如果要读取的内容在另一个检出目录中不存在,会返回 NotFoundError: Symbol not found: 'X';如果存在,则会成功读取,但 resolvedPath 可能与你预期的不符。无论哪种情况,失败响应中的 error.resolvedPath 都会标明搜索的是哪个检出目录(如果调用在解析出任何内容前就失败,则完全不包含该字段),因此可以区分“那里没有”和“检出目录不对”。

写入则不能任其发生:同一仓库的两个检出目录大多包含相同的代码,因此在错误的检出目录中写入会正常解析、应用并返回成功,但修改的是你原本不打算修改的目录——只有在已经更改文件的那次调用返回时,你才会发现这一点。因此,当解析出的检出目录属于包含关联 worktree 的仓库时,若调用 applyFixes、editMember 或 renameSymbol 时设置了 previewOnly: false,且 project 不是绝对路径——省略、空白、"."、不带路径的项目名称、相对路径 "App.sln"——则会直接拒绝(ValidationError,不会写入,也不会提示确认),不受 RoselineMCP:ConfirmDestructiveWrites 影响。只有传入绝对路径的 project 才能解除拒绝,因为只有绝对路径能指定检出目录:其他任何写法都会相对于服务端的工作目录解析,而你无法确定的恰恰就是这个目录。请参阅 docs/API.md。

相对文件路径以 resolvedPath 为基准。 导航工具返回的 file/definitionFile、applyFixes/editMember/renameSymbol 返回的 changedFiles 和补丁标头,以及 verification.errors[]/checkCompilation 的 errors[] 中的 file,都是相对于 resolvedPath 所在目录的——因此,dirname(resolvedPath) + <returned path> 就是实际文件路径,且返回的 patch 可从该目录应用(git apply -p1)。通常该目录就是解决方案根目录;如果直接打开的是 .csproj,则是项目自身的目录——包括未列在最近的上级 .sln 中的项目。一个例外:listDiagnostics/analyzeSolution 返回的 file 是绝对路径,无需拼接。请参阅 docs/API.md。

MCP 调用中使用的工具名称为 snake_case。 为便于阅读,以下各节标题使用易读的 PascalCase/camelCase,但 tools/list 返回(且 tools/call 需要)的实际 MCP 工具名称为:search_symbols、get_symbol_info、find_references、find_implementations、get_call_graph、get_type_hierarchy、get_symbol_at_position、edit_member、rename_symbol(与现有的 analyze_solution / list_diagnostics / apply_fixes / check_compilation / create_patch 保持一致)。

5. SearchSymbols

按通配符/子串名称模式查找符号,或列出单个文件的大纲。

searchSymbols({
  project: "MyApp.Core",
  query: "*Service",             // Substring, or wildcard with * and ? — omit to outline a file
  file: "UserService.cs",        // Optional: restrict to one file, or outline it when query omitted
  kinds: ["class", "method"],    // Optional: filter by kind (also accepts "type" / "member")
  max: 50                        // Optional (default: 50)
})

返回: symbols(name、fullName、kind、signature、file、line — file 相对于 resolvedPath 所在目录;单文件大纲则返回 name、kind、signature、line、containingType)、totalFound、truncated(未达到上限时省略)。

6. GetSymbolInfo

精简版“转到定义”:符号的声明元数据,以及(可选)其源代码。

getSymbolInfo({
  project: "MyApp.Core",
  symbol: "Acme.Users.UserService.GetUser",  // Simple or fully-qualified name
  includeSource: true                          // Optional (default: true)
})

返回: name、fullName、kind、signature,以及(为空或不存在时各自省略)modifiers、baseTypes、interfaces、documentation、definitionFile/Line 和 source。可访问性已包含在 signature 中;definitionFile 相对于 resolvedPath 所在目录。

7. FindReferences

符号在整个解决方案中的每个使用位置,以位置和单行代码片段的形式返回。

findReferences({ project: "MyApp.Core", symbol: "GetUser", includeDefinition: false, max: 100 })

返回: references(file — 相对于 resolvedPath 所在目录、line、snippet)、totalReferences、truncated(未达到上限时省略)。

8. FindImplementations

接口/成员的实现、虚拟/抽象成员的重写,或类的派生类型。

findImplementations({ project: "MyApp.Core", symbol: "IRepository", max: 100 })

返回: implementations(符号摘要)、totalFound、truncated。

9. GetCallGraph

针对方法、带深度限制并进行循环检测的调用方和/或被调用方图。

getCallGraph({
  project: "MyApp.Core",
  method: "Handle",
  direction: "callers",   // "callers" (default) | "callees" | "both"
  depth: 1,               // 1-3 (default: 1)
  max: 50                 // Optional: nodes expanded per direction
})

返回: callers/callees 节点树(fullName,使用简单参数类型名称;file — 相对于 resolvedPath 所在目录;line、truncated、children)。调用 GetSymbolInfo 可获取节点的完整签名。

10. GetTypeHierarchy

类型的基类链、实现的接口和/或派生类型。

getTypeHierarchy({
  project: "MyApp.Core",
  type: "SqlRepository",
  direction: "both",   // "base" | "derived" | "both" (default)
  max: 100             // Optional: maximum derived types returned (default: 100)
})

返回: baseTypes、interfaces、derivedTypes(以符号摘要形式返回)。

13. GetSymbolAtPosition

位于 file:line(:column) 位置的符号 — 无需读取文件,即可将诊断信息、堆栈跟踪或 grep 命中项转换为符号名称。

getSymbolAtPosition({
  project: "MyApp.Core",
  file: "UserService.cs",  // File name or path suffix (same matching as SearchSymbols)
  line: 42,                // 1-based
  column: 17               // Optional (1-based) — omit to resolve the most relevant symbol on the line
})

返回: name、fullName、kind、signature、isDeclaration(该位置是否位于符号自身的声明上),以及(为空或不存在时各自省略)containingType、documentation、definitionFile/Line(相对于 resolvedPath 所在目录)。仅指定行的查询优先返回该行上的声明,而非被引用的符号。

代码编辑工具(默认预览)

对成员进行精确编辑,生成成员级变更,而非重写整个文件。与 ApplyFixes 一样,两者都默认使用预览模式(previewOnly: true)— 除非明确传入 previewOnly: false,否则不会写入磁盘。

11. EditMember

替换、添加或删除单个类型成员;返回统一差异。

editMember({
  project: "/repo/src/MyApp.Core/MyApp.Core.csproj",
  symbol: "Acme.UserService.GetUser",  // The member (replace/delete), or the container type (add)
  operation: "replace",                 // "replace" | "add" | "delete"
  newSource: "public User GetUser(int id) => _repo.Find(id);",  // Required for replace/add
  previewOnly: false                    // Optional (default: true). Set false to write to disk.
})

返回: operation、target、changedFiles、patch、previewOnly、applied、notes。

12. RenameSymbol

重命名符号并更新整个解决方案中的所有引用(Roslyn 重命名);返回统一差异。

renameSymbol({ project: "/repo/src/MyApp.Core/MyApp.Core.csproj", symbol: "GetUser", newName: "GetUserById", previewOnly: false })

返回: symbol、newName、changedFiles、patch、previewOnly、applied、verification、notes。

每次写入都会经过编译验证。 在 edit_member、rename_symbol 或 apply_fixes 修改磁盘前,候选变更会先在内存中编译。如果变更引入编译器错误 — 包括你从未指定的下游项目中的错误 — 则会拒绝写入:调用仍会成功,applied 返回 false,不会写入任何内容,并会返回差异和错误。传入 allowIntroducedErrors: true 可强制写入。已存在问题的代码仓库仍可编辑:门槛检查的是变更引入了什么,而不是整个代码树能否编译。有关检查范围规则和保证边界,请参阅编译验证。

工具注解

RoselineMCP 的 SDK(ModelContextProtocol 2.2.0)支持标准 MCP 工具 注解提示(readOnlyHint、destructiveHint、 idempotentHint),并且每个工具都会通过 [McpServerTool(ReadOnly = ..., Destructive = ..., Idempotent = ...)] 声明这些提示:

工具readOnlyHintdestructiveHintidempotentHint备注
AnalyzeSolution✅ true❌ false✅ true从不写入磁盘。
ListDiagnostics✅ true❌ false✅ true从不写入磁盘。
ApplyFixes❌ false⚠️ true❌ falsedestructiveHint 是静态的最坏情况注解:它为 true,因为传入 previewOnly: false 时,该工具可以写入文件,但默认调用(未设置 previewOnly,即 true)不会写入任何内容。SDK 的注解模型无法表达“仅在特定参数值下具有破坏性”——请参阅源码中 ApplyFixesTool.ApplyFixes 的文档注释。
CheckCompilation✅ true❌ false✅ true从不写入磁盘。编译已加载的解决方案并报告编译器的判定结果。
SuggestFixExamples✅ true❌ false✅ true从不写入磁盘。
CreatePatch✅ true❌ false✅ true仅处理提供的两个字符串;从不接触文件系统。
SearchSymbols✅ true❌ false✅ true从不写入磁盘。
GetSymbolInfo✅ true❌ false✅ true从不写入磁盘。
FindReferences✅ true❌ false✅ true从不写入磁盘。
FindImplementations✅ true❌ false✅ true从不写入磁盘。
GetCallGraph✅ true❌ false✅ true从不写入磁盘。
GetTypeHierarchy✅ true❌ false✅ true从不写入磁盘。
GetSymbolAtPosition✅ true❌ false✅ true从不写入磁盘。
EditMember❌ false⚠️ true❌ falsedestructiveHint 的最坏情况说明与 ApplyFixes 相同:仅在传入 previewOnly: false 时写入文件;默认调用不会写入任何内容。
RenameSymbol❌ false⚠️ true❌ falsedestructiveHint 的最坏情况说明与 ApplyFixes 相同:仅在传入 previewOnly: false 时写入文件;默认调用不会写入任何内容。

这些提示是 MCP 客户端可读取的静态工具元数据(例如,在 Agent 调用破坏性工具前向用户发出警告)——它们描述的是工具的最坏情况行为,而非任何特定调用的结果。关于这些注解所依托的工具名称和参数的稳定性保证,请参阅下文的工具兼容性政策。

工具兼容性政策

  • 在同一主版本内,工具名称和必需参数保持稳定。 基于 1.x 版本的 AnalyzeSolution(pathOrGit, ...) 编写的 MCP 客户端集成,在所有 1.x 版本中都能继续使用。
  • 次要版本中可以添加可选参数(例如,CreatePatch 新增了可选且有默认值的 ignoreWhitespace/ignoreCase 参数,不会影响现有调用方)。
  • 重命名或移除参数、更改参数的必需/可选状态,或更改工具名称,均属于破坏性变更。 破坏性变更会在 CHANGELOG.md 的专门“破坏性变更”标题下说明,且只会随主版本号升级发布。
  • 响应的结构(JSON 字段名称/类型)记录在 docs/API.md 中,并遵循相同政策:新增字段不属于破坏性变更,重命名或移除字段则属于破坏性变更。

支持的分析器

诊断工具(analyze_solution、list_diagnostics、apply_fixes)会报告编译器诊断和分析器诊断,并通过 Roslyn 的 CompilationWithAnalyzers 执行(check_compilation 特意不在此列表中——它仅检查编译器,因此速度足以用于编辑循环):

  • Roslyn Analyzers —— 内置的 C# 编译器诊断
  • Roslynator —— 500 多个 C# 分析器和修复,随 RoselineMCP 一同打包(作为与 RoselineMCP.dll 同级的 analyzers/ 文件夹提供),并默认执行,因此 RCS* 诊断会直接显示并可修复
  • 自定义分析器 —— 分析器所针对的解决方案引用的任何基于 Roslyn 的分析器,都会从项目的分析器引用中加载,并与打包的分析器一同运行(没有内置的 StyleCop.Analyzers 引用——如果需要 SA* 诊断,请将其添加到所分析的解决方案中)。其代码修复器也会加载:当 Roslyn、打包的目录或项目自身的分析器引用中包含匹配的修复器时,分析器报告的规则就可以自动修复(同一 ID 两处都有时,以打包版本为准)。

无法加载的内容都会明确列出。 如果 Roslyn 无法加载某个分析器引用,例如该引用是针对比 RoselineMCP 更新的 Microsoft.CodeAnalysis 构建的,或文件已损坏,Roslyn 会让它贡献 零个 分析器,而不是直接失败。三个诊断响应都包含一个 analyzerLoad 区块(analyzersRan、referencesConsulted、referencesContributing、referencesWithoutAnalyzers——已成功加载但未声明 C# 分析器的引用,只计数而不列出名称——analyzersLoaded,以及每个加载失败引用对应的 notes[] 条目:其名称、失败原因——load-failure,包含 Roslyn 的 errorCode 和消息;unresolved(程序集不在磁盘上,因此在 Roslyn 因此报错之前已将其从已加载的解决方案中移除);exception;或在 list_diagnostics 和 apply_fixes 中出现的 fixer-load-failure(无法加载其代码修复器))。如果所有引用都做出了贡献且没有失败,则省略此区块;因此只要该区块出现,就一定包含信息;参见 docs/API.md。

将 RoselineMCP:RunAnalyzers 设为 false,即可仅获取编译器诊断(大型解决方案中速度更快;参见配置和 SECURITY.md 中关于分析器执行的说明)。此时仍会显示该区块,其中 analyzersRan: false,以便区分“已关闭”和“一切正常”。

示例

分析解决方案
# Using with an MCP client
mcp call analyzeSolution '{
  "pathOrGit": "/Users/dev/MyProject/MyProject.sln",
  "severity": "warning",
  "maxDiagnostics": 50
}'

响应:

{
  "solution": "MyProject.sln",
  "projects": 5,
  "diagnosticSummary": {
    "error": 2,
    "warning": 15,
    "info": 28
  },
  "topDiagnostics": [
    {
      "id": "CS0168",
      "severity": "warning",
      "message": "The variable 'ex' is declared but never used",
      "file": "Program.cs",
      "line": 42
    }
  ]
}
应用修复
mcp call applyFixes '{
  "project": "MyProject.Core.csproj",
  "ids": ["CS0168", "RCS1001"],
  "previewOnly": true
}'

响应中包含一个统一差异补丁,展示将要应用的所有更改。

配置

RoselineMCP 会从服务二进制文件的安装目录(AppContext.BaseDirectory)读取 appsettings.json 和 appsettings.{Environment}.json,而不是从进程工作目录读取。从目标仓库内部启动服务时,不会读取该仓库自己的 appsettings.json;而随 dotnet tool 安装打包的设置始终可以找到。配置只在启动时读取;不会监视文件变化并重新加载。

环境变量

以 ROSELINE_ 为前缀的环境变量会覆盖 JSON 文件,并使用 __ 作为节分隔符。因此,RoselineMCP 节下的设置需要添加双重前缀:

# RoselineMCP:EnableDiagnosticLogging
ROSELINE_RoselineMCP__EnableDiagnosticLogging=true

# RoselineMCP:DefaultTimeout (ms)
ROSELINE_RoselineMCP__DefaultTimeout=300000

# RoselineMCP:RunAnalyzers (compiler-only diagnostics when false)
ROSELINE_RoselineMCP__RunAnalyzers=false

# RoselineMCP:ConfirmDestructiveWrites (no elicitation before writes; unattended hosts)
ROSELINE_RoselineMCP__ConfirmDestructiveWrites=false

# RoselineMCP:ConfirmDestructiveWritesTimeout (ms to wait for that confirmation; 0 = forever)
ROSELINE_RoselineMCP__ConfirmDestructiveWritesTimeout=300000

# Logging:LogLevel:RoselineMCP
ROSELINE_Logging__LogLevel__RoselineMCP=Debug
  • DOTNET_ENVIRONMENT:设置环境(Development、Production)
appsettings.json

配置日志记录和其他设置:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "RoselineMCP": "Debug"
    }
  },
  "RoselineMCP": {
    "DefaultTimeout": 120000,
    "EnableDiagnosticLogging": false,
    "WorkspaceCache": true,
    "RunAnalyzers": true,
    "ConfirmDestructiveWrites": true,
    "ConfirmDestructiveWritesTimeout": 300000
  }
}
  • RoselineMCP:DefaultTimeout:应用于每次工具调用的墙钟时间分析预算(毫秒),此外还受调用方自身的取消机制限制。0 表示禁用。对于这三个写入工具,它不涵盖整个调用:触发写入确认后,只有在用户回答后计时才会开始,因此思考时间计入 ConfirmDestructiveWritesTimeout。请根据分析所需时间设置,而不是调用方观察到的整个时长。
  • RoselineMCP:EnableDiagnosticLogging:选择启用的本地工具调用跟踪——参见调试日志。默认禁用;在 appsettings.Development.json 中启用。
  • RoselineMCP:WorkspaceCache:在导航/编辑工具调用之间复用已加载的 MSBuild 工作区(默认启用)——参见性能。设为 false 可在每次调用时加载新的工作区。这是隔离/调试开关,不是节省内存的开关——经测量,禁用后常驻内存增加约 26%,第二次调用延迟增加约 45 倍;参见内存管理。
  • RoselineMCP:RunAnalyzers:在诊断工具中运行 Roslyn 分析器(捆绑的 Roslynator 和目标项目自身的分析器引用)(默认启用)——参见支持的分析器。设为 false 可仅运行编译器诊断。
  • RoselineMCP:ConfirmDestructiveWrites:当调用方传入 previewOnly: false 时,在写入工具实际写入前请求客户端确认(通过 MCP elicitation)(默认启用)。对于无人值守的主机——CI、无头 Agent,或任何无法响应 elicitation 的客户端——设为 false。此时,显式传入 previewOnly: false 是写入前唯一的保护措施。
  • RoselineMCP:ConfirmDestructiveWritesTimeout:等待该确认的时长(毫秒);超时后将沉默视为“否”,并返回预览(默认 300000,即 5 分钟)。它有意不使用 DefaultTimeout——后者是分析预算,而用户查看实际差异时可能合理地超过该时限。客户端接受提示词却始终不作答,过去会导致工具调用永久阻塞;将此值设为 0 或更小可恢复不设上限的等待。

架构

RoselineMCP 使用 stdio 传输——这是有意为之的设计决策。服务器作为本地进程运行,由 MCP 客户端(Claude Desktop、AI Agent)启动,通过 stdin/stdout 通信,并在客户端断开连接时退出(写入确认待处理期间除外,此时服务器会继续运行,直至 ConfirmDestructiveWritesTimeout 到期;若该值为 0,则会一直运行——参见 docs/ARCHITECTURE.md)。这使其非常适合通过 NuGet 全局工具(dotnet tool install -g RoselineMCP)或 Docker 镜像分发——无需绑定端口、无需 HTTP 服务器,也无需管理基础设施。

┌─────────────────────┐
│   MCP Client        │
│  (Claude Desktop,   │
│   AI Assistants)    │
└────────┬────────────┘
         │ MCP Protocol (stdio)
         ▼
┌─────────────────────┐
│   RoselineMCP       │
│   MCP Server        │
│                     │
│  ┌───────────────┐  │
│  │  Tool Layer   │  │
│  │  (Analyze,    │  │
│  │   Fix, Patch) │  │
│  └───────┬───────┘  │
│          ▼          │
│  ┌───────────────┐  │
│  │ Service Layer │  │
│  │ (Workspace,   │  │
│  │  Diagnostics) │  │
│  └───────┬───────┘  │
│          ▼          │
│  ┌───────────────┐  │
│  │ Roslyn +      │  │
│  │ Roslynator    │  │
│  │ Analyzers     │  │
│  └───────────────┘  │
└─────────────────────┘
         │
         ▼
┌─────────────────────┐
│  C# Source Code     │
│  (.sln / .csproj)   │
└─────────────────────┘

项目结构

RoselineMCP/
├── RoselineMCP/
│   ├── Interfaces/       # Service interfaces
│   ├── Services/         # Core business logic
│   ├── Tools/            # MCP tool implementations
│   ├── Models/           # Data transfer objects
│   └── Program.cs        # Application entry point
├── RoselineMCP.Tests/    # Unit tests
├── .github/workflows/    # CI/CD pipelines
├── Dockerfile            # Container build
└── RoselineMCP.sln       # Solution file

性能

  • 工作区缓存——导航、编辑和诊断/修复工具(ListDiagnostics、ApplyFixes,以及所有由 IProjectLoader 支持的工具)会在多次调用间复用已加载的 MSBuildWorkspace,因此除首次调用外,每次调用都能省去数百毫秒的重新加载时间。缓存条目带有指纹(.sln、每个 .csproj、每个源文件及其目录的最后写入时间 + 大小),并会在每次调用时重新检查,因此磁盘上的任何更改——包括 RoselineMCP 自身所做的编辑——都会触发重新加载。对于捕获时间戳时自身最后写入时间仍较新的文件/目录,还会一并记录内容签名(哈希值或目录列表),因此即使在同一文件系统时间戳粒度区间内发生长度相同的写入,也会通过比较签名而非仅凭基本文件状态匹配来捕获;这种方式开销很低,文件保持较新时无需每次调用都强制重新加载。可通过 RoselineMCP:WorkspaceCache = false 禁用——但请注意,这是用于隔离/调试的开关,并非降低内存占用的方法:已释放的工作区所占内存不会归还给操作系统,因此禁用缓存后,常驻内存占用会更差约 26%,速度也会慢约 45 倍。测量结果及评估后为何拒绝空闲释放方案,见内存管理
  • 工作区隔离(AnalyzeSolution)——AnalyzeSolution 仍会为每项操作创建全新的 MSBuildWorkspace(见架构)
  • 顺序分析项目——解决方案中的项目会逐个分析,而非并发分析,以保持 MSBuild 工作区状态一致
  • 结果上限——maxDiagnostics/max 限制每次调用返回的诊断数量,与发现的诊断数量无关

编译防护

EditMember/RenameSymbol/ApplyFixes 背后的编译检查仅会针对通过这些工具进行的写入触发。编译防护会将相同的检查应用于 C# 解决方案中的每次文件写入——无论 Agent 使用的是 Edit、Write、MultiEdit 还是其他工具——它会作为 PostToolUse hook 运行,并通过本地套接字向已运行的服务请求检查结果。

它只会报告,无法阻止。 PostToolUse 会在工具完成写入之后触发,而且 hook 协议不包含阻止决策。防护的作用是在同一轮中向 Agent 显示新增的编译器错误,让它接下来修复这些错误,而不是在此基础上继续操作。它无法阻止写入——有关为何拒绝可阻止写入的替代方案,请参阅此 issue。

启用它(默认关闭),然后安装 hook:

# 1. the server opens the local guard endpoint
export ROSELINE_RoselineMCP__Guard=true

# 2. print the settings.json block and paste it into .claude/settings.json
roseline-mcp guard --print-hook

每次写入时的处理方式:

情况结果
编辑引入了编译器错误在 Agent 当前轮次中报告错误(退出码 2,通过 stderr 输出)
编辑未引入任何错误静默——退出码 0,无输出,不消耗 token
分支原本就有错误静默——已有错误并非 Agent 所致
不是 .cs 文件,或没有所属项目静默
服务未运行或响应过慢静默——无法提供信息的防护不得造成中断

仅检查编译器诊断,并且范围限定为已更改项目及其依赖项目,因此足够快速,可用于内循环。它会添加一个本地 IPC 端点:在共享机器上启用前,请先阅读 SECURITY.md。

安全

  • 默认只读——AnalyzeSolution、ListDiagnostics、CreatePatch 以及全部六个代码导航工具(SearchSymbols、GetSymbolInfo、FindReferences、FindImplementations、GetCallGraph、GetTypeHierarchy)绝不会写入磁盘。三个可写入的工具——ApplyFixes、EditMember 和 RenameSymbol——默认都将 previewOnly: true;调用方必须显式传入 previewOnly: false 才能写入。在这个选择加入机制之后还有第二道尽力而为的保护:写入工具会通过 MCP elicitation 请求客户端确认,然后才写入;如果用户拒绝,调用会降级为预览。提示未得到回应时也会如此——往返等待时间受 RoselineMCP:ConfirmDestructiveWritesTimeout 限制(默认 5 分钟),超时后调用会返回预览,而不会写入或一直挂起。如果客户端不支持 elicitation,则会跳过确认;操作员也可以通过 RoselineMCP:ConfirmDestructiveWrites=false 完全禁用确认——此后只剩 previewOnly: false 这一道保护。请参阅 SECURITY.md。
  • 真实、只读的 Git 克隆——pathOrGit 接受 http(s):// Git URL,并会将其浅克隆(git clone --depth 1)到临时目录中;操作完成后会删除该目录。其他任何 URL 方案都不会被视为 Git 远程服务。
  • MSBuild 并非沙箱——通过 MSBuildWorkspace 加载 .sln/.csproj 会进行设计时 MSBuild 评估,并可能执行嵌入在项目中的构建逻辑(<Exec> 任务、自定义 UsingTask 程序集、导入的 .targets/.props)。分析完全不受信任的仓库或 URL,会给主机带来真实的代码执行风险。在将 RoselineMCP 指向不受信任的输入之前,请参阅 SECURITY.md,了解完整说明和操作员建议。
  • 执行分析器就是执行代码——诊断工具也会在进程内运行目标项目引用的 Roslyn 分析器(请参阅支持的分析器);来自不受信任仓库的分析器可执行任意代码。RoselineMCP:RunAnalyzers = false 会禁用诊断分析器阶段(包括捆绑的 Roslynator)。请参阅 SECURITY.md。
  • 代码修复提供程序来自相同的引用——list_diagnostics 和 apply_fixes 还会加载项目自身分析器引用中携带的 CodeFixProvider 类型。这不会加载分析器阶段尚未加载的程序集(每个类型都通过其引用自身的程序集加载器获取),但这是有意为之的选择,而非意外行为;RunAnalyzers = false 不会控制此功能。详情已记录在 SECURITY.md。
  • 无论该开关如何设置,源生成器都会运行——生成器通过相同的 AnalyzerReferences 提供,但它们会在构建任何编译时运行,而不是作为诊断阶段的一部分,因此每条语义分析路径都会执行它们——包括所有导航工具。若不破坏语义分析,就无法阻止它们运行。RunAnalyzers = false 可以缩小不受信任仓库的代码执行范围,但无法消除风险。请改用隔离方式——参阅 SECURITY.md。
  • 没有专用的路径遍历沙箱——路径仅通过普通存在性检查进行解析,不会根据允许的根目录进行规范化;请将 pathOrGit/project/branch 视为受信任的操作员输入。

故障排除

常见问题
  1. 找不到 MSBuild:确保已安装 .NET SDK,且其位于 PATH 中
  2. 无法加载解决方案:检查是否缺少 NuGet 包,并运行 dotnet restore
  3. 未找到分析器(RCS/SA)诊断**:确认 RoselineMCP:RunAnalyzers 未设置为 false;对于非捆绑规则集(例如 StyleCop),请确认目标项目中已安装该分析器
  4. 权限被拒绝:确保对解决方案文件具有读取权限
调试日志

启用详细日志:

ROSELINE_Logging__LogLevel__RoselineMCP=Debug dotnet run --project RoselineMCP/RoselineMCP.csproj
跟踪单个工具调用

每次工具调用都会获得一个调用级别的关联 ID(GUID)。生成它的成本很低,因此始终会创建,但只有在需要时才会显示:它会包含在每个 JSON 错误响应(correlationId)中,并通过 ILogger.BeginScope 附加到该调用的日志行中。这样,用户报告故障时只需提供一个 ID,你就能找到完整的服务端日志条目——无需按时间戳搜索。

如需深入选择性跟踪每次工具调用(开始/停止、持续时间、成功/失败),并将其记录为 System.Diagnostics.Activity 跨度,请将 RoselineMCP:EnableDiagnosticLogging 设为 true(它在 appsettings.Development.json 中已经设为 true):

ROSELINE_RoselineMCP__EnableDiagnosticLogging=true dotnet run --project RoselineMCP/RoselineMCP.csproj

此功能使用内置的 ActivitySource/Activity API,而非 OpenTelemetry SDK,因此不会增加额外依赖。跨度仅通过现有的 ILogger 管道记录,该管道已路由到 stderr——绝不会写入 stdout(MCP JSON-RPC 通道),也不会通过网络发送任何内容;关闭该标志时(默认状态),不会注册监听器,跨度的开销几乎为零。

路线图

  • 更多分析器规则集(SonarAnalyzer、FxCop)
  • 提供带置信度评分的自动修复建议
  • 集成 CI/CD,实现自动化分析流水线
  • 在单个会话中支持多个解决方案
  • 增量分析(仅分析已更改的文件)
  • 通过 MCP 配置自定义分析器规则

想要参与贡献?任选一项路线图任务并提交 PR!

文档

  • 文档网站 -- 概览、工具参考,以及 token 节省基准测试 (由 website/ 构建,部署到 GitHub Pages)
  • docs/API.md -- 每个 MCP 工具的完整请求/响应参考、服务接口、模型及错误响应约定
  • docs/AGENT-BENCHMARK.md -- 端到端 A/B 测试:AI Agent 使用 RoselineMCP 实际上能否减少 token 消耗?(坦诚地说——大型代码库中效果显著,小型代码库中则持平)
  • docs/ARCHITECTURE.md -- 分层架构、数据流和设计模式
  • PROMPTS.md -- 各工具的提示词示例和端到端工作流
  • CHANGELOG.md -- 发布历史和重大变更
  • SECURITY.md -- 漏洞报告和 MSBuild 代码执行注意事项
  • CONTRIBUTING.md -- 开发环境设置和 PR 流程

Atypical MCP 服务

这是 Atypical Consulting 的一套 Model Context Protocol 服务的一部分:

  • RoselineMCP — 面向 AI Agent 的 Roslyn 代码智能
  • ASTral — 结构化代码检索(tree-sitter)
  • AdrMcp — 通过 MCP 提供架构决策记录
  • MarkdownInk — 终端 Markdown 渲染

贡献

欢迎贡献!请先阅读 CONTRIBUTING.md。

  1. Fork 此仓库
  2. 创建功能分支(git checkout -b feature/amazing-feature)
  3. 使用 conventional commits 规范提交(git commit -m 'feat: add amazing feature')
  4. 将分支推送到远程仓库(git push origin feature/amazing-feature)
  5. 发起 Pull Request

许可证

MIT © 2026 Atypical Consulting SRL

致谢


由 Atypical Consulting 倾心打造 —— 主张鲜明、达到生产级标准的开源项目。

贡献者


由 Atypical Consulting 打造。我们还开发了 NuGetKeep, 一款具备供应链隔离功能的可自托管 NuGet 服务。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。