RoslynMcpServer / rules
Cursor rule8 starsChanged 46 days agoMITView on GitHub
RoslynMcpServer — architecture, layout, version, DI
In this repository16 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .cursor/rules/roslyn-mcp-build-sdk.mdcCursor rule
- .cursor/rules/roslyn-mcp-ci.mdcCursor rule
- .cursor/rules/roslyn-mcp-decompile.mdcCursor rule
- .cursor/rules/roslyn-mcp-dev-conventions.mdcCursor rule
- .cursor/rules/roslyn-mcp-docs-agents.mdcCursor rule
- .cursor/rules/roslyn-mcp-docs-lifecycle.mdcCursor rule
- .cursor/rules/roslyn-mcp-github-release.mdcCursor rule
- .cursor/rules/roslyn-mcp-paths.mdcCursor rule
- .cursor/rules/roslyn-mcp-pitfalls.mdcCursor rule
- .cursor/rules/roslyn-mcp-structural-tests.mdcCursor rule
- .cursor/rules/roslyn-mcp-tools.mdcCursor rule
- .cursor/rules/roslyn-mcp-version-bump.mdcCursor rule
- epoch-subagent-loopSkill
- epoch-subagent-loopSkill
- prepare-github-releaseSkill
The file
Files
---
description: RoslynMcpServer — architecture, layout, version, DI
alwaysApply: true
---
# RoslynMcpServer overview
MCP server (stdio) for C# analysis: Roslyn workspaces + ILSpy decompile. TFM `net10.0`, version in `RoslynMcpServer.csproj` (currently **1.5.15**). Package id `RoslynMcpServer`. Self-contained publish for win/osx/linux RIDs.
## Layout
- `Program.cs` — MSBuild bootstrap, optional `ROSLYN_MCP_WORKSPACE` → cwd, Serilog to `logs/mcp-*.log` under `AppContext.BaseDirectory` (each line prefixed with a harness session id)
- `Hosting/` — DI (`AddRoslynMcpServerTools`), `McpToolRegistry`
- `Tools/` — MCP tool classes (Workspace, CodeAnalysis, Skeleton, Build, Run, Test, NuGet, Utility, …)
- `Services/` — `Workspace` (`SolutionManager`), `Analyzers`, `Build`, `Editing`, `Navigation`, `Resolve`, `Testing`; helpers that do not belong to one of those stay at the root
- `Diagnostics/` — parsers (build, VSTest, NuGet audit), SDK mismatch, MSBuild locator
- `RoslynMcpServer.Tests/` — xUnit; `InternalsVisibleTo`
- Docs: `README.md` (EN+RU), `AGENTS.md.sample` (copy to app repos as `AGENTS.md`)
## DI / tools
Tools are singletons registered in `RoslynMcpServiceCollectionExtensions`. Inject `SolutionManager` — do not `new` workspaces/HTTP. Heavy services via constructor.
## Related consumer
Real-world validation often uses **BrqMover** (`c:\Devel\BrqMover`) — app repo with its own `AGENTS.md`; do not hardcode that path into this repo’s docs/rules.
## Version history (agent-relevant)
- **1.5.7** — Linux SDK fallback also searches `/usr/lib/dotnet` and `~/.dotnet`. Missing-SDK messages name `DOTNET_ROOT`/`PATH` off Windows. `get_mcp_server_info` publishes with the current process RID. Analyzer path keys are case-sensitive off Windows
- **1.5.6** — a watcher event during the additional-file or `.editorconfig` content read no longer drops that save for the rest of the flush. The flush reads the path again a few times and publishes only after the bytes are accepted. An unstable, unreadable, missing, or still-open own write stays deferred
- **1.5.4** — saved additional-file and analyzer-config text is applied on the published snapshot (`WithAdditionalDocumentText` / `WithAnalyzerConfigDocumentText`) during the same flush as `.cs`. Not `TryApplyChanges`. XAML, resx, Razor, evaluation-input paths, and new or deleted files stay out. Coverage-unknown does not block a document already in the graph and is not cleared by the replace
- **1.5.3** — DLL tests share one solution-target `buildPolicy` (`auto` / `always` / `never`) on `run_dotnet_test`, `run_specific_test`, and `run_test_by_filter` when `binariesPath` is set
- **1.5.2** — disk watcher follows the loaded graph: recursive project directories, non-recursive watches for linked files and walk-up props outside them. One user `.cs` text updates every document of that path. Non-C# inputs are recorded by role and are not text-synced. Own writes match saved bytes, including BOM. Semantic flush does not clear input revisions. `search_code` roots are unchanged
- **1.5.1** — WPF `{ProjectName}_{random}_wpftmp.csproj` create/delete does not mark the project graph stale unless that path is a loaded project. A real project-file change during the build still does
- **1.5.0** — MCP C# SDK 2.2.0. Group enablement batches `tools/list_changed` with the SDK `DeferChangedEvents` scope. `2025-11-25` sessions receive that notification directly; `2026-07-28` sessions receive it after `subscriptions/listen` (`toolsListChanged`). Plugin projects reference `ModelContextProtocol` 2.2 (`Major.Minor` must match the host assembly)
- **1.4.19** — disk watcher error and directory-rename callbacks still request a full re-read when the logger throws (`Logger.Log` rethrows a provider failure such as Windows Event Log `ObjectDisposedException`); the callback no longer kills the process
- **1.4.18** — plugins: `IRoslynMcpPlugin` assemblies load before `Build` from `plugins/<id>/`, the `plugins` key of `RoslynMcp.jsonc`, or `ROSLYN_MCP_PLUGINS` (dev directory shadow-copied); a plugin that cannot be loaded is skipped with `[RoslynMcp] plugin skipped (<id or path>): <reason>` on stderr and in `logs/mcp-*.log` while the host still starts; `get_mcp_server_info` lists loaded plugins and skips, `get_tool_help` reports `Kind`/`Group` `plugin` from the start report; plugin tools are in `tools/list` and `Registered MCP tools`, not in `McpToolCatalog` or `list_tool_groups`, and `lite`/`full` do not filter them
- **1.4.17** — `get_changed_files` reads git stdout and stderr together, closes stdin, and stops the process after 180s plus up to 3s of cleanup (`Kill(entireProcessTree)` on Windows, Linux, and macOS)
- **1.4.16** — shared `logs/mcp-*.log` lines include a harness session id (`[cursor-k7m2]`, `[opencode-4mht]`): parent exe name, or node command-line package/directory; 4-char suffix; unknown parent is `cli`; command line is not logged
- **1.4.15** — writes preserve the file's BOM state (no BOM added to BOM-free files, none stripped from BOM files); `SourceTextEncoding` resolves existing document → candidate → on-disk BOM
- **1.3.32** — `DotNetCliRunner` timeout kills the process then drains pipes (no hang on canceled `ReadToEndAsync`); lifecycle host `build` honors `TimeoutMs`
- **1.3.31** — `update_file_content` / `apply_patch` do not recreate missing-on-disk `.cs`; disk-sync does not `WithDocumentText` a deleted known document
- **1.3.30** — disk-sync updates texts of known documents only (no `AddDocument`/`RemoveDocument`); new/deleted `.cs` → composition-stale + reload, not `<Compile Include>` / NETSDK1022
- **1.3.29** — single `TestAttributeMatcher` (base-chain walk) shared by `get_test_list` and `run_specific_test`; custom `FactAttribute`-derived attributes (`[AnalyzerLifecycleFact]`, `[WpfFact]`) discovered and filterable; `DataRowAttribute` no longer a test marker; `get_test_list` adds `totalTestMethodsFound` (before filters) and only blames filters when the workspace did find tests
- **1.3.28** — `get_test_list` discovered **0** tests on every real workspace: `GetSymbolInfo(AttributeSyntax).Symbol` is the attribute *constructor* (`.ctor`), and names were compared without the `Attribute` suffix (`Fact` vs `FactAttribute`); now resolves `ContainingType` + strips suffix/qualifier, syntactic fallback only when unbound; `TestDiscoveryHelperTests` fixtures now reference corelib + `System.Runtime` + `xunit.core` so attributes actually bind (they were false-green)
- **1.3.27** — `run_dotnet_test` / `run_specific_test` / `run_test_by_filter` / `run_dotnet_run` emit the same MCP progress heartbeats as build (`dotnet build` / `dotnet test` / `dotnet run`; 5 s; no stdout); `RunSeparatedAsync` takes optional `CliProgressWatch`
- **1.3.26** — progress `elapsed` = current step only (boundary = `starting`); numeric `Progress` = strictly increasing whole seconds, no `Total` (not a percentage); adapter detects SDK no-op progress so a token-less call starts no timer
- **1.3.25** — `run_dotnet_build` emits MCP `notifications/progress` heartbeats (step label, elapsed, previous exit; no stdout) via a reusable `DotNetCliRunner`/`DotNetBuildProbe` seam; no schema change, no host-timeout fix
- **1.3.24** — test tools include VSTest `Standard Output/Error` (ConversationId, `ITestOutputHelper`) with per-stream budgets; `includeFullOutput` / `maxOutputChars`
- **1.3.23** — `run_specific_test` matches xUnit method-only / `FQN(args)` display names (dot-bounded suffix); slow durations `[3 m 8 s]` valid
- **1.3.22** — test failure text keeps multiline `Error Message:`; MSBuild `Build FAILED` / `0 Error(s)` footer after failed tests is not compile/silent failure
- **1.3.21** — U-ARB-01: inaccessible original analyzer path is skip (no rewrite, not missing)
- **1.3.20** — preserve `DependencyUnsupported` / main-only through a full publication ban (v3 S8)
- **1.3.19** — mixed analyzer prepare: per-reference applied/excluded/banned publication (v3 S5), no `HasAnyApplied`
- **1.3.18** — withhold opt-in semantics when provenance capture unsuitable (V3-R3); cached `true` does not repair
- **1.3.17** — persistent fail-closed publication after a failed opt-in (V3-R2)
- **1.3.16** — reject stale write bases before any disk/workspace mutation (V3-R1 / A4-09)
- **1.3.15** — no implicit semantic workspace load (`FindDocumentAsync`; U-ARB-04-IMPL-1)
- **1.3.14** — atomic analyzer load/prepare boundary (U-ARB-04)
- **1.3.13** — `shadowCopyInSolutionAnalyzers` activation is session-sticky (U-ARB-05); disable via `reset_workspace`
- **1.3.12** — analyzer provenance acceptance (E5-S4)
- **1.3.11** — analyzer provenance diagnostics: stable internal reason codes (E5-S3)
- **1.3.10** — analyzer provenance rollout: exact load-session F-09 join only (E5-S2)
- **1.3.9** — analyzer provenance capture via design-time binlog replay (F-09)
- **1.3.8** — workspace write boundary (epoch 4): preflight → exact inverse → persist → apply/reconciliation
- **1.3.7** — overlay loader contract: restart-required, main-only (epoch 3)
- **1.3.6** — immutable content-hashed analyzer generation mapping (epoch 2); zero analyzer I/O on edit
- **1.3.5** — overlay fix: shadow rewrite stays in-memory, never `TryApplyChanges` (v1.3.4 corrupted real `.csproj`)
- **1.3.4** — `load_workspace` `shadowCopyInSolutionAnalyzers` (superseded by 1.3.5)
- **1.3.3** — `load_workspace` `logProjectOutputDiagnostics`
- **1.3.2** — `binariesPath` on `run_specific_test` / `run_dotnet_test`; `run_test_by_filter` honors `noBuild`
- **1.3.1** — `get_test_list` `projectName` / `nameContains` filters
- **1.3.0** — `run_test_by_filter` (raw VSTest `--filter`)
- **1.2.3** — `run_dotnet_build` `projectName` (sln `-t` virtual path); `-p:Configuration` in probes
- **1.2.2** — `load_workspace` `briefOutput`
- **1.2.1** — `load_workspace` `buildArgs` (session-cached; build only)
- **1.2.0** — tool profiles `full` / `lite`, `ROSLYN_MCP_TOOL_GROUPS`, `list_tool_groups` / `get_tool_help` / `enable_tool_group`
- **1.1.1** — decompile `assemblyName`: dotted simple names (`Spectre.Console`) no longer truncated
- **1.1.0** — disk watcher: saved `.cs` (IDE/git) sync into MSBuildWorkspace before symbol search; no keystroke/unsaved buffers; `.csproj` changes skip load cache, not OpenSolutionAsync from the watcher
- **1.0.35** — Roslyn 5.9.0; dedicated VS 2026 / MSBuild 18 BuildHost (`XMakeElements`) load/symbol failure (not SDK mismatch)
- **1.0.34** — `load_workspace`: wrapped design-time MSBuild warnings (ASPDEPR007 / IncludeOpenAPIAnalyzers, MSB3270, analyzer metadata refs) are warnings, not hard Failure
- **1.0.33** — `load_workspace` optional `targetFramework` (inner TFM for CrossTargeting / `TargetFrameworks`); dedicated missing-`Compile` load report
- **1.0.32** — `run_specific_test`: VSTest Passed/Failed lines accept `[1 s]` / `[1 m 28 s]` durations (not only `ms`)
- **1.0.31** — `run_dotnet_test` / `run_specific_test`: separate incremental `dotnet build` then `dotnet test --no-build` (parser sees test output only)
- **1.0.30** — `apply_patch` replaceAll: advance past inserted text (hang when newString contains oldString)
- **1.0.29** — `load_workspace` optional Configuration/Platform (cached for build/test); empty-TFM ResolvePackageAssets dedicated fail
- **1.0.28** — `run_dotnet_test`: infer Passed when `.slnx` VSTest omits the `Passed:` line
- **1.0.27** — `load_workspace`: NU1701 / TFM-compat restore warnings soft (not fatal); `Msbuild failed` wrapper word `failed` is not blocking by itself
- **1.0.26** — agent diagnostics: client-abort `load_workspace`, empty `get_test_list`, `run_specific_test` path/filter mismatch hints
- **1.0.25** — `run_dotnet_build`: default `--no-incremental`; effective exit = last build step (restore cannot mask)
- **1.0.22** — `run_specific_test`: VSTest-safe method filters (`~`, no `()`, no bogus leading `.` on dotted FQNs)
- **1.0.21** — `load_workspace`: NuGet prune / unused PackageReference advisories soft (warnings), not hard Failure
- **1.0.20** — optional `configuration` (`-c`) on `run_dotnet_build` / `run_dotnet_test` / `run_specific_test`
- **1.0.19** — `.slnx` accepted by `load_workspace` / build / test / discovery (prefer solution files for multi-config)
- **1.0.18** — tool `[Description]` accuracy pass (build probe, decompile resolve, NuGet timeouts, AST params)
- **1.0.17** — `run_dotnet_test` / `run_specific_test` optional `noBuild` / `noRestore`
- **1.0.15** — `search_code` `caseSensitive`; no-workspace candidate paths; `rename_project`; branding recipe in AGENTS
- **1.0.14** — `run_dotnet_run`, `run_nuget_audit`, `get_changed_files`, workspace health on `load_workspace`
- **1.0.13** — exact assembly resolve (deps.json + NuGet), no fuzzy `Contains`
- **1.0.10+** — SDK pin from `global.json`, build probe, VSTest parser, `MCP_MSBUILD_SDK_MISMATCH`
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

