Skip to content
Roslyn Bridge MCP

Usage

Ask your agent to use the roslyn Model Context Protocol (MCP) server.

Example usage:

Use Roslyn to report diagnostics for src/Calculator.cs, find its implementations,
and preview a rename. Do not apply changes.

The bridge reads saved files and loads the project independently of your editor. Available fixes and refactorings depend on the installed Roslyn version and project.

Tools

Tool Arguments Result
diagnostics file path or glob, severity, ids, summary Errors, warnings and suggestions
navigate action (definition, type_definition, implementation, references, reads, writes, callers, callees, supertypes, subtypes, hover, source, members, impact), and symbol or file, line, character Locations, related symbols, hover text, source or members
bulk_navigate queries (1 to 16 items, each with the action and the symbol or file, line, character of navigate), context, limit, offset One section per query
symbols file or query Document or workspace symbols
edit action (rename, rename_file, code_actions) and its inputs Edit previews, then applied changes
lsp action (status, capabilities, reload, request), method, parameters Session state, a fresh session or a raw Language Server Protocol (LSP) result

diagnostics, navigate, bulk_navigate and symbols are read-only. edit and lsp can write files. Each tool takes flat arguments:

{ "action": "definition", "file": "src/Calculator.cs", "line": 12, "character": 9 }

An unknown or missing argument returns the error invalid_request. For an unknown argument, the message lists the valid names. An array argument, such as queries of bulk_navigate, may also be sent as a JSON string.

navigate and edit accept a symbol name instead of a position, for example Calculator.Add. The name matches the end of the fully qualified name. A parameter list selects an overload, as in Calculator.Add(int, int).

Generic arguments are optional unless a generic and a non-generic type share the name. A parameter type also matches its nullable form.

A constructor needs its parameter list. An ambiguous name returns the error ambiguous_symbol with up to 20 candidates, one per line. Send any candidate symbol back unchanged. When candidates share a name, send the symbol with the candidate’s file. An unknown name returns the error symbol_not_found. When symbols with a similar name exist, it lists up to 10 of them as candidates, which you can also send back unchanged.

Unknown name Error
Container of a qualified name not found, as in Nope.Missing Says that no type matches the container, and names up to 10 types with a similar name. Each type is named once.
Container found, as in Calculator.Missing Says that the type has no such member, and lists its members with a similar name. Without any, it points to members.

Paths are relative to the workspace. Input coordinates start at 1, with characters counted as UTF-16 code units. Only raw requests keep zero-based LSP positions.

When no file has the given path, a file may be a file name or a path suffix, such as Calculator.cs or Math/Calculator.cs. It must match whole path segments and name exactly one workspace file. The response then starts with a resolved file: path line. When several files match, the error ambiguous_file lists up to 20 of them. In bulk_navigate, it fills the section of each query that names the file, and the other queries run. This applies to file of navigate, bulk_navigate, symbols and edit, and to file of diagnostics without glob characters. It does not apply to newName.

Results

Results are compact text lines, with positions written line:character. Failed calls start with error CODE: message and set isError. Raw requests and capabilities return JSON.

Action Result
definition, type_definition, implementation, references One line per file with its positions. references leaves out source-generated code and counts the omitted occurrences.
reads, writes The references that read or write a field, property, local, parameter or event, in the format of references. An empty result reads no reads or no writes.
callers, callees, supertypes, subtypes One line per symbol: its declaration, its kind and its name. An empty result reads no callers, no callees, no supertypes or no subtypes.
hover Plain text.
symbols The symbol lines of the related actions. For a file, they give the declaration end after a dash, as in 5:18-9:2, and are indented under their container.
source The saved text of each declaration, documentation comment included, after a file:first-last kind name header. A partial type returns every part.
members The type, then the members it declares grouped by file, with names relative to the type.
impact Sections headed by ## action. A member gets its references, callers and implementations. A type gets its references and subtypes.
bulk_navigate One section per query in request order, headed ## number action target.

Locations:

src/Calculator.cs 12:9 40:17

Workspace files use relative paths. External and generated locations keep their absolute URI. Location links use the target selection start. Use the lsp tool with action=request for full LSP ranges and metadata.

Reads and writes:

Code Counted as
x += 1, x++, out x Write
Volatile.Read(ref x), Interlocked.Read(ref x) Read
Volatile.Write(ref x, 1) Write
Any other ref x, such as Interlocked.Exchange(ref x, 0) Read and write
The declaration and its initializer Neither

limit and offset apply to the filtered list. A ref argument to a method that only reads is still listed as a write unless the method is Volatile.Read or Interlocked.Read.

Related symbols with call sites:

src/Consumer.cs:7:26 method MyApp.Consumer.Run(IGreeter)
calls 7:59

Everything after the kind is a symbol name that navigate and edit accept unchanged. In every result, a constructor has the kind constructor. An explicit constructor is named like MyApp.Box.Box(int). A primary constructor has no declaration of its own, so its line names the type. After no callers, a line says that reflection or code outside the workspace may still call the member.

Options of the results:

Option or case Behavior
context Shows each position on its own line with its trimmed source line. For callers, call sites are in the caller’s file. For callees, they are in the requested file.
callees Lists calls only, and counts the property, field and constant accesses it leaves out.
file and line alone source and members use the innermost declaration around that line.
impact not fitting The largest sections are named with their sizes on a final omitted to fit: line. Request those alone.
bulk_navigate Runs up to 16 independent navigate queries concurrently. Each takes the action, symbol, file, line and character of navigate, and context, limit and offset apply to every query.
A failed bulk_navigate query Shows its error line in its own section, and the others still run. If the call times out, finished sections stay and the rest report timeout.

