
dotnet-mcp
io.github.Skymly由 GitHub 账号 Skymly 发布v5.0.1更新于 Nov 7, 2026
MCP server for .NET symbols, XAML, source generators, and restricted workspace edit
概览
本地 MCP 服务器,为编码代理提供编译器级准确的 .NET 解决方案导航、XAML 查询,以及受限的重命名、诊断修复与重构编辑。
- 可以做什么
- 打开并检查 .NET 工作区:加载解决方案或项目、轮询加载状态、列出项目、检查漂移。
- 解析与导航符号:转到定义、成员、引用、实现、调用方、类型层次,并区分手写成员与源生成成员。
- 检查项目:诊断、源生成器、生成源、生成器诊断、dynamic 调用。
- 查询 Avalonia 与 MAUI XAML:解析类、xmlns、x:Name、编译绑定与 XAML 诊断。
- 预览并应用受限写入:重命名、诊断修复(含项目级 Fix all)与代码重构。
- 适用场景
- 当代理需要理解或安全重构 C#/VB/F# .NET 代码库时使用,尤其适用于使用源生成器或 Avalonia/MAUI XAML 的项目,并希望采用先预览后应用的编辑方式而非自由写文件。
- 运行要求
- 以 .NET 工具形式通过 stdio 本地运行(NuGet 包 Skymly.DotNetMcp,命令 dnmcp),需要 .NET 10 或更高版本。必须通过 --roots 或 DOTNET_MCP_TRUSTED_ROOTS 配置受信根,否则启动失败。预算与审计设置通过环境变量配置。
安装
在 SourceWeft 中
- 打开 控制台中的 dotnet-mcp,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
dotnet-mcp
An MCP (Model Context Protocol) server for .NET workspaces. It gives coding agents compiler-accurate symbol navigation, source-generator attribution, Avalonia/MAUI XAML queries, and a restricted Workspace Edit surface (rename / diagnostic fix / code refactoring). It is not a generic file writer, shell, or LSP proxy.
Package id on NuGet: Skymly.DotNetMcp (CLI command: dnmcp). Requires .NET 10+.
What it can do
- Load
.sln/.slnx/.slnf/ SDK-style.csproj/.vbproj/.fsproj - C# and VB.NET via Roslyn; F# via an FCS stack beside the Roslyn snapshot
- Resolve a name to a checksummed
SymbolHandle, then go to definition, members, references, implementations, callers, type hierarchy - Attribute handwritten vs source-generated members (generator assembly + type + version)
- Project diagnostics; list generators / generated sources / generator diagnostics; list
dynamicinvocations - Avalonia
.axamland MAUI.xaml: class, xmlns,x:Name, compiled-binding path, XAML diagnostics - Restricted writes: preview then apply for rename, diagnostic fix (including project Fix all), and code refactoring
What it does not do
- Generic write / patch / create / delete file tools
- Shell, process, HTTP, or package-download tools
- WPF / WinUI XAML
- F# source-generator attribution (
symbol_attributionon an F# handle returnsGeneratorLanguageNotSupported), generator queries, dynamic invocation queries, diagnostic fix, or code refactoring - Cross-language F# reads and writes — F# handles search the defining project plus its F# dependents (or every F# project with
entireSolution), but C#/VB consumers are named, not searched, and a visible F# symbol with C#/VB dependents cannot be renamed - Extract-method / change-signature UIs
- Opening untrusted repositories safely —
workspace_openruns MSBuild evaluation and project analyzers/generators
Tool names are locked by a snapshot test. Domain vocabulary: CONTEXT.md.
Quick Start
Trusted roots are required. The process working directory is never an implicit trusted root.
On Windows, separate multiple roots with ;. You can also set DOTNET_MCP_TRUSTED_ROOTS. When both are set, startup uses their union; neither replaces the other. --roots=path is the same as --roots path; an empty value is rejected. A missing or empty roots configuration exits with code 1 and writes one JSON object to stderr (error, message, suggestedAction) instead of a stack trace.
Skymly.DotNetMcp is published on NuGet. dnx is the preferred install. A source build or a local pack works too.
MCP client (stdio):
Equivalent: dotnet tool exec Skymly.DotNetMcp --yes -- --roots /path/to/repo, or dotnet tool install -g Skymly.DotNetMcp then dnmcp --roots /path/to/repo.
Development run
From a clone of this repo:
Local pack
stdio only. Framework-dependent .NET tool; NativeAOT is not required.
Typical agent loop: workspace_open (returns immediately) → poll workspace_status until ready → symbol_resolve → navigation / attribution. Prefer a .slnf or a single project for a large solution. .slnf entries already in the workspace (duplicates, or projects an earlier entry pulled in transitively) are skipped and named in the load warnings rather than failing the open.
For agent setup, docs/agent-guidance.md holds a copy-paste block for a consuming repo's AGENTS.md / CLAUDE.md — the loop, the 1-based position model, and the preview → apply write rule. The server also sends the same brief in the initialize result instructions and ships trace_symbol / safe_rename prompts that walk an agent through the two core workflows.
MCP tools
diagnostics_list_fixes and symbol_list_refactorings return epoch. fixIndex and refactoringIndex are valid only for that epoch. After it advances, preview fails with FixListEpochMismatch or RefactoringListEpochMismatch instead of selecting another action.
If a code-action provider throws, diagnostics_preview_fix and symbol_preview_refactoring still return FixApplyFailed or RefactoringApplyFailed, but the message says the provider threw. That is not the same as a fix that produced no handwritten change. Fix all stops with FixApplyFailed instead of skipping that occurrence.
project_diagnostics without projectId reports a failed project as error plus suggestedAction, not as a Severity=Error diagnostic. Do not pass that row to diagnostics_list_fixes.
project_diagnostics sets degraded plus a degradedReason when the compilation reports CS0006 or CS0012 — metadata references that did not resolve — computed over the project's full diagnostic set before paging. Listed errors may then be workspace artifacts rather than real code defects; verify with dotnet build before trusting fix previews. Both fields are omitted otherwise.
On paged results (items / truncated / nextCursor), message is optional and omitted when there is nothing to add.
symbol_find_references also merges Exact XAML usage points (bindings, x:Class, element types, x:Name fields, event handlers) for C#/VB handles. Source hits page first; XAML hits follow in the same paged stream and carry xamlUsage naming the usage kind — source hits omit the field. Name-matched Unverified points are never included, and the XAML scan covers the same scope as source references (defining project plus dependents, or every project with entireSolution). One soft budget covers both lanes and the cursor walks both stages.
symbol_resolve_at accepts positions inside registered XAML documents too: a covering usage point resolves to its target handle with resolvedFrom = Reference and matched set to the exact usage span, while a position outside every usage returns NoSymbolAtPosition.
symbol_preview_rename keeps XAML in sync for C#/VB handles: Exact usage points in registered XAML documents (bindings, x:Class, element/attribute names, x:DataType, markup type refs, x:Name values, event-handler values) become ordinary old/new slices in the same preview — each edits only the symbol's simple-name occurrence inside its span — and symbol_apply_rename writes them through the same pipeline (WriteSuppression, encoding/BOM preserved, no files added or removed). Name-matched Unverified usages are reported under unverifiedXamlMentions without being written. The Origin = SourceGenerator refusal stays, with one exception: a generated x:Name field is renamed through its XAML value plus handwritten references, and the generator re-emits the field on its next run. Diagnostic fix and code refactoring previews never slice XAML documents.
Rename's write set is compiler-visible references plus those Exact XAML usages. It does not rewrite metadata-name strings (a GetTypeByMetadataName or ForAttributeWithMetadataName argument, for example), short attribute names the compiler did not bind, documentation, comments, or PublicAPI lists. Those hits are not listed — unverifiedMentions is not a field — so do not expect a whole-repository rename.
All located outputs share one position model: line and column are 1-based, columns count UTF-16 code units (a tab is one column), and endColumn is exclusive — the same file(line,col) convention the compilers print. start/length remain as UTF-16 offsets for slicing. Locations without a source position (InMetadata, None) omit the position fields, and positions in source-generated documents are coordinates inside the generated text. A position reported by one tool feeds the next tool verbatim — for example a project_diagnostics row's line/column/endLine/endColumn are exactly the locator arguments of diagnostics_list_fixes and diagnostics_preview_fix.
symbol_attribution reports a third axis beside declaration availability and generator identity: triggers[] on the root symbol and every member name the handwritten code that caused a generated member — a PartialDefinition counterpart bound by the compiler (C# and VB), an Attribute declaration such as [ObservableProperty], [RelayCommand], or [JsonSerializable], or a XamlElement (x:Name field or the x:Class document root, resolved through the XAML usage index). Each trigger carries confidence (Exact for compiler-bound evidence, Convention for unique name-inverse lookups), the unified position quad, detail, and a handle that re-resolves through symbol_summary for code triggers. Handwritten symbols return triggers: []; a generated member whose generator matches no rule and has no partial counterpart returns triggers: [] plus a triggerMessage instead of a guessed location.
An empty or whitespace path to workspace_open or an XAML tool is an empty-path error (InvalidWorkspacePath or XamlDocumentNotFound), not PathOutsideTrustedRoots.
workspace_open returns the same progress fields as workspace_status, including errorCode when the open fails before the background load. A null errorCode is omitted.
A source generator or analyzer that references a newer Microsoft.CodeAnalysis than the server bundles is refused by Roslyn, and its output silently drops out of project_list_generators, project_list_generated_sources, and symbol_attribution. Once the workspace is ready, workspace_status.warnings carries an AnalyzerReferencesNewerCompiler entry that names the file (not its path). It is read from the assembly's metadata, so the analyzer is not loaded to find out. The fix is a dotnet-mcp release that bundles a newer Roslyn.
An analyzer path MSBuild declared but that resolves to no loadable assembly — an OutputItemType="Analyzer" project reference whose output is not built, or a DLL missing on disk — is not a silent miss either: project_list_generators lists it under unresolvedAnalyzerReferences with a message saying to build the analyzer project and reopen the workspace. Generator identities are only ever reported for assemblies that actually loaded.
Security
- Trusted roots — every path is canonicalized (including parent reparse points). Unresolvable links fail closed. Loaded project graphs and apply-paths are re-checked. Configure
--roots/--roots=pathorDOTNET_MCP_TRUSTED_ROOTS. When both are set, the trusted set is their union. Path comparison ignores case on Windows and respects it on Linux and macOS, including a default macOS volume that does not, so write a path with the same casing as the configured root. Startup failure usesTrustedRootsConfigurationFailedon stderr, not a stack trace. - Open means execute — loading a solution runs MSBuild and referenced analyzers / source generators. Do not point this server at untrusted trees.
.slnfproject entries are checked before MSBuild opens them;.sln/.slnx/ single-project graphs are checked after load, so an out-of-rootProjectReferenceis evaluated before it is rejected. Loaded documents and analyzer references may also resolve under toolchain roots — the NuGet package cache and the dotnet install directory — because packages like xunit v3 inject package-cache sources into the compile and builds already execute code from those roots; project paths and the whole write set still require trusted roots. - Default read + named writes — only rename / diagnostic fix / refactoring preview-apply. No generic write, command, or network tools. Apply refuses, and does not write, a document that has no BOM and is not valid UTF-8 (
SourceEncodingRefused). - Audit — local process logs (stderr under stdio). Tool name and path metadata only; no source text; no telemetry. Disable with
DOTNET_MCP_AUDIT=0. Logging configuration comes from environment variables and the server's own install directory. Anappsettings.jsonin the directory the MCP client launched the server from is not read, so an opened repository cannot reformat or silence the audit log.
See ADR-0004.
Soft budgets and long-running load
These tools stop at the soft budget (ADR-0003) and return partial results + nextCursor instead of hanging past the common ~60s client tools/call cap: project_diagnostics, xaml_diagnostics, project_list_dynamic_invocations, symbol_find_references, symbol_find_callers. For F# handles the budget is checked between project scans — a spent budget yields the partial page plus a nextCursor that resumes at the next project in the scope; the per-project FCS check itself is not budgeted. These run to completion (or to the client timeout) without a budget: symbol_members, symbol_type_hierarchy, symbol_find_implementations, project_list_generated_sources, project_list_generator_diagnostics. symbol_resolve is bounded by the same budget, but a budget hit fails with SoftBudgetExceeded rather than a partial page. Progress notifications are not a keepalive.
Document-scope Fix all applies at most 32 fixes. Project-scope Fix all also stops at a fixed application cap (default 64). Neither application cap is an environment variable.
0 means the budget is already spent — list tools return a truncated page right away (possibly empty) with nextCursor, and project Fix all fails the preview; symbol_find_references and symbol_find_callers still finish the current document (and symbol_find_references finishes the current project on its XAML lane) so the cursor advances, so a page may contain items; negative or unparseable values fall back to the defaults.
workspace_open never blocks the MCP request. Clients that do not opt into MCP Tasks should poll workspace_status. workspace_status.watcher is ok, lost, or off; lost means file watching failed and a restart was attempted. Details: spikes/s3-mcp-long-running/CONCLUSIONS.md. That note separates the spike jobId shape from the product DTO, which has no jobId.
Development / CI
Product and tests target net10.0. Fixtures include net8.0 / net9.0 projects (needed for MsBuildWorkspaceIntegrationTests).
There is no packages.lock.json, and RestorePackagesWithLockFile is not set. Direct PackageReference versions are pinned centrally in Directory.Packages.props; the test fixtures and spikes opt out and pin their own. Transitive dependency resolution is not locked, so a later restore can select a different transitive version.
CI: .github/workflows/ci.yml (Ubuntu, Windows and macOS; product SDK via global.json 10.0.x roll-forward, fixture SDKs 8.0.x/9.0.x, a C# whitespace-format check, a known-vulnerable-package check, pack + McpServer metadata check, and a smoke test that runs the packed tool with the dotnet tool exec form from Quick Start). Third-party actions are pinned to commit SHAs and the workflow token is read-only. A separate codeql.yml workflow runs CodeQL on the C# sources for every pull request and weekly, and Dependabot proposes weekly NuGet updates (grouped by package family) and GitHub Actions updates.
The whitespace rules live in the root .editorconfig (LF line endings, 4-space indent for C#); fixtures and spikes are exempt. CI runs this on Ubuntu, and you can run the same command locally on a checkout with LF line endings:
Each --include folder needs its trailing slash. Without it the value is read as a file name, nothing matches, and the check passes without looking at a file.
Product benches: docs/perf/benchmark.md. The task-level A/B record, including the losses, is docs/perf/agent-eval.md. That record does not close the #528 publish gate.
This repo uses mattpocock/skills; see AGENTS.md and docs/agents/.
中文
面向 Agent 的 .NET MCP 服务器:C# / VB / F# 符号导航、源生成器归因、Avalonia/MAUI XAML、以及受限 Workspace Edit(rename / Diagnostic fix / Code Refactoring)。不是通用写文件、shell 或 LSP 代理。
NuGet 包 id 为 Skymly.DotNetMcp(命令名为 dnmcp)。必须通过 --roots、--roots=path 或 DOTNET_MCP_TRUSTED_ROOTS 配置受信根,不再默认使用进程工作目录。两者同时设置时取并集,而不是互相覆盖。配置缺失或空值时进程以退出码 1 结束,并在 stderr 写一行 JSON,而不是异常堆栈。workspace_open 会运行 MSBuild 与 analyzer/源生成器,不要对不受信任的仓库使用。
安装(NuGet 已上架,dnx 为首选;也可源码运行或本地 pack):
源码运行:
本地 pack:
Agent 接入:docs/agent-guidance.md 提供可直接粘贴到消费方 AGENTS.md / CLAUDE.md 的片段;服务器 initialize 结果携带相同的 instructions,并附带 trace_symbol / safe_rename 两个 prompt。
来源:README.md,提交 bd76691
工具
0版本历史
1- v5.0.1最新Nov 7, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分