Sharplens Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Sharplens Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
A Model Context Protocol (MCP) server providing 92 AI-optimized tools for .NET/C# semantic code analysis, navigation, refactoring, and code generation using Microsoft Roslyn.
Built for AI coding agents - provides compiler-accurate code understanding that AI cannot infer from reading source files alone.
dotnet tool install -g SharpLensMcpThen run with:
sharplensnpx -y sharplens-mcpdotnet build -c Release
dotnet publish -c Release -o ./publishdotnet tool install -g SharpLensMcp
# or
npx -y sharplens-mcp{
"mcpServers": {
"sharplens": {
"type": "stdio",
"command": "npx",
"args": ["-y", "sharplens-mcp"],
"env": {
"DOTNET_SOLUTION_PATH": "/path/to/your/Solution.sln (or .slnx)"
}
}
}
}Claude Code has native LSP support for basic navigation (go-to-definition, find references). SharpLensMcp adds deep semantic analysis:
| Capability | Native LSP | SharpLensMcp |
|---|---|---|
| Go to definition | ✅ | ✅ |
| Find references | ✅ | ✅ |
| Find async methods missing CancellationToken | ❌ | ✅ |
| Impact analysis (what breaks?) | ❌ | ✅ |
| Dead code detection | ❌ | ✅ |
| Complexity metrics | ❌ | ✅ |
| Safe refactoring with preview | ❌ | ✅ |
| Batch operations | ❌ | ✅ |
| Environment Variable | Description | Default |
|---|---|---|
DOTNET_SOLUTION_PATH | Path to a .sln, .slnx or .slnf file (or a directory holding exactly one) to auto-load on startup; the load runs beside the request loop, so initialize answers immediately | None (must call load_solution) |
SHARPLENS_ABSOLUTE_PATHS | Use absolute paths instead of relative | false (relative paths save tokens) |
SHARPLENS_LOG_LEVEL | Logging verbosity: Trace, Debug, Information, Warning, Error | Information |
SHARPLENS_TIMEOUT_SECONDS | Timeout for long-running operations | 30 |
SHARPLENS_MAX_DIAGNOSTICS | Maximum diagnostics to return | 100 |
SHARPLENS_ENABLE_SEMANTIC_CACHE | Cache the file-path to document lookup | true (set to false to disable) |
The pre-1.6.0 ROSLYN_* spellings of these variables are still read as a fallback; the SHARPLENS_* spelling wins when both are set. Boolean values are case-insensitive. A number that does not parse or is below its minimum falls back to the default, and one above its maximum is capped; each case logs a warning to stderr.
A project built for several target frameworks is one project to every tool: each result is reported once, with a targetFrameworks list where it exists only under some frameworks. projectName accepts the plain name (MyLib) for all frameworks, or a framework-qualified name (MyLib(net8.0)) for one.
If DOTNET_SOLUTION_PATH is not set, you must call the load_solution tool before using other tools.
Tool names no longer carry the roslyn: prefix — the colon violates the MCP tool-name pattern (^[a-zA-Z0-9_-]{1,64}$), which some clients enforce. Every tool keeps its name minus the prefix:
| 1.5.x name | 1.6.0 name |
|---|---|
roslyn:load_solution | load_solution |
roslyn:get_diagnostics | get_diagnostics |
roslyn:rename_symbol | rename_symbol |
| ...same rule for all tools... | drop the roslyn: prefix |
tools/list publishes only the new names. Calls using the old prefixed names are still accepted as aliases for one release and will be removed in the following one.
AI models may have trained bias toward using their native tools (Grep, Read, LSP) instead of MCP server tools, even when SharpLensMcp provides better capabilities.
To ensure optimal tool usage:
CLAUDE.md: For C# code analysis, prefer SharpLensMcp tools over native tools:
- Use `search_symbols` instead of Grep for finding symbols
- Use `get_method_source` instead of Read for viewing methods
- Use `find_references` for semantic (not text) referencesThe semantic analysis from Roslyn is more accurate than text-based search, especially for overloaded methods, partial classes, and inheritance hierarchies.
Important: SharpLensMcp maintains an in-memory representation of your solution for fast queries. When files are modified externally (via Edit/Write tools), the agent is responsible for synchronizing changes.
sync_documents:| Action | Call sync_documents? |
|---|---|
| Used Edit tool to modify .cs files | ✅ Yes |
| Used Write tool to create new .cs files | ✅ Yes |
| Deleted .cs files | ✅ Yes |
| Used SharpLensMcp refactoring tools (rename, extract, etc.) | ❌ No (auto-updated) |
| Modified .csproj files | ❌ No (use load_solution instead) |
# After editing specific files
sync_documents(filePaths: ["src/MyClass.cs", "src/MyService.cs"])
# After bulk changes - sync all documents
sync_documents()A full sync also picks up new .cs files the project's compile items include. SharpLensMcp's apply tools write only the files an edit changes, keep each file's encoding and line endings, and refuse with STALE_DOCUMENT when a target file changed on disk since it was read — run sync_documents, then retry. They also refuse with UNSUPPORTED_ENCODING to write a file whose bytes its encoding cannot reproduce (a BOM-less file that is not valid UTF-8 on a system whose fallback code page is UTF-8, such as Linux); save it as UTF-8 first.
This mirrors how LSP (Language Server Protocol) works - the client (editor) notifies the server of changes. This approach:
If you don't sync: Queries may return stale data (old method signatures, missing new files, etc.)
success/error/data format with suggestedNextTools| Tool | Description |
|---|---|
get_symbol_info | Semantic info at position |
go_to_definition | Jump to symbol definition |
find_references | All references; each classified read/write/invocation/cast/typeof/nameof/attribute; optional kind filter |
find_implementations | Interface/abstract implementations |
find_callers | Impact analysis - who calls this? |
get_call_graph | Multi-hop callers/callees graph with depth bound + cycle detection |
find_path_between | Reachability + the connecting call path(s) between two methods; follows dispatch, with barriers and a checkpoint |
get_type_hierarchy | Inheritance chain |
search_symbols | Glob pattern search (*Handler, Get*) |
semantic_query | Multi-filter search (async, public, etc.) |
get_type_members | All members by type name |
get_type_members_batch | Multiple types in one call |
get_method_signature | Detailed signature by name |
get_derived_types | Find all subclasses |
get_base_types | Full inheritance chain |
get_attributes | List attributes on a symbol |
get_containing_member | Enclosing symbol at position |
get_method_overloads | All overloads of a method |
find_attribute_usages | Find types/members by attribute |
get_external_type_info | Inspect NuGet/BCL/external assembly types — members + XML docs |
resolve_stack_trace | Map a pasted stack trace to file/line/symbol, mangling undone |
get_extension_methods | Extensions applying to a type — classic and C# 14 blocks |
get_documentation | Full XML docs for a symbol with <inheritdoc> expanded |
get_super_method | Navigate to the base member / interface members a member implements |
| Tool | Description |
|---|---|
get_diagnostics | Compiler errors/warnings + configured analyzer findings (StyleCop, Roslynator, NetAnalyzers); matches CI |
diff_api_surface | Public-API breaking-change report vs a git ref |
get_exception_flow | Which exceptions can escape a method, and where they're caught |
find_similar_code | Structural similarity search (token-shingle fingerprints) |
remove_unused_code | Compute dead-code removals + newly unused usings (generation-only) |
find_dead_branches | Unreachable basic blocks per method (real CFG, not heuristics) |
add_missing_imports | Compute the usings that fix CS0246/CS0103 (generation-only) |
analyze_data_flow | Variable assignments and usage |
analyze_control_flow | Branching/reachability |
analyze_change_impact | What breaks if changed? |
check_type_compatibility | Can A assign to B? |
get_outgoing_calls | What does this method call? |
find_unused_code | Dead code detection |
validate_code | Compile check without writing |
get_complexity_metrics | Cyclomatic, nesting, LOC, cognitive |
find_circular_dependencies | Project and namespace cycle detection |
get_missing_members | Unimplemented interface/abstract members |
| Tool | Description |
|---|---|
rename_symbol | Safe rename across solution |
change_signature | Add/remove/reorder parameters |
extract_method | Extract with data flow analysis |
extract_interface | Generate interface from class |
generate_constructor | From fields/properties |
move_type_to_file | Compute the contents to move a type into its own file (generation-only) |
split_type | Compute a partial-class split for selected members (generation-only) |
organize_usings | Sort and remove unused |
organize_usings_batch | Batch organize multiple files |
format_document_batch | Batch format files in project |
get_code_actions_at_position | All Roslyn refactorings at position |
apply_code_action_by_title | Apply any refactoring by title |
implement_missing_members | Generate interface stubs |
encapsulate_field | Field to property |
inline_variable | Inline temp variable |
extract_variable | Extract expression to variable |
| Tool | Description |
|---|---|
add_null_checks | Generate ArgumentNullException guards |
generate_equality_members | Equals/GetHashCode/operators |
generate_test_stub | Compilable test skeleton for a method (framework auto-detected) |
| Tool | Description |
|---|---|
get_type_overview | Full type info in one call |
analyze_method | Signature + callers + outgoing calls + location |
get_file_overview | File summary with diagnostics |
get_method_source | Source code by name |
get_method_source_batch | Multiple method sources in one call |
get_instantiation_options | How to create a type |
get_project_health | Composite audit dashboard: diagnostics + unused + coupling + coverage per project |
| Tool | Description |
|---|---|
find_god_objects | Detect over-coupled types via efferent + afferent coupling + member-count thresholds |
find_untested_code | Find public surface no test reaches — tests detected as xUnit, NUnit, MSTest, TUnit, Reqnroll and SpecFlow discover them, with setup, fixtures and step bindings |
find_tests | Which tests cover a symbol — the inverse of find_untested_code |
find_type_instantiations | Where a type is constructed (new T) |
find_pattern_usages | Where a type appears in is/as/pattern matches |
find_throw_sites | Where an exception type is thrown (optionally derived) |
find_catch_blocks | Where an exception type is caught (optionally via a base clause) |
find_async_issues | async void / blocking-on-async / unforwarded CancellationToken |
check_architecture | Enforce namespace/project dependency rules over the type graph |
find_naming_violations | Naming audit honoring .editorconfig rules, with conventional defaults |
| Tool | Description |
|---|---|
get_di_registrations | Scan DI service registrations |
find_reflection_usage | Detect reflection/dynamic usage |
find_interceptors | Surface [InterceptsLocation] call rerouting, generated code included |
| Tool | Description |
|---|---|
health_check | Server status + load fidelity (partial flag, declared-vs-loaded projects, loadFailures, loadWarnings, lastLoadFailure) — check without reloading |
find_unused_dependencies | PackageReferences/ProjectReferences the compiler never needs |
fix_all | Compute the fix for every instance of a diagnostic id (generation-only) |
load_solution | Load .sln/.slnx/.slnf; reports partial loads (partial + loadFailures: dropped projects, failed restores, projects loaded without references) and MSBuild warnings (loadWarnings) separately |
sync_documents | Sync file changes into loaded solution |
get_project_structure | Solution structure |
dependency_graph | Project dependencies |
get_code_fixes | Available fixes for a diagnostic |
apply_code_fix | Apply a specific code fix |
get_nuget_dependencies | NuGet package listing per project |
get_source_generators | List active source generators |
get_generated_code | View generated source code |
For MCP clients other than Claude Code, add to your configuration:
{
"mcpServers": {
"sharplens": {
"command": "sharplens",
"args": [],
"env": {
"DOTNET_SOLUTION_PATH": "/path/to/your/Solution.sln (or .slnx)"
}
}
}
}load_solution with path to .sln or .slnx file (or set DOTNET_SOLUTION_PATH)preview: trueMCP Client (AI Agent)
| stdin/stdout (JSON-RPC 2.0)
v
SharpLensMcp
- Protocol handling
- 92 AI-optimized tools
|
v
Microsoft.CodeAnalysis (Roslyn)
- MSBuildWorkspace
- SemanticModel
- SymbolFinderWhy does the tool target `net8.0` — can it analyze my .NET 9 / .NET 10 project?
Yes. net8.0 is the tool's own runtime floor — the Roslyn 5.x packages it builds on require it — not a ceiling on what it can analyze. RollForward lets the installed tool run on newer .NET runtimes, and MSBuildWorkspace loads each project's real target framework from its csproj, so one install analyzes solutions targeting .NET 8, 9, 10, and beyond.
public async Task<object> YourToolAsync(string param1, int? param2 = null,
CancellationToken cancellationToken = default)
{
EnsureSolutionLoaded();
// Your logic...
return CreateSuccessResponse(
data: new { /* results */ },
suggestedNextTools: new[] { "next_tool_hint" }
);
}ReadOnly flag (mutating tools pass ReadOnly: false and receive a destructiveHint annotation), and a handler that binds arguments through JsonRpcParameters and calls your method. The registry drives both tools/list and dispatch; there is no separate switch to edit. Two tests keep it honest: ToolsListGoldenTests locks the published schema byte-for-byte (re-capture the golden when a schema change is intentional), and ToolSchemaParityTests asserts every parameter the handler reads is declared in the schema.dotnet build -c Release
dotnet publish -c Release -o ./publishRoslynService method against a deterministic fixture, AND a wire test through the MCP dispatcher (in tests/SharpLensMcp.Tests/Mcp/) with exact value locks plus an error path. This is non-negotiable; see Testing.Every test must satisfy the Testing Charter (C1–C9) in tests/SharpLensMcp.Tests/TESTING.md — the standing contract. The headline rules:
(line, column) — never NotBeNull / > 0 / a type-only check as the sole assertion.Fixtures/*.cs fixture and a dispatcher (wire) test that unwraps content[0].text, plus an error path.error.Code / meta.TotalCount; the MCP wire yields camelCase. Read the casing your test's path actually produces.xunit.runner.json; fixture mutators always restore; the timeout test uses a forced-cancellation seam, not a timing race.StdioIntegrationTests value-pins one tool per category over the real binary and runs the tools/list golden over the stdio pipe.Run the suite:
dotnet test -c Release| File | Purpose |
|---|---|
src/RoslynService.cs + the src/RoslynService.*.cs partials | Tool implementations split by concern across ~30 partials (Navigation, Analysis, Refactoring, Inspection, Validation, TypeDiscovery, Discovery, ExternalApi, Quality, Metrics, CodeActions, CodeGeneration, Compound, CallAnalysis, ExceptionFlow, StackTrace, ApiSurface, SimilarCode, …) — each file's name predicts its contents |
src/McpServer.cs | MCP protocol mechanics: JSON-RPC parse loop, initialize negotiation, per-call timeout, in-band vs protocol error mapping |
src/ToolRegistry.cs + src/ToolDefinition.cs | The tool surface: one ToolDefinition record per tool (name, schema, ReadOnly flag, handler). Drives tools/list order and dispatch lookup |
src/JsonRpcParameters.cs + JsonRpcInvalidParamsException.cs | Typed JSON-RPC argument accessors and the -32602 Invalid params exception they raise |
src/*Data.cs / *Entry.cs records, ConstructorMember.cs, SignatureChange.cs | Typed records used by the audit composite, constructor generator, and signature-change parser (one type per file) |
MIT - See LICENSE for details. <!-- mcp-name: io.github.pzalutski-pixel/sharplens -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.