A final truncated: line gives the total and the next offset when limit omitted results:

truncated: 300 locations in total, next offset: 50. Raise limit or narrow the query.

Send the next offset as offset to read the next page. offset skips that many results and never changes the totals. navigate, bulk_navigate, symbols and diagnostics accept it, and a negative offset returns invalid_request. An offset past the last result returns a line that gives the total. Pages do not overlap because results keep a fixed order. Locations, related symbols and members are in file and position order. Workspace symbols are ordered by how well the name matches, then by file and position. Diagnostics are in file, line and character order.

lsp with action=status returns running, loading and workspace lines, and a server line when the --server option is set. While Roslyn loads the workspace and reports progress, a progress: line follows loading:, such as progress: Loading Calculator.slnx 40%. The line has no percentage when Roslyn reports none. The error loading repeats the progress in its message.

For diagnostics, omit file to scan C# files or use a glob such as src/**/*.cs. Braces list alternatives, so src/{Calculator,Program}.cs checks two files in one call. Only .cs and .csx files are analyzed. severity defaults to warning, which reports errors and warnings. A settings file can change that default for the project. Set it to information or hint to include analyzer suggestions. Each file with diagnostics is followed by one indented line per diagnostic, then a totals line:

src/Problems.cs
5:19 error CS0246 The type or namespace name 'List<>' could not be found
4 files checked, 1 diagnostic in 1 file, 3 below the severity

ids lists diagnostic codes, such as ["CS0246", "IDE0005"]. Codes match without regard to case, and ids applies before severity. The report lists and counts only matching diagnostics, and its totals line ends with filtered by ids. A filtered result without matches does not mean the workspace is clean. summary returns one line per code instead of one line per diagnostic. It lists the code, its count, its severity, one example location and its message. Lines are sorted by count, then by code. limit and offset count code lines, and the totals line still counts diagnostics:

CS0246 x12 error src/Problems.cs:5:19 The type or namespace name 'List<>' could not be found
IDE0005 x3 hint src/Program.cs:1:1 Using directive is unnecessary.
4 files checked, 15 diagnostics in 2 files

A line starting with incomplete: lists files not attached to a project, for example a file outside every project. These files get no semantic diagnostics. A newly created file gets a few seconds to join its project first. After a truncated: line, omitted files are not necessarily clean. limit defaults to 50 and accepts 1 to 250. Narrow the query if results are truncated or too large.

Preview and apply

The edit tool returns an edit preview whose first line holds its proposal ID. Apply that preview with the same action:

{ "action": "rename", "proposalId": "id-from-preview", "apply": true }

For code actions, request the listing, then send its proposal ID and zero-based actionIndex to resolve a preview. Apply the preview with its new proposal ID. Set endLine and endCharacter when an action needs a selection. Some Roslyn commands reveal their edits only when executed.

To fix a diagnostic without its position, pass its code as diagnostic with file, and optionally line. The listing then holds only the fixes for its first occurrence. Nested actions appear as one entry per choice, titled with their menu path, such as Introduce parameter for 'x' > into new overload. A fix-all action appears once per scope, such as Fix All: Remove unnecessary usings (Document), and fixes every occurrence in that scope. Entries under Suppress or configure issues are hidden, and a final line counts them. Set all to list them. Indexes count hidden entries, so they stay the same with all and can skip numbers without it.

apply: true also works without a preview: on a fresh rename, on a code action listing with actionIndex, or on a fresh code_actions request with actionIndex.

A preview lists each file operation, followed by its changed excerpts with their one-based start:

proposal 3f2a9c: 1 file, not applied
change src/Calculator.cs
@@ 12:9
- int Add(int a, int b)
+ int Compute(int a, int b)

Excerpts keep some unchanged context. A preview truncated: line means some changes could not be fully shown within the comparison or display limits. The preview response is limited to 32 000 characters. A truncated: line marks omitted files. These limits leave the proposed edit unchanged.

Proposals expire after five minutes. A proposal becomes stale when a file it edits changes, or when a project, props, solution or editorconfig file changes. On stale_edit, request a new preview. Changes to other source files keep the proposal valid. Reloading also discards proposals. After an applied file creation or rename, the bridge waits for Roslyn to attach the new file to its project, and reloads Roslyn only if that takes too long.

Application results contain a compact receipt, without source excerpts. The first line says whether the writes finished and whether Roslyn was refreshed. One line per completed operation follows, so a path can appear more than once. If a later step fails, the response starts with the error and the failed step, followed by the receipt of completed writes. Inspect both before retrying. After an application failure, the bridge reloads Roslyn on the next request. Large receipts keep their totals and end with a truncated: line when some operations are omitted. An oversized command result is omitted. A successful receipt ends with the errors and warnings of the changed C# files, in the diagnostics format, so checking the edit needs no further call. The bridge skips the check above 128 changed files or when it fails. Run diagnostics on the changed files then.

Limits

Edits must stay inside the workspace. The bridge rejects symbolic links below its root. Each file replacement is atomic, but a failed operation across several files can leave partial changes.

Diagnostics scans cover at most 1000 files. An edit can affect up to 256 files, with 8 MiB per file and 64 MiB in total.

Raw requests reserve lifecycle and document synchronization methods for the bridge. Unknown methods and workspace/executeCommand require apply: true because they may write files. Use reload if results remain stale after an external change.