
C# Class Analyzer MCP
io.github.undy-mosq由 GitHub 账号 undy-mosq 发布v1.0.4更新于 Oct 24, 2026
A read-only MCP server that lets an AI assistant browse any C# solution through Roslyn.
概览
只读 MCP 服务器,通过 Roslyn 加载 C# 解决方案,让助手列出类型、读取文档与方法体并追踪继承关系。
- 可以做什么
- 按文件夹或命名空间列出类型声明,可按 class、interface、record、enum 等种类筛选
- 根据类型声明行读取其 XML 文档、签名与成员列表
- 根据声明行读取方法的签名、文档、位置与方法体,每个重载一个区块
- 以缩进树形式追踪派生类型以及方法重写或接口实现
- 用正则表达式逐行搜索文件,默认只搜 C# 文件
- 重新加载缓存的解决方案快照,或更改相对路径的基准目录
- 适用场景
- 适合助手处理 C# 代码库时,只取所需的类型或方法,而不必把整个文件读入上下文。适用于代码导航、影响面分析和继承层次查询,前提是解决方案已在本地磁盘上。
- 运行要求
- 以 .NET 工具(CSharpAnalyserMcp)通过 stdio 在本地运行,或用 dnx 按需运行。需要 .NET SDK 8.0 或更高版本,使用 dnx 时需 SDK 10.0 或更高版本,以及能打开该解决方案的 MSBuild 工具链(Visual Studio 2022、VS Build Tools,或 SDK 自带的 SDK 风格项目支持)。解决方案路径在启动时通过 --workspace 参数传入;无需账号、密钥或请求头。
安装
在 SourceWeft 中
- 打开 控制台中的 C# Class Analyzer MCP,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
English | 简体中文
CSharpAnalyserMcp
A read-only Model Context Protocol (MCP) server that lets an AI assistant browse any C# solution through Roslyn.
The server loads a solution with MSBuildWorkspace into a cached Roslyn snapshot and then answers structured queries about it: where each type is declared, its XML documentation, and a method's signature, documentation, source location and body. An agent can therefore pull in the exact slice of source it needs instead of reading whole files into its context window.
- Transport: stdio (
StdioServerTransport), protocol traffic on stdout only; all logs go to stderr. - Solution path is passed on the command line (
--workspace <path to .sln>); the solution is loaded before the MCP handshake, so a bad path fails fast with a message on stderr and a non-zero exit code. - Every tool returns MCP text content and never
structuredContent: listing / hierarchy / search tools return one text block per entry (a string list from the client's point of view), while detail tools emitpath / desc / namespace / signature / bodyblocks separated by a line containing---. - Distribution: published to NuGet as the .NET tool CSharpAnalyserMcp (command
csharp-analyser-mcp) and listed in the official MCP Registry asio.github.undy-mosq/CSharpAnalyserMcp.
Installation
NuGet .NET tool (recommended)
Install it globally: a --local install only writes a manifest entry, so csharp-analyser-mcp never lands on PATH and MCP clients cannot start it.
On demand with dnx (nothing to install, .NET SDK 10+)
From source
Requirements
Client configuration
The server is started with a single argument, --workspace, pointing at the solution file.
Installed .NET tool
The global tool shim lives in %USERPROFILE%\.dotnet\tools. MCP clients spawn the process themselves and only see the PATH they inherited, so point the configuration at the shim by absolute path (expand %USERPROFILE%, e.g. C:\Users\you\.dotnet\tools\csharp-analyser-mcp.exe):
Claude Desktop (claude_desktop_config.json):
VS Code (.vscode/mcp.json):
The bare command name ("command": "csharp-analyser-mcp") works only when that directory is already on the client's PATH; a client started before the tool was installed keeps the old environment, so restart it after changing PATH.
On demand with dnx (nothing installed)
Append @<version> to the package id to pin a version. The MCP Server tab of the NuGet package page offers the same JSON for copying. dnx is a .cmd shim; if the client cannot spawn it, use the equivalent dotnet form instead: "command": "dotnet" with "args": ["tool", "exec", "CSharpAnalyserMcp", "--yes", "--", "--workspace", "D:\\MyProject\\MySolution.sln"].
Published executable
VS Code (.vscode/mcp.json):
Running the project from source
Press F5 in VS Code to debug the server itself; .vscode/launch.json already passes a --workspace argument — point it at your own solution.
Tools
list_classes_in_folder
Files under bin/obj are skipped. Returns a string list, one text content per type, formatted as {relativePath} L{start}-{end} {namespace}: {signature}; the namespace segment is omitted for the global namespace, and a partial type reports the location of its first declaration plus a trailing ...(partial xN).
list_classes_in_namespace
get_class_documentation
On a match the result is a text block: path / desc / namespace (the global namespace prints as global) / signature / body (member signatures, one per line); multiple matches are separated by a line containing ---. A miss prints (no match) followed by candidates : and candidate declaration lines.
get_method
Matching rules:
- Both declaration lines must match the canonical signature or the first source line of the declaration exactly after whitespace is stripped (no substring matching).
- Only members declared by the type itself are searched (ordinary methods; no inherited members, constructors or properties). Explicit interface implementations (
IFoo.Bar) are matched too. - Parameter types parsed from the declaration line are compared case-insensitively and whitespace-insensitively, without namespace prefixes; C# aliases are mapped to their metadata names (
int→Int32,string→String, …). The comparison is relaxed step by step: exact → ignoring generic arguments → allowing a prefix of the parameter list. - When nothing matches,
(no match)is printed followed bycandidates :and candidate declaration lines (same-named methods of that type first, otherwise every method of that type).
The result is a text block per overload: path / desc (raw XML docs, 2000-char cap) / namespace / class / signature / body (source with the outermost braces and the common indentation removed); overloads are separated by a line containing ---.
find_inheritance
The first entry is the queried type itself (no indentation, no prefix); every derived type follows as its own text content, indented by one tab and prefixed with - per hierarchy level. A class root reports the classes / records deriving from it; an interface root reports sub-interfaces plus the classes / structs / records implementing it directly. Generic base types are matched by OriginalDefinition (Base<T> and Base<int> count as the same base). Each type appears once, at its shallowest depth; a miss returns (no match) followed by candidates : and candidate declaration lines.
find_method_overrides
The first entry is the method itself; implementations / overrides follow as their own text contents, indented by one tab and prefixed with - per hierarchy level. An interface member root reports the implementing methods in every implementing type (including explicit IFoo.Bar implementations); a class method root reports the overrides in derived classes. Only the downward direction is reported — base declarations are not walked upwards. A miss returns (no match) followed by candidates : and candidate declaration lines.
search_regex
- A directory is searched recursively;
bin/obj/.gitand symlinked directories are skipped. A file path is searched directly. - Every match is one text content:
{relativePath} L{line}: {line text}(line text trimmed). - At most 1000 matches; when truncated, a final
... [truncated: showing 1000 of N matches]entry is appended. - Reads the files on disk, so it is not affected by the Roslyn snapshot /
reload_solution. - A missing path or an invalid regex returns
isErrorwith the reason in the text; no matches returns(no match).
reload_solution
No parameters. Discards the cached snapshot and re-opens the solution, so later queries see the current files on disk. Prints solution / resolveBaseDirectory / projects / reloaded : true ({ms} ms).
set_resolve_base_path
Type kinds and kinds
kind is lowercase and mutually exclusive: class, static class, record, struct, record struct, interface, enum, delegate. Only classes can be static, so class and static class are distinct; structs, enums, interfaces and delegates have no static form.
The kinds filter is case-insensitive and accepts multiple values (an omitted kinds behaves like ["class"]):
The same table, the declaration-line protocol (strict matching of typeDeclaration / methodDeclaration plus candidates recovery) and the text output shapes are all sent to the client as server-level instructions during the initialize handshake (see Tools/ServerInstructions.cs), so the model does not have to guess the accepted values or the output format.
Output format
Every tool returns MCP text content and never structuredContent. Listing / hierarchy / search tools return one text content per entry, so the client receives a list of strings instead of a single newline-joined block. Paths are shown relative to the resolve base directory (default: the solution's directory), using / as separator.
Listing (list_classes_in_folder / list_classes_in_namespace)
Each type is one text content (the tool returns a string list):
The namespace segment is omitted for the global namespace (only the : remains); a partial type shows the location of its first declaration plus a trailing ...(partial xN); a miss returns a single (no match) item.
Type detail (get_class_documentation)
One block per same-named type, blocks separated by a line containing ---:
Method detail (get_method)
One block per overload, blocks separated by a line containing ---:
No match prints (no match) followed by candidates : and candidate declaration lines (brief-line format, ready to copy into the declaration parameter):
Hierarchy (find_inheritance / find_method_overrides)
The first entry is the queried type / method itself (no indentation, no -); derived types / implementations follow as their own text contents, indented by one tab and prefixed with - per hierarchy level:
No match returns a single (no match) item; candidates, when any, follow as candidates : and the candidate declaration lines.
Regex search (search_regex)
Every match is one text content:
No match returns a single (no match) item; above 1000 matches a final truncation entry is appended.
Workspace (reload_solution / set_resolve_base_path)
Output limits
Long payloads are truncated to keep tool results small; the appended marker reads ... [truncated: showing {n} of {m} chars]. All thresholds live in Services/TextTruncator.cs.
Passing 0 to maxXmlChars / maxBodyChars disables truncation for that call.
Typical workflow
- Start the server once with
--workspacepointing at your solution (an MCP client does this for you). - Discover types:
list_classes_in_namespace { "namespaceName": "MyApp.Services" }orlist_classes_in_folder { "folderPath": "src/Services", "kinds": ["all"] }; to find a specific string, usesearch_regex { "path": "src", "pattern": "..." }. - Read a type's contract by copying its declaration line from the listing:
get_class_documentation { "typeDeclaration": "public class UserService : BaseService" }. - Read the exact implementation:
get_method { "methodDeclaration": "public User GetById(int id)", "typeDeclaration": "public class UserService : BaseService" }. - Walk the hierarchy:
find_inheritance { "typeDeclaration": "public abstract class UserServiceBase" }orfind_method_overrides { "methodDeclaration": "public abstract User GetById(int id)", "typeDeclaration": "public abstract class UserServiceBase" }. - After the source files change, call
reload_solutionbefore the next query — otherwise queries keep answering from the stale snapshot.
Troubleshooting
- The server exits immediately with
Solution file not found(or another MSBuild error) on stderr → the--workspacepath is wrong; it must point at the solution file, not at a folder. The command "dnx" was not foundin the client's MCP log →dnxships with the .NET SDK 10 and newer. Install .NET SDK 10, or use an installed tool or the published executable instead.dotnet tool installreports that the package is not a .NET tool → the version you asked for was packed beforePackAsToolwas enabled; install the current version instead (dotnet tool list --globalshows what is installed).spawn csharp-analyser-mcp ENOENTorMCP error -32000: Connection closedin the client log → the client could not resolve the command it was told to run. Use the absolute path to%USERPROFILE%\.dotnet\tools\csharp-analyser-mcp.exe(a--localinstall has no shim there at all) and restart the client.Cannot find package CSharpAnalyserMcp with version x.y.zright after a release → NuGet's index can lag behind the release. Retry later, or install from the downloaded.nupkg:dotnet tool install -g --add-source <folder> CSharpAnalyserMcp --version x.y.z.
Behavior notes and limitations
- Snapshot semantics. The solution is read once from disk; file edits become visible only after
reload_solution. Unsaved editor buffers are never visible. - Regex search reads the disk.
search_regexreads files directly, bypassing the Roslyn snapshot; it searches*.csby default, skipsbin/obj/.gitwhile recursing, and returns at most 1000 matches. - Source-only view. Syntax trees under
bin/objare skipped, so types without source declarations are not reported. - Declared members only.
get_methoddoes not walk base types, interfaces or the other parts of apartialtype. - Exact names. Type and method names must match exactly; namespaces are compared as full display strings. Use
namespaceName(or a qualifiedclassName) to disambiguate. - Cost. Every query asks each project for its compilation, so response time grows with solution size.
- Diagnostics. Workspace load problems are written to stderr as
[WorkspaceFailed] {Kind}: {Message}; nothing but JSON-RPC ever reaches stdout. - One solution per process. The workspace path is fixed at startup; start another instance to analyse another solution.
License
MIT — see LICENSE.
Building, publishing and the release process: docs/DEVELOPMENT.zh-CN.md (中文).
来源:README.md,提交 765ee35
工具
0版本历史
3- v1.0.4最新Oct 23, 2026
- v1.0.3Oct 4, 2026
- v1.0.2Sep 30, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分