mcp-guard is a Roslyn DiagnosticAnalyzer plus a small rule framework that runs at build time and in
the IDE. It targets netstandard2.0 so it loads in every supported build host, verified on the
.NET 8 SDK (Roslyn 4.8) and the .NET 10 SDK (Roslyn 5.0).
For every [Description] attribute in the compilation,
McpToolDescriptionAnalyzer:
- Gates to the MCP surface — keeps only strings the model actually reads:
[Description]on an[McpServerTool]/[McpServerPrompt]/[McpServerResource]member, one of its parameters, or an[McpServer*Type]type, plus theName = "..."of those members. Ordinary[Description]usage is ignored, which keeps false positives near zero. MCP attributes are matched by name, so the analyzer does not require the MCP SDK to be resolvable. - Extracts the text — attribute arguments are compile-time constants, so the semantic model's
constant value covers plain, verbatim, and raw string literals plus
constconcatenation (McpDescriptionExtractor). - Runs the rule set — each rule inspects the extracted text and reports its own diagnostic.
A rule is a small class deriving from
McpDescriptionRule: it owns its
DiagnosticDescriptor and a single Analyze method, and is a stateless singleton registered in the
analyzer's RuleSet. Adding a rule does not touch the orchestration; see
CONTRIBUTING.
Detection logic lives in dedicated, testable helpers (e.g. ToolDescriptionPhrases,
HiddenCharacters, SecretArtifacts, ExfiltrationCues) so the rules stay thin.
mcp-guard only sees source at build time, so it covers the static half of MCP defense: description and metadata content. Runtime guards (rug pulls, tool shadowing, live exfiltration) are out of scope by design; see the threat model.
The analyzer ships as McpGuard.Analyzers, a development dependency whose DLL is packed into
analyzers/dotnet/cs/ (no lib/), so Roslyn auto-loads it for both IDE squiggles and command-line
build warnings. It declares no package dependencies. Microsoft.CodeAnalysis.CSharp is pinned to the
oldest supported host (4.8.0); referencing a newer Roslyn would stop the analyzer loading on older
build hosts.