resharper-cli-mcp
resharper-cli-mcp is an MCP server that gives a C# coding agent ReSharper's solution-wide inspections (resharper_inspect) and its code cleanup (resharper_cleanup). It wraps JetBrains' jb, managing its cache and returning LLM-friendly markdown sized to a context window. It is unofficial — not affiliated with or endorsed by JetBrains. The server shells out to a jb you install yourself and bundles no JetBrains software.
What the server adds
jb is built for a batch job: one run against one checkout, a report written to a file. An agent hits the same solution several times an hour, and what each call costs comes down to whether ReSharper's solution-wide index is already built. So the server owns the cache directory and runs a lifecycle over it:
-
The first run happens before you ask for it. A speculative inspection starts as soon as a client connects, skipped when a run against that cache succeeded in the last hour; a tool call arriving mid-pass cancels it and takes the cache within a second or two.
RESHARPER_MCP_PREWARM=offturns it off. -
Runs are serialized per solution. A cross-process lock keeps every client on one cache generation; a second concurrent
jbforks a cold copy of its own and leaves it behind on disk. Ajbyou start yourself is outside that queue, so give it its own--caches-home. -
A fresh checkout is seeded from a warm one. Caches are keyed to the solution's absolute path, so a new worktree or clone starts cold. When a call finds no cache and a same-named sibling checkout has a warm one, the server copies it across, best-effort and never over a cache a successful run produced. The copy still has to be re-keyed, so a seeded run lands between warm and cold.
-
SARIF becomes markdown that fits the client. Issues come back grouped by file, re-rendered at progressively lower detail until they fit the client's output budget, with every issue still counted and every file still named at each step.
detailcaps that ladder when you want a rollup without overflowing the budget to get one. When the summary is not enough,report=Markdownwrites the complete listing to a file and the response names it.
Quickstart
The server needs the .NET 10 SDK and JetBrains' ReSharper Command Line Tools. Both install as .NET global tools, and neither needs an IDE.
dotnet tool install -g JetBrains.ReSharper.GlobalTools
dotnet tool install -g Zphil.ReSharperCli
The server looks for jb on PATH and then in ~/.dotnet/tools. An MCP client often starts the server without your shell's PATH, so a jb that answers in your terminal can still be invisible to it.
Register the server with your MCP client under the command resharper-cli-mcp. For Claude Code, add it to .mcp.json:
{
"mcpServers": {
"resharper": {
"command": "resharper-cli-mcp"
}
}
}
The server finds a single .sln/.slnx in its working directory; when that directory holds zero or several, set JB_SOLUTION_PATH in the config's env block.
llms-install.md is the same setup written as a checklist, with the configuration block for each of the common clients. Point an agent at it to have the server installed for you.
VS Code, Visual Studio, Cursor and LM Studio can add the server in one click, once both tools are installed:
Other clients
Every client runs the same command, resharper-cli-mcp, with no arguments. Only the file and the key around it change.
Visual Studio
Visual Studio 2022 17.14 and later, and Visual Studio 2026, read an .mcp.json beside the solution, so a checked-in file registers the server for everyone working on it. The top-level key is servers, and the transport is named:
{
"servers": {
"resharper": {
"type": "stdio",
"command": "resharper-cli-mcp"
}
}
}
Rider and Junie
Junie reads ~/.junie/mcp/mcp.json for every project, or .junie/mcp/mcp.json for one. Rider's AI Assistant takes the same JSON under Settings | Tools | AI Assistant | MCP:
{
"mcpServers": {
"resharper": {
"command": "resharper-cli-mcp"
}
}
}
Running the server alongside a JetBrains IDE means two ReSharper engines over one solution, each with its own cache. Point one of them elsewhere with JB_CACHE_HOME if disk use matters.
Codex CLI
codex mcp add resharper -- resharper-cli-mcp
Cline
Cline stores its servers in cline_mcp_settings.json, which the MCP Servers panel opens under Configure MCP Servers:
{
"mcpServers": {
"resharper": {
"command": "resharper-cli-mcp"
}
}
}
Install as a Claude Desktop extension
Claude Desktop installs local MCP servers as MCP Bundles. Download resharper-cli-mcp-<version>.mcpb from the latest release, double-click it, and set Solution file to the .sln or .slnx you want analysed. Claude Desktop starts the server outside your repository, so there is no working directory for it to discover one in. Run cap sets how long one jb run may take before the server kills it; ten minutes by default, which a first run against a large solution can exceed.
The bundle holds the server and neither of its prerequisites. Install the .NET 10 runtime and the ReSharper Command Line Tools first, as under Quickstart: the bundle launches the server with dotnet, and every tool call shells out to jb.
Install as a Claude Code plugin
This repository doubles as a single-plugin marketplace, so the tools, the derive_style_guide prompt, and both guide resources arrive in one step:
/plugin marketplace add andypgray/resharper-cli-mcp
/plugin install resharper-cli-mcp@resharper-cli-mcp
The plugin starts the server with dotnet dnx, which fetches a pinned Zphil.ReSharperCli version from NuGet on first use. The marketplace commit you install therefore determines the server you run. Each release moves that pin, so run claude plugin update resharper-cli-mcp@resharper-cli-mcp to pick up a newer server. You still need the .NET 10 SDK and the ReSharper Command Line Tools; ReSharper's caches live in the plugin's own data directory, outside your source tree.
Tools
| Tool | Mutates files | What it does |
|---|---|---|
resharper_inspect | no | Runs ReSharper InspectCode and returns the issues, grouped by file. |
resharper_cleanup | yes | Runs ReSharper CleanupCode to reformat and normalize the given files in place. |
resharper_reset_cache | no (deletes caches) | Drops the solution's ReSharper cache so the next run rebuilds its analysis from cold. |
Scope resharper_inspect with the files glob (entries may be solution-relative or absolute) and raise severity (Suggestion, Warning, Error; default Warning) to control how much comes back. Each issue carries a file, line, severity, rule ID, and message:
Found 2 issue(s) across 1 file(s):
### /repo/src/HomeController.cs
- **Line 8** [WARNING] `RedundantUsingDirective`: Using directive is not required by the code and can be safely removed.
- **Line 24** [SUGGESTION] `FieldCanBeMadeReadOnly.Local`: Field can be made readonly.
A solution-wide sweep lands on the reduced rendering by construction, which collapses issues repeating a rule within a file to one example message. To work through findings one at a time, pass report=Markdown: resharper_inspect writes every issue with its own message to a file under the system temp directory, names that file at the top of its response, and deletes it after seven days. It is off by default, and markdown is the only format — jb writes one report per run and this server needs the SARIF to build the summary. detail runs the other way, naming the most detailed level the response may use, from Full down to a one-line Minimal; it caps rather than pins, so the response still steps lower to fit, and the note says which of the two happened. detail=Minimal report=Markdown surveys a legacy solution in a single call.
resharper_cleanup changes style, never behavior: formatting, using directives, var style, modifier order, redundant qualifiers and parentheses, braces. Write correct logic and let cleanup do the polish: call it once, at the end of a task, with every changed file batched into the one call. It reports which files it actually changed on disk.
For a legacy codebase where the fallback Built-in: Full Cleanup profile would churn code you did not touch, define a narrower profile (for example Custom: No Reordering) in the solution's .sln.DotSettings and name it under SilentCleanupProfile. Every call then uses it, including calls from an agent that does not know it exists.
Run times
Each run is capped at 10 minutes; RESHARPER_MCP_TIMEOUT_SECS moves the cap. Narrowing a call with files will not make it finish sooner: resolving symbols across projects takes the whole solution model, so files decides what is reported, not how much is analysed. When an MCP client's own tool-call timeout is shorter than a cold run needs, the client gives up first; in Claude Code, raise it with a per-server "timeout" in .mcp.json or MCP_TOOL_TIMEOUT. The resharper://guides/setup resource carries all of this at troubleshooting depth, for an agent to pull when a call cannot find jb, times out, or comes back shortened.
A run in flight reports itself every ten seconds as an MCP progress notification: first the wait for another run on the same cache, then the cache state jb opened, then a running count of the files it has analysed, each with the elapsed time and the cap. That last one is what tells a slow run from a hung one, and a caller watching "8 minutes 2 seconds, cap 10 minutes" can raise RESHARPER_MCP_TIMEOUT_SECS before the call fails rather than after. Notifications go only to a client that asks for progress by sending a progressToken with the call; one that does not gets the same result and no notifications.
Configuration
Set these in the MCP client config's env block. All are optional. Each JB_ variable becomes something jb itself is told; the RESHARPER_MCP_ ones govern this server's own behaviour and never reach jb.
| Variable | Purpose |
|---|---|
JB_SOLUTION_PATH | Solution to use when the working directory has zero or several; the solutionPath tool argument overrides it for one call. |
JB_SETTINGS_PATH | Explicit .DotSettings file for jb, mounted as a Custom layer above the solution's and every project's own settings. |
JB_CACHE_HOME | ReSharper cache directory (default ~/.jb-cache). |
JB_EXTENSIONS | Semicolon-separated ReSharper plugin IDs to load. |
JB_EXTENSION_SOURCE | Custom NuGet source for those plugins. |
RESHARPER_MCP_TIMEOUT_SECS | Cap in seconds on one jb run, and on the wait for one already in flight (default 600, clamped to 60–86,400). |
RESHARPER_MCP_PREWARM | off disables the background cache pre-warm above. |
RESHARPER_MCP_LOG_LEVEL | Level for the rolling file log (default Warning). |
MAX_MCP_OUTPUT_TOKENS | Client output budget the reduction ladder renders to fit (2.5 characters per token; 25,000 characters when unset). |
Solution discovery tries, in order: the solutionPath argument, JB_SOLUTION_PATH, then a single .sln/.slnx in the working directory (top level only, no parent walk).
Settings discovery tries, in order: JB_SETTINGS_PATH, a .DotSettings file beside the solution, then GlobalSettingsStorage.DotSettings in the JetBrains shared directory. jb mounts the last two on its own, so the server passes --settings only for a JB_SETTINGS_PATH outside them (naming an already-mounted file would demote every project's own .DotSettings). On top of whichever settings apply, jb reads .editorconfig from the source tree automatically.
Logs roll daily under %LOCALAPPDATA%\Zphil.ReSharperCli\logs on Windows, and the platform-equivalent path elsewhere.
What ReSharper enforces
resharper_inspect obeys inspection severities (what gets reported); resharper_cleanup enforces code style through its cleanup profile (what gets rewritten). The two axes do not share a switch: setting a rule to DO_NOT_SHOW hides its issue, and cleanup goes on normalizing that style. The full model ships as an on-demand MCP resource, resharper://guides/configuration, for an agent to pull just before changing what ReSharper enforces.
For an existing codebase the derive_style_guide MCP prompt walks an agent through deriving an intentional style guide from the code you already have, .editorconfig-first, with ReSharper-only knobs spilling into .sln.DotSettings. If you have access to Resharper or Rider, JetBrains' first-party Detect Code Style Settings is the better baseline; the prompt is the path for headless use.
Cleanup reminder hook
The single end-of-task cleanup is easy for an agent to forget. This Claude Code PostToolUse hook appends a one-line reminder to the agent's context after each .cs/.razor edit; it never edits code or calls the tool itself, so the agent decides when to clean up. Add it to .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "grep -qiE '\"file_path\"[[:space:]]*:[[:space:]]*\"[^\"]*\\.(cs|razor)\"' && printf '%s' '{\"hookSpecificOutput\":{\"hookEventName\":\"PostToolUse\",\"additionalContext\":\"When this task is done, batch every edited .cs/.razor file into one resharper_cleanup call.\"}}' || true"
}
]
}
]
}
}
The command uses grep and printf, so it needs a POSIX shell (on Windows, Git Bash).
Privacy Policy
resharper-cli-mcp collects nothing. It has no telemetry, no analytics, no accounts and no remote logging, and it makes no network calls of its own. Every tool call shells out to the jb on your machine, and the issues and cleanup summaries it produces go back over stdio to the MCP client that launched the server.
The diagnostic log described under Configuration is the only thing written to disk. It keeps 7 daily files and can contain absolute paths and the rule IDs and messages read from your solution. It stays on the machine, and deleting it at any point is safe.
PRIVACY.md is the full policy: what is collected, how your source code is processed, the local logs and how long they are kept, the two network paths around the server, and where to ask about it.
Contributing
Contributions are welcome. Bug reports reproduced on a public solution, MCP client-compatibility fixes, and improvements to discovery or output formatting land best. See CONTRIBUTING.md for the development setup (.NET 10 SDK) and the two-seam test architecture. To report a security issue privately, see SECURITY.md.
License
MIT; see LICENSE.
JetBrains and ReSharper are trademarks of JetBrains s.r.o. This project is an independent wrapper of their ReSharper Command Line Tools, which ship under JetBrains' own license.