Let AI assistants like Claude safely refactor your C# codebase using the same Roslyn compiler platform that powers Visual Studio.
Roslyn MCP Server is a Model Context Protocol (MCP) server that exposes 62 Roslyn-powered tools to AI assistants and other MCP clients. It combines 36 refactoring operations, 5 code navigation tools, 6 analysis and metrics tools, 5 code generation tools, and 10 code conversion tools -- giving your AI deep code intelligence, comprehensive refactoring, and modern C# syntax transformations with full solution-wide reference tracking and preview support.
- Why RoslynMcpServer?
- Prerequisites
- Quick Start
- Standalone CLI
- Configuration
- Available Tools
- Preview Mode
- Troubleshooting
- NuGet Libraries
- Contributing
- License
- 62 tools -- refactoring, navigation, analysis, generation, and conversion tools, the most comprehensive Roslyn MCP server available
- Preview mode on every operation -- see exactly what will change before applying
- Atomic file writes with rollback -- if any file write fails, all changes are reverted
- Solution-wide reference updates -- renames and moves propagate across your entire solution
- Single command install --
dotnet tool install -g RoslynMcp.Server, no repo cloning needed - Cross-platform -- works on Windows, Linux, and macOS
Before installing, make sure you have:
- .NET 9.0 SDK or later -- Download here
- A C# solution (
.slnor.slnx) or project (.csproj) to work with
Verify your .NET SDK version:
dotnet --versionThe output should be 9.0.x or higher.
dotnet tool install -g RoslynMcp.ServerCreate a .mcp.json file in your project root (for Claude Code):
{
"mcpServers": {
"roslyn-refactor": {
"type": "stdio",
"command": "roslyn-mcp",
"args": []
}
}
}Then restart Claude Code or run /mcp to connect.
Ask Claude:
"Run the roslyn diagnose tool for my solution at C:/path/to/MySolution.sln"
You should see a health report with Roslyn version, MSBuild status, and workspace details.
Ask Claude:
"Rename the class UserService to AccountService in C:/path/to/MySolution.sln"
Claude will use the rename_symbol tool to rename the class and update every reference across your entire solution.
All 62 tools are also available as a standalone CLI for use in scripts, CI/CD pipelines, and terminals without an AI assistant.
dotnet tool install -g RoslynMcp.Cliroslyn-cli <solution-path> <tool-name> [--option value ...]
roslyn-cli <tool-name> --help
roslyn-cli --help# Check environment health
roslyn-cli C:/path/to/MySolution.sln diagnose --format text
# Rename a symbol across the entire solution
roslyn-cli C:/path/to/MySolution.sln rename-symbol --source-file C:/path/to/Foo.cs --symbol-name Bar --new-name Baz
# Get compiler diagnostics (errors only), pipe to jq
roslyn-cli C:/path/to/MySolution.sln get-diagnostics --severity-filter Error | jq '.data'
# Preview a refactoring without applying
roslyn-cli C:/path/to/MySolution.sln extract-method --source-file Foo.cs --start-line 10 --end-line 20 --method-name DoWork --previewOutput is JSON by default (pipeable to jq). Use --format text for human-readable output. Exit codes: 0=success, 1=tool error, 2=CLI error, 3=environment error.
Create .mcp.json in your project root:
{
"mcpServers": {
"roslyn-refactor": {
"type": "stdio",
"command": "roslyn-mcp",
"args": []
}
}
}Add to your claude_desktop_config.json:
{
"mcpServers": {
"roslyn-refactor": {
"command": "roslyn-mcp",
"args": []
}
}
}Config file locations:
| OS | Path |
|---|---|
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
All tools accept a solutionPath parameter (absolute path to a .sln, .slnx, or .csproj file). Refactoring tools also accept a preview parameter (set to true to see changes without applying them).
| Tool | Description | Key Parameters |
|---|---|---|
move_type_to_file |
Move a C# type declaration to a different file. Updates all references automatically. | sourceFile, symbolName, targetFile, createTargetFile |
move_type_to_namespace |
Change the namespace of a C# type. Updates all using directives and qualified references. | sourceFile, symbolName, targetNamespace, updateFileLocation |
rename_symbol |
Rename any C# symbol (type, method, property, field, variable, etc.) with automatic reference updates across the solution. | sourceFile, symbolName, newName, line, column, renameOverloads, renameFile |
rename_file_to_match_type |
Rename a source file so its name matches the primary type declared in it, without renaming the type or its references. | sourceFile, typeName, line, column |
rename_namespace |
Rename a C# namespace across the solution, updating declarations, using directives, and qualified name references. Does not move folders by default. | sourceFile, namespaceName, newName, line, column, updateFolders |
| Tool | Description | Key Parameters |
|---|---|---|
extract_method |
Extract selected code into a new method. Automatically detects parameters and return values. | sourceFile, startLine, startColumn, endLine, endColumn, methodName, visibility |
extract_variable |
Extract an expression to a local variable. | sourceFile, startLine, startColumn, endLine, endColumn, variableName, useVar, replaceAll |
extract_constant |
Extract a literal value to a named constant. | sourceFile, startLine, startColumn, endLine, endColumn, constantName, visibility, replaceAll |
extract_interface |
Extract an interface from a class's public members. | sourceFile, typeName, interfaceName, members, targetFile, separateFile |
extract_base_class |
Extract members (methods, properties, fields, and events) to a new base class. Field-like and accessor-style events move by name; a multi-variable event field moves only the selected declarator. Private events become protected on the new base. makeAbstract still only marks the new class abstract. |
sourceFile, typeName, baseClassName, members, targetFile, separateFile, makeAbstract |
pull_members_up |
Move selected members (methods, properties, fields, and events) from a derived type onto an existing base class or interface. Field-like and accessor-style events move by name; a multi-variable event field moves only the selected declarator. Private events become protected on the base. makeAbstract on a class target makes the event abstract and keeps an override on the derived type; interface targets keep the implementation on the derived type. |
sourceFile, typeName, members, targetBaseType, makeAbstract |
push_members_down |
Move selected members (methods, properties, fields, and events) from a base type down onto derived types. Field-like and accessor-style events move by name; a multi-variable event field moves only the selected declarator. leaveAbstract on a class source makes the event abstract on the base and adds an override on each derived type. |
sourceFile, typeName, members, targetDerivedTypes, leaveAbstract |
use_base_type |
Replace derived-type references with a compatible base type or interface. | sourceFile, typeName, targetBaseType |
introduce_field |
Turn a selected local variable or expression into a class field, optionally initializing it in a constructor. | sourceFile, startLine, startColumn, endLine, endColumn, fieldName, isReadonly, isStatic, initializeInConstructor, replaceAll |
safe_delete |
Delete a selected symbol only when it has no remaining references. If usages exist, reject with their locations. | sourceFile, startLine, startColumn, endLine, endColumn, symbolName |
make_static |
Make a selected instance method static when it does not use instance state. Adds the static modifier and updates call sites and method-group conversions to the containing type name. | sourceFile, startLine, startColumn, endLine, endColumn, symbolName |
make_non_static |
Make a selected static method an instance method when a valid instance receiver exists. Removes the static modifier and updates type-name call sites and method-group conversions to an instance receiver (or this in the same type). |
sourceFile, startLine, startColumn, endLine, endColumn, symbolName |
| Tool | Description | Key Parameters |
|---|---|---|
inline_method |
Inline a method by replacing call sites with the method body. Optionally remove the method. | sourceFile, methodName, line, column, callSiteLocation, removeMethod |
inline_variable |
Inline a local variable by replacing all usages with its initializer value. | sourceFile, variableName, line |
inline_constant |
Inline a const field by replacing references with a formatted literal. Optionally remove the constant. | sourceFile, constantName, typeName, removeConstant |
| Tool | Description | Key Parameters |
|---|---|---|
change_signature |
Add, remove, or reorder method parameters and update all call sites. | sourceFile, methodName, parameters (array of changes), line |
add_parameter |
Add a named parameter to a method and update call sites, overrides, and interface implementations. | sourceFile, methodName, parameterName, parameterType, defaultValue, position, line, column, updateOverrides, updateImplementations |
remove_parameter |
Remove a named parameter from a method and drop matching call-site arguments, updating overrides and interface implementations. | sourceFile, methodName, parameterName, line, column, force, updateOverrides, updateImplementations |
reorder_parameters |
Reorder a method's parameters by a 0-based permutation and update positional call-site arguments, updating overrides and interface implementations. | sourceFile, methodName, newOrder, line, column, updateOverrides, updateImplementations |
change_return_type |
Change a method's return type and update return statements when the conversion is safe, updating overrides and interface implementations. | sourceFile, methodName, newReturnType, line, column, updateOverrides, updateImplementations, convertReturnStatements |
encapsulate_field |
Convert a field to a property with backing field. | sourceFile, fieldName, propertyName, readOnly |
| Tool | Description | Key Parameters |
|---|---|---|
generate_constructor |
Generate a constructor that initializes fields and/or properties of a type (includeProperties: default true includes settable properties, false uses instance fields only unless members names a property; includeInheritedMembers: default false keeps this-type-only collection, true also collects accessible instance fields and, when includeProperties is true, settable properties declared on base types; replaceExisting: replace an existing constructor with the exact same signature instead of failing — optional-parameter / required-parameter ambiguity still fails; visibility: default public, also private / protected / internal / protected internal / private protected; structs/record structs reject the three protected forms; unsealed-record copy constructors must be public or protected (CS8878); copyConstructor: default false keeps today's one-parameter-per-member constructor, true generates a single same-type copy constructor that assigns each selected member from that parameter — derived records whose base is also a record include : base(other); classBaseCopy: default false keeps today's class copy-constructor shape, true (requires copyConstructor) emits : base((Base)other) on an ordinary class when the immediate base has an accessible Base(Base) copy constructor and does not reassign inherited members; callBase: default false keeps today's non-copy shape (no : base(...)), true emits : base(...) on an ordinary class or record class when an accessible immediate-base constructor's parameter types are a prefix of the generated constructor — conflicts with copyConstructor; record structs / structs ignore callBase). |
sourceFile, typeName, members, includeProperties, includeInheritedMembers, addNullChecks, replaceExisting, visibility, copyConstructor, classBaseCopy, callBase |
generate_property |
Generate a property on a type: auto-property { get; set; }, init-only { get; init; }, or a backing-field form when a field is the target (replaceExisting: default false keeps today's fail-on-clash; true removes the existing property of that name — including across partials — and inserts a freshly generated one; fields and methods of the same name are never removed; two same-named properties with no single target fail with NameCollision). |
sourceFile, typeName, propertyName, propertyType, fieldName, visibility, initOnly, replaceExisting |
generate_method_stub |
Generate a method from an undefined call site, inferring the signature from usage (throwNotImplemented: default true emits throw new NotImplementedException();; false uses default-return / empty void bodies via SyntaxGenerationHelper.CreateDefaultReturnBody; async Task / Task<T> unwrap so the body compiles; ref / ref readonly returns still throw; replaceExisting: default false keeps today's fail-on-clash; true removes a compatible ordinary method — same name, type-parameter arity, parameter count, parameter types in order, and RefKind — including across partials, then inserts a freshly generated stub; constructors, operators, local functions, explicit interface implementations, and accessors are never replaced; two compatible ordinary methods with no single target fail with NameCollision). |
sourceFile, line, column, methodName, returnType, visibility, generateAsync, throwNotImplemented, replaceExisting |
generate_overrides |
Generate override methods, properties/indexers, and events for base class virtual/abstract members (callBase: default true emits base.M(...) for non-abstract virtual methods and return base.Prop; / base.Prop = value; for non-abstract virtual properties and indexers (return base[i]; / base[i] = value;); abstract members still throw; events always use empty add/remove regardless of callBase; a cross-assembly protected internal event is emitted as protected (CS0507); internal / private protected events from another assembly are not generated; false uses default-return / empty bodies; replaceExisting: default false skips members this type already overrides; true also replaces those existing overrides — match methods by name + parameter types + RefKind, properties and events by name; two same-name existing overrides with no exact signature match fail with OverrideExists; new hiders / explicit interface implementations / non-override ordinary members are never replaced). |
sourceFile, typeName, members, callBase, replaceExisting |
implement_interface |
Generate interface member implementations for a type (indexers emit this[...] indexer declarations via CreateIndexerStub; ordinary properties stay on CreatePropertyStub; throwNotImplemented: default true emits throw new NotImplementedException();; false uses default-return / empty setter bodies; ref / ref readonly getters still throw; replaceExisting: default false keeps today's only-unimplemented members and MemberAlreadyImplemented when nothing is missing; true also replaces already-implemented interface members — methods by name + parameter types + RefKind, properties and events by name, indexers by Item / this[] / display forms; two same-name existing implementations with no exact signature match fail with NameCollision before any write; explicitImplementation still selects explicit vs ordinary public stubs; preview describes generate vs replace and writes nothing). |
sourceFile, typeName, interfaceName, explicitImplementation, members, throwNotImplemented, replaceExisting, preview |
implement_abstract |
Generate implementation stubs for unimplemented abstract members inherited by a selected class — methods, properties, indexers, and events (throwNotImplemented: default true emits throw new NotImplementedException();; false uses default-return / empty setter bodies; ref / ref readonly methods and getters still throw; events always use empty add/remove; a cross-assembly protected internal event is emitted as protected (CS0507); internal / private protected events from another assembly are not selected; replaceExisting: default false keeps today's only-unimplemented members and NoUnimplementedAbstractMembers when nothing is missing; true also replaces already-implemented abstract members — methods by name + parameter types + RefKind, properties and events by name, indexers by Item / this[] / display forms; two same-name existing implementations with no exact signature match fail with NameCollision before any write; new hiders / explicit interface implementations / non-override ordinary members are never replaced; preview describes generate vs replace and writes nothing). |
sourceFile, typeName, members, throwNotImplemented, replaceExisting, preview |
| Tool | Description | Key Parameters |
|---|---|---|
convert_to_async |
Convert a synchronous method to async/await pattern. | sourceFile, methodName, line, renameToAsync |
convert_expression_body |
Toggle between expression body (=> expr;) and block body ({ return expr; }). |
sourceFile, direction, memberName, line |
convert_to_block_body |
Convert a selected expression-bodied member (=> expr) to a block body. Methods become { return expr; } or { expr; } as appropriate; properties and accessors that are expression-bodied are converted too. |
sourceFile, memberName, line |
convert_property |
Convert between auto-property and full property with backing field. | sourceFile, direction, propertyName, line |
convert_foreach_linq |
Convert foreach loops with Add patterns to LINQ Select/Where expressions. | sourceFile, line |
convert_anonymous_to_class |
Convert an anonymous type (new { ... }) to a named class or record, replacing same-shape anonymous creations in the solution. |
sourceFile, line, newTypeName, column, asRecord |
convert_tuple_to_struct |
Convert a tuple ((int X, int Y) / (1, 2) / ValueTuple) to a named struct, replacing same-shape tuple creations in the solution. |
sourceFile, line, newTypeName, column |
convert_to_pattern_matching |
Convert if/is chains and switch statements to switch expressions. | sourceFile, line |
convert_to_interpolated_string |
Convert string.Format() calls and concatenation to interpolated strings. | sourceFile, line |
introduce_parameter |
Promote a local variable to a method parameter, updating all call sites. | sourceFile, variableName, line |
| Tool | Description | Key Parameters |
|---|---|---|
add_missing_usings |
Add missing using directives required to resolve unbound type references. Process a single file or all files in the solution. | sourceFile, allFiles |
remove_unused_usings |
Remove unused using directives. Process a single file or all files in the solution. | sourceFile, allFiles |
sort_usings |
Sort using directives alphabetically in a C# file. | sourceFile, systemFirst |
| Tool | Description | Key Parameters |
|---|---|---|
diagnose |
Check the health of the Roslyn MCP server environment and workspace status. | solutionPath (optional), verbose |
These read-only tools let you explore and understand your codebase without making changes. Use them to discover symbols, trace references, and inspect type information before refactoring.
| Tool | Description | Key Parameters |
|---|---|---|
find_references |
Find all references to a symbol across the entire solution. Returns file locations, context snippets, and write/definition indicators. | sourceFile, symbolName, line, column, maxResults |
go_to_definition |
Navigate to the source definition of a symbol. Supports partial classes with multiple definition locations. | sourceFile, symbolName, line, column |
get_symbol_info |
Get detailed metadata for any symbol: kind, accessibility, modifiers, base types, interfaces, members, parameters, return type, and XML documentation. | sourceFile, symbolName, line, column |
find_implementations |
Find all implementations of an interface or overrides of an abstract/virtual member. | sourceFile, symbolName, line, column, maxResults |
search_symbols |
Search for symbols by name pattern across the entire workspace. Filter by kind (class, method, property, etc.). | query, kindFilter, maxResults |
These tools analyze your code without making changes. Use them to understand code quality, data flow, and control flow.
| Tool | Description | Key Parameters |
|---|---|---|
get_diagnostics |
Retrieve compiler diagnostics (errors, warnings, info) filtered by severity and optionally by file. | sourceFile, severityFilter |
get_code_metrics |
Calculate code metrics: cyclomatic complexity, lines of code, maintainability index, class coupling, depth of inheritance. | sourceFile, symbolName, line |
analyze_control_flow |
Analyze control flow for a code region: start/end point reachability, return statements, and exit points. | sourceFile, startLine, endLine |
analyze_data_flow |
Analyze data flow for a code region: variables read/written inside, data flowing in/out, captured variables. | sourceFile, startLine, endLine |
find_callers |
Find all callers of a symbol across the entire solution. | sourceFile, symbolName, line, column, maxResults |
get_type_hierarchy |
Retrieve the type hierarchy (base types and/or derived types) for a given type. | sourceFile, symbolName, line, column, direction |
get_document_outline |
Get a hierarchical outline of all symbols in a file (namespaces, types, members). | sourceFile |
These tools generate new code members for existing types.
| Tool | Description | Key Parameters |
|---|---|---|
generate_equals_hashcode |
Generate Equals() and GetHashCode() overrides for a type based on its fields/properties (implementIEquatable: also add IEquatable<T> and typed Equals; generateOperators: also add == / !=; replaceExisting: replace existing equality members instead of failing; useHashCodeCombine: default true uses HashCode.Combine / builder, false uses unchecked prime-multiply; includeProperties: default true includes readable properties, false uses instance fields only unless fields names a property; callSuper: default false keeps member-only Equals/GetHashCode, true folds the immediate base type's equality into both methods; includeInheritedMembers: default false keeps this-type-only collection, true also collects accessible instance fields/properties declared on base types). |
sourceFile, typeName, fields, includeProperties, implementIEquatable, generateOperators, replaceExisting, useHashCodeCombine, callSuper, includeInheritedMembers |
generate_tostring |
Generate a ToString() override for a type (format: interpolated or stringbuilder; includeProperties: default true includes readable properties, false uses instance fields only unless fields names a property; includeInheritedMembers: default false keeps this-type-only collection, true also collects accessible instance fields/properties declared on base types; replaceExisting: replace an existing parameterless ToString instead of failing; callSuper: default false keeps member-only ToString, true folds the immediate base type's ToString into the generated override). |
sourceFile, typeName, fields, includeProperties, format, includeInheritedMembers, replaceExisting, callSuper |
format_document |
Format a C# file using Roslyn's built-in formatter. | sourceFile |
add_null_checks |
Add null-check statements (ArgumentNullException.ThrowIfNull or guard clauses) for method parameters. | sourceFile, methodName, line, style |
Every refactoring tool supports a preview parameter. When set to true, the tool computes and returns the changes that would be made without writing anything to disk. This lets you review diffs before committing to a refactoring.
Example (as a natural language prompt to Claude):
"Preview what would happen if I renamed OrderProcessor to OrderHandler in C:/path/to/MySolution.sln"
Claude will call rename_symbol with preview: true and show you the affected files and diffs.
If you see errors about the SDK not being found:
- Verify the SDK is installed:
dotnet --list-sdks - Make sure .NET 9.0 or later appears in the list
- If not, install it from https://dotnet.microsoft.com/download/dotnet/9.0
If MSBuild cannot be located or your solution fails to load:
- Make sure you can build the solution from the command line first:
dotnet build /path/to/MySolution.sln - On Windows, ensure Visual Studio Build Tools or a Visual Studio installation is available
- Check that
solutionPathis an absolute path to a valid.sln,.slnx, or.csprojfile
The diagnose tool is the first thing to try when something is not working. It reports:
- Whether Roslyn is loaded and its version
- Whether MSBuild was found and its version
- Whether the .NET SDK is available and its version
- Whether a given solution can be loaded, including project and document counts
Run it through Claude:
"Run the roslyn diagnose tool with verbose output for C:/path/to/MySolution.sln"
Or without a solution path to check just the environment:
"Run the roslyn diagnose tool"
In addition to the global tool, the project publishes libraries for building custom integrations:
# Core library -- refactoring operations and workspace management
dotnet add package RoslynMcp.Core
# Contracts library -- shared models and interfaces
dotnet add package RoslynMcp.ContractsContributions are welcome. See CONTRIBUTING.md for guidelines.
git clone https://github.com/JoshuaRamirez/RoslynMcpServer.git
cd RoslynMcpServer
dotnet build -c Release# All tests
dotnet test
# Specific test projects
dotnet test tests/RoslynMcp.Core.Tests
dotnet test tests/RoslynMcp.Server.Tests
dotnet test tests/RoslynMcp.Cli.TestsThis project is licensed under the MIT License. See the LICENSE file for details.
- Built with Roslyn -- the .NET Compiler Platform
- Implements the Model Context Protocol
- Issues: GitHub Issues
- Discussions: GitHub Discussions