RoselineMCP 2.0.0

{
  "servers": {
    "RoselineMCP": {
      "type": "stdio",
      "command": "dnx",
      "args": ["RoselineMCP@2.0.0", "--yes"]
    }
  }
}
                    
This package contains an MCP Server. The server can be used in VS Code by copying the generated JSON to your VS Code workspace's .vscode/mcp.json settings file.
dotnet tool install --global RoselineMCP --version 2.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest
                    
if you are setting up this repo
dotnet tool install --local RoselineMCP --version 2.0.0
                    
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=RoselineMCP&version=2.0.0
                    
nuke :add-package RoselineMCP --version 2.0.0
                    

RoselineMCP

Roslyn code intelligence for AI coding agents, over MCP. Give Claude, Cursor, and Copilot a semantic view of your C# solution โ€” symbols, references, call graphs, surgical edits โ€” so they navigate by structure instead of re-reading source. Measured 88% fewer tokens โ†’

Atypical-Consulting - RoselineMCP License: MIT .NET 10 stars - RoselineMCP forks - RoselineMCP

GitHub tag issues - RoselineMCP GitHub pull requests GitHub last commit

CI

NuGet Docker

Docs & Benchmark Tokens saved

๐Ÿ“– Documentation, tool reference & the honest benchmark โ†’


Table of Contents

Why RoselineMCP

Your coding agent shouldn't read a 700-line file to change one method. Source code dominates an agent's token budget, so the cheapest win is to stop feeding it whole files.

RoselineMCP wraps the Roslyn compiler platform as an MCP server. Instead of dumping source into the model, it answers structural questions precisely โ€” where is this symbol used, what implements this interface, who calls this method, what's the shape of this file โ€” and it edits surgically: a member-level diff, not a whole-file rewrite.

On RoselineMCP's own source, the read-only navigation tools returned a pooled 88% (median 85%) fewer tokens than reading the corresponding files โ€” measured honestly, weak cases included.

search_symbols on Program.cs: 1,154 tokens โ†’ 125 (โˆ’89%). The agent gets the shape of the file; you skip the wall.

Quick Start

Any MCP client that speaks dnx (the .NET equivalent of npx) runs it on demand โ€” no install step. Requires the .NET 10 SDK.

// claude_desktop_config.json  ยท  .vscode/mcp.json  ยท  ~/.cursor/mcp.json
{
  "mcpServers": {
    "roseline": { "command": "dnx", "args": ["RoselineMCP", "--yes"] }
  }
}

Then ask your agent to "find every caller of OrderService.Checkout" or "rename Foo to Bar across the solution." Prefer a pinned NuGet install or Docker? See Getting Started.

Features

  • Token-efficient code navigation -- symbols, references, call graphs, type hierarchies, and file outlines via Roslyn instead of whole files. A measured 88% pooled / 85% median token reduction -- see the benchmark.
  • Surgical code edits -- replace/add/delete a member or rename a symbol solution-wide, emitting a unified diff instead of a whole-file rewrite. Preview by default.
  • Comprehensive analysis & auto-fix -- diagnostics across a solution (Roslyn + Roslynator) with automated fixes and reviewable patches.
  • Read-only by default -- the six navigation tools and the diagnostics/patch tools never touch disk; the three write tools require an explicit previewOnly: false.
  • Works with your client -- Claude Desktop, VS Code (Copilot / MCP), Cursor. Install via dnx, NuGet global tool, or Docker.
  • Honest, reproducible benchmark -- run it against your own solution: dotnet run --project RoselineMCP.TokenBenchmark -c Release.

Tech Stack

Layer Technology
Runtime .NET 10.0
Compiler Platform Roslyn (Microsoft.CodeAnalysis) 5.3.0
Analyzers Roslynator 4.15.0
MCP SDK ModelContextProtocol 1.4.0
Diff Engine DiffPlex 1.9.0
Build System MSBuild 18.7.1
Hosting Microsoft.Extensions.Hosting 10.0.9

Versions above are kept in sync with RoselineMCP/RoselineMCP.csproj โ€” that file is the source of truth if this table ever drifts.

Getting Started

Prerequisites

  • NuGet global tool: .NET 10.0 SDK or later
  • Docker: Docker Desktop or Docker Engine
  • Build from source: .NET 10.0 SDK + MSBuild (included with Visual Studio or .NET SDK)
  • MCP client: Claude Desktop or any MCP-compatible client

Installation

Claude Desktop, one click: download RoselineMCP.mcpb from the latest release and open it โ€” Claude Desktop shows an install dialog, no config editing. (It launches via dnx under the hood, so the .NET 10 SDK is still required.) Prefer to edit config yourself, or using another client? Use one of the options below.

Option 1 -- dnx (no install step) (recommended)

RoselineMCP ships an MCP server registry manifest, so any MCP client that understands the dnx launcher (the .NET equivalent of npx โ€” resolves and runs a NuGet-packaged tool on demand, without a separate dotnet tool install step) can start it directly. Requires the .NET 10.0 SDK.

{
  "mcpServers": {
    "roseline": {
      "command": "dnx",
      "args": ["RoselineMCP", "--yes"]
    }
  }
}

Add this to your Claude Desktop or VS Code MCP configuration (see MCP Client Compatibility below for exact file locations per client). dnx downloads and caches the tool on first use, so there's nothing to pre-install globally.


Option 2 -- NuGet Global Tool (offline / pinned-version installs)

Requires .NET 10.0 SDK or later.

dotnet tool install -g RoselineMCP

After installation, the roseline-mcp command is available globally.

Claude Desktop configuration (NuGet global tool)

Add to your Claude Desktop configuration file (claude_desktop_config.json):

{
  "mcpServers": {
    "roseline": {
      "command": "roseline-mcp"
    }
  }
}

Config file location:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Option 3 -- Docker

No SDK required. Works on any platform with Docker installed.

docker run -i --rm phmatray/roseline-mcp:latest
Claude Desktop configuration (Docker)
{
  "mcpServers": {
    "roseline": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "phmatray/roseline-mcp:latest"
      ]
    }
  }
}

Note: The -i flag is required for stdio transport. The --rm flag removes the container after the session ends.


Option 4 -- Build from Source

git clone https://github.com/Atypical-Consulting/RoselineMCP.git
cd RoselineMCP
dotnet build
dotnet test
Claude Desktop configuration (build from source)
{
  "mcpServers": {
    "roseline": {
      "command": "dotnet",
      "args": ["run", "--project", "/path/to/RoselineMCP/RoselineMCP.csproj"]
    }
  }
}

MCP Client Compatibility

RoselineMCP speaks plain stdio MCP, so it should work with any MCP-compatible client. The snippets below are documented, not independently verified in every case โ€” we've confirmed the protocol-level behavior (stdio transport, tool discovery, JSON responses) works correctly, but we have not personally exercised each client's own configuration UI/file end to end. If one of these doesn't work as written for your client version, please open an issue.

<details> <summary><strong>Claude Desktop</strong></summary>

Edit claude_desktop_config.json (see file locations under Installation above) and add a roseline entry under mcpServers, using any of the four install options shown above (dnx, global tool, Docker, or build-from-source).

</details>

<details> <summary><strong>VS Code (GitHub Copilot / MCP extension)</strong></summary>

Add an entry to your workspace or user mcp.json (Command Palette โ†’ "MCP: Open User Configuration", or .vscode/mcp.json in the workspace):

{
  "servers": {
    "roseline": {
      "command": "dnx",
      "args": ["RoselineMCP", "--yes"]
    }
  }
}

Substitute "command": "roseline-mcp" (no args) if you installed via the NuGet global tool instead.

</details>

<details> <summary><strong>Cursor</strong></summary>

Add a roseline entry to ~/.cursor/mcp.json (global) or .cursor/mcp.json (project-local), using the same command/args shape as the VS Code snippet above.

</details>

Available Tools

1. AnalyzeSolution

Analyzes an entire C# solution for diagnostics. Read-only โ€” never modifies files on disk. pathOrGit also accepts an http(s):// Git URL, which is shallow-cloned to a temp directory, analyzed, and deleted afterward.

analyzeSolution({
  pathOrGit: "/path/to/solution.sln",
  include: "Core",              // Optional: only project names containing this substring
  exclude: "Test",              // Optional: skip project names containing this substring
  severity: "warning",          // Optional: minimum severity (Error|Warning|Info|Hidden)
  maxDiagnostics: 100           // Optional: Maximum diagnostics to return (default: 100)
})

Returns: solution file name, project count, a diagnosticSummary (counts by severity), and a topDiagnostics array with project/file/line/column/id/severity/message per diagnostic.

2. ListDiagnostics

Gets detailed diagnostics for a specific project. Read-only โ€” never modifies files on disk.

listDiagnostics({
  project: "MyProject.csproj",
  ids: ["CS0168", "CS0219"],       // Optional: Filter by diagnostic IDs
  files: ["Controller.cs"],        // Optional: substring match against each diagnostic's file path (case-insensitive; NOT a glob pattern)
  max: 50                          // Optional: Maximum results
})

Returns: project name, totalDiagnostics count, the filtered diagnostics list, stats (counts grouped by ID and by severity), and suggestedFixableIds โ€” diagnostic IDs a code fix provider is actually registered for.

3. ApplyFixes

Applies automated code fixes for specified diagnostics. Defaults to preview mode: previewOnly defaults to true, so calling this tool without setting it never writes to disk โ€” you must pass previewOnly: false explicitly to apply changes.

applyFixes({
  project: "MyProject.csproj",
  ids: ["CS0168", "RCS1001"],   // Diagnostic IDs to fix
  previewOnly: false             // Optional (default: true). Set false to write changes to disk.
})

Returns: project name, fixedCount, fixersApplied (diagnostic IDs actually fixed), changedFiles, a unified diff patch, notes (skipped/failed IDs and status messages), and previewOnly echoing back whether anything was written.

4. CreatePatch

Generates a unified diff between two text versions. Read-only โ€” operates purely on the provided strings, never touches the filesystem.

createPatch({
  before: "original code",
  after: "modified code",
  fileName: "Example.cs",        // Optional: For display in diff
  ignoreWhitespace: false,       // Optional: ignore whitespace-only differences
  ignoreCase: false              // Optional: ignore case differences
})

Returns: the unified diff patch, hasChanges, linesAdded, linesRemoved, and the fileName/summary used in the diff header.

Code Navigation Tools (read-only)

These tools return precise structure instead of whole files, so an AI agent can orient itself in a codebase while spending far fewer tokens than reading source directly. All are read-only and take an optional project (name, directory, .csproj path, or .sln path) โ€” when omitted, RoselineMCP auto-discovers the solution/project from its working directory. When the project belongs to a solution, the whole solution is loaded so references/renames span projects. Full request/response shapes are in docs/API.md.

Tool names on the wire are snake_case. The section headings below use friendly PascalCase/camelCase for readability, but the actual MCP tool names returned by tools/list (and expected by tools/call) are: search_symbols, get_symbol_info, find_references, find_implementations, get_call_graph, get_type_hierarchy, edit_member, rename_symbol (matching the existing analyze_solution / list_diagnostics / apply_fixes / create_patch).

5. SearchSymbols

Find symbols by wildcard/substring name pattern, or outline a single file.

searchSymbols({
  project: "MyApp.Core",
  query: "*Service",             // Substring, or wildcard with * and ? โ€” omit to outline a file
  file: "UserService.cs",        // Optional: restrict to one file, or outline it when query omitted
  kinds: ["class", "method"],    // Optional: filter by kind (also accepts "type" / "member")
  max: 50                        // Optional (default: 50)
})

Returns: symbols (name, fullName, kind, signature, file, line โ€” file paths are solution-root-relative; the single-file outline instead returns name, kind, signature, line, containingType), totalFound, truncated (omitted when not capped).

6. GetSymbolInfo

The compact "go to definition": a symbol's declaration metadata and (optionally) its source.

getSymbolInfo({
  project: "MyApp.Core",
  symbol: "Acme.Users.UserService.GetUser",  // Simple or fully-qualified name
  includeSource: true                          // Optional (default: true)
})

Returns: name, fullName, kind, signature, and (each omitted when empty/absent) modifiers, baseTypes, interfaces, documentation, definitionFile/Line, and source. Accessibility is already part of signature; definitionFile is solution-root-relative.

7. FindReferences

Every use site of a symbol across the solution, as location + one-line snippet.

findReferences({ project: "MyApp.Core", symbol: "GetUser", includeDefinition: false, max: 100 })

Returns: references (file โ€” solution-root-relative, line, snippet), totalReferences, truncated (omitted when not capped).

8. FindImplementations

Implementations of an interface/member, overrides of a virtual/abstract member, or derived types of a class.

findImplementations({ project: "MyApp.Core", symbol: "IRepository", max: 100 })

Returns: implementations (symbol summaries), totalFound, truncated.

9. GetCallGraph

A depth-bounded caller and/or callee graph for a method, with cycle detection.

getCallGraph({
  project: "MyApp.Core",
  method: "Handle",
  direction: "callers",   // "callers" (default) | "callees" | "both"
  depth: 1,               // 1-3 (default: 1)
  max: 50                 // Optional: nodes expanded per direction
})

Returns: callers/callees trees of nodes (fullName with simple parameter-type names, file โ€” solution-root-relative, line, truncated, children). Call GetSymbolInfo for a node's full signature.

10. GetTypeHierarchy

A type's base-class chain, implemented interfaces, and/or derived types.

getTypeHierarchy({ project: "MyApp.Core", type: "SqlRepository", direction: "both" }) // "base" | "derived" | "both"

Returns: baseTypes, interfaces, derivedTypes (as symbol summaries).

Code Editing Tools (preview by default)

Surgical edits that emit a member-level change rather than a whole-file rewrite. Like ApplyFixes, both default to preview mode (previewOnly: true) โ€” nothing is written to disk unless you pass previewOnly: false explicitly.

11. EditMember

Replace, add, or delete a single type member; returns a unified diff.

editMember({
  project: "MyApp.Core",
  symbol: "Acme.UserService.GetUser",  // The member (replace/delete), or the container type (add)
  operation: "replace",                 // "replace" | "add" | "delete"
  newSource: "public User GetUser(int id) => _repo.Find(id);",  // Required for replace/add
  previewOnly: false                    // Optional (default: true). Set false to write to disk.
})

Returns: operation, target, changedFiles, patch, previewOnly, applied, notes.

12. RenameSymbol

Rename a symbol and update every reference across the solution (Roslyn rename); returns a unified diff.

renameSymbol({ project: "MyApp.Core", symbol: "GetUser", newName: "GetUserById", previewOnly: false })

Returns: symbol, newName, changedFiles, patch, previewOnly, applied, notes.

Tool Annotations

RoselineMCP's SDK (ModelContextProtocol 1.4.0) supports the standard MCP tool annotation hints (readOnlyHint, destructiveHint, idempotentHint), and every tool declares them via [McpServerTool(ReadOnly = ..., Destructive = ..., Idempotent = ...)]:

Tool readOnlyHint destructiveHint idempotentHint Notes
AnalyzeSolution โœ… true โŒ false โœ… true Never writes to disk.
ListDiagnostics โœ… true โŒ false โœ… true Never writes to disk.
ApplyFixes โŒ false โš ๏ธ true โŒ false destructiveHint is a static, worst-case annotation: it's true because the tool can write files when previewOnly: false is passed, even though the default call (previewOnly unset, i.e. true) writes nothing. The SDK's annotation model has no way to express "destructive only for a specific parameter value" โ€” see the doc comment on ApplyFixesTool.ApplyFixes in source.
CreatePatch โœ… true โŒ false โœ… true Operates purely on the two provided strings; never touches the filesystem.
SearchSymbols โœ… true โŒ false โœ… true Never writes to disk.
GetSymbolInfo โœ… true โŒ false โœ… true Never writes to disk.
FindReferences โœ… true โŒ false โœ… true Never writes to disk.
FindImplementations โœ… true โŒ false โœ… true Never writes to disk.
GetCallGraph โœ… true โŒ false โœ… true Never writes to disk.
GetTypeHierarchy โœ… true โŒ false โœ… true Never writes to disk.
EditMember โŒ false โš ๏ธ true โŒ false Same worst-case destructiveHint rationale as ApplyFixes: writes a file only when previewOnly: false is passed; the default call writes nothing.
RenameSymbol โŒ false โš ๏ธ true โŒ false Same worst-case destructiveHint rationale as ApplyFixes: writes files only when previewOnly: false is passed; the default call writes nothing.

These hints are static per-tool metadata for MCP clients that surface them (e.g. to warn a user before an agent invokes a destructive tool) โ€” they describe the tool's worst-case behavior, not the outcome of any specific call. See Tool Compatibility Policy below for the stability guarantees around tool names and parameters that these annotations sit on top of.

Tool Compatibility Policy

  • Tool names and required parameters are stable within a major version. An MCP client integration written against AnalyzeSolution(pathOrGit, ...) on 1.x will keep working across all 1.x releases.
  • Optional parameters may be added in minor versions (e.g. CreatePatch gained ignoreWhitespace/ignoreCase as optional, defaulted parameters without breaking existing callers).
  • Renaming or removing a parameter, changing a parameter's required/optional status, or changing a tool's name is a breaking change. Breaking changes are called out under a dedicated "Breaking Changes" heading in CHANGELOG.md and only ship in a major version bump.
  • Response shapes (JSON field names/types) are documented in docs/API.md and follow the same policy: additive fields are non-breaking, renamed/removed fields are breaking.

Supported Analyzers

RoselineMCP includes support for:

  • Roslyn Analyzers -- Built-in C# compiler diagnostics
  • Roslynator -- 500+ analyzers, refactorings, and fixes for C#
  • Custom Analyzers -- Any Roslyn-based analyzer referenced by your solution (loaded and run the same way as Roslynator; there is no built-in StyleCop.Analyzers reference in this repository's own .csproj โ€” add it to your analyzed solution if you want SA* diagnostics)

Examples

Analyzing a Solution

# Using with an MCP client
mcp call analyzeSolution '{
  "pathOrGit": "/Users/dev/MyProject/MyProject.sln",
  "severity": "warning",
  "maxDiagnostics": 50
}'

Response:

{
  "solution": "MyProject.sln",
  "projects": 5,
  "diagnosticSummary": {
    "error": 2,
    "warning": 15,
    "info": 28
  },
  "topDiagnostics": [
    {
      "id": "CS0168",
      "severity": "warning",
      "message": "The variable 'ex' is declared but never used",
      "file": "Program.cs",
      "line": 42
    }
  ]
}

Applying Fixes

mcp call applyFixes '{
  "project": "MyProject.Core.csproj",
  "ids": ["CS0168", "RCS1001"],
  "previewOnly": true
}'

Response includes a unified diff patch showing all changes that would be applied.

Configuration

Environment Variables

  • ROSELINE_LOG_LEVEL: Set logging level (Debug, Information, Warning, Error)
  • ASPNETCORE_ENVIRONMENT: Set environment (Development, Production)

appsettings.json

Configure logging and other settings:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "RoselineMCP": "Debug"
    }
  },
  "RoselineMCP": {
    "DefaultTimeout": 120000,
    "EnableDiagnosticLogging": false
  }
}
  • RoselineMCP:DefaultTimeout: Wall-clock timeout (ms) applied to each tool call, in addition to the caller's own cancellation. 0 disables it.
  • RoselineMCP:EnableDiagnosticLogging: Opt-in, local-only tracing of tool invocations โ€” see Debug Logging. Disabled by default; enabled in appsettings.Development.json.

Architecture

RoselineMCP uses stdio transport โ€” this is an intentional design decision. The server runs as a local process launched by the MCP client (Claude Desktop, AI agents), communicates over stdin/stdout, and exits when the client disconnects. This makes it perfectly suited for distribution as a NuGet global tool (dotnet tool install -g RoselineMCP) or Docker image โ€” no port binding, no HTTP server, no infrastructure to manage.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   MCP Client        โ”‚
โ”‚  (Claude Desktop,   โ”‚
โ”‚   AI Assistants)    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚ MCP Protocol (stdio)
         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   RoselineMCP       โ”‚
โ”‚   MCP Server        โ”‚
โ”‚                     โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  Tool Layer   โ”‚  โ”‚
โ”‚  โ”‚  (Analyze,    โ”‚  โ”‚
โ”‚  โ”‚   Fix, Patch) โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚          โ–ผ          โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ Service Layer โ”‚  โ”‚
โ”‚  โ”‚ (Workspace,   โ”‚  โ”‚
โ”‚  โ”‚  Diagnostics) โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚          โ–ผ          โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ Roslyn +      โ”‚  โ”‚
โ”‚  โ”‚ Roslynator    โ”‚  โ”‚
โ”‚  โ”‚ Analyzers     โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚
         โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  C# Source Code     โ”‚
โ”‚  (.sln / .csproj)   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Project Structure

RoselineMCP/
โ”œโ”€โ”€ RoselineMCP/
โ”‚   โ”œโ”€โ”€ Interfaces/       # Service interfaces
โ”‚   โ”œโ”€โ”€ Services/         # Core business logic
โ”‚   โ”œโ”€โ”€ Tools/            # MCP tool implementations
โ”‚   โ”œโ”€โ”€ Models/           # Data transfer objects
โ”‚   โ””โ”€โ”€ Program.cs        # Application entry point
โ”œโ”€โ”€ RoselineMCP.Tests/    # Unit tests
โ”œโ”€โ”€ .github/workflows/    # CI/CD pipelines
โ”œโ”€โ”€ Dockerfile            # Container build
โ””โ”€โ”€ RoselineMCP.sln       # Solution file

Performance

  • Workspace Isolation -- Each operation creates a fresh MSBuildWorkspace; nothing is cached or reused across calls (see Architecture)
  • Sequential Project Analysis -- Projects within a solution are analyzed one at a time, not concurrently, to keep MSBuild workspace state consistent
  • Result Capping -- maxDiagnostics/max bound how many diagnostics are returned per call, independent of how many were found

Security

  • Read-Only by Default -- AnalyzeSolution, ListDiagnostics, CreatePatch, and all six code navigation tools (SearchSymbols, GetSymbolInfo, FindReferences, FindImplementations, GetCallGraph, GetTypeHierarchy) never write to disk. The three write-capable tools โ€” ApplyFixes, EditMember, and RenameSymbol โ€” each default to previewOnly: true; writing requires the caller to pass previewOnly: false explicitly.
  • Real, Read-Only Git Cloning -- pathOrGit accepts http(s):// Git URLs, which are shallow-cloned (git clone --depth 1) into a temp directory that's deleted after the operation. No other URL scheme is treated as a Git remote.
  • MSBuild Is Not a Sandbox -- loading a .sln/.csproj via MSBuildWorkspace is a design-time MSBuild evaluation and can execute build logic embedded in the project (<Exec> tasks, custom UsingTask assemblies, imported .targets/.props). Analyzing a fully untrusted repository or URL carries a real code-execution risk on the host. See SECURITY.md for the full write-up and operator recommendations before pointing RoselineMCP at untrusted input.
  • No Dedicated Path-Traversal Sandbox -- paths are resolved with plain existence checks, not canonicalized against an allowed root; treat pathOrGit/project/branch as trusted operator input.

Troubleshooting

Common Issues

  1. MSBuild not found: Ensure .NET SDK is installed and in PATH
  2. Solution won't load: Check for missing NuGet packages, run dotnet restore
  3. No diagnostics found: Verify analyzers are installed in the target project
  4. Permission denied: Ensure read access to solution files

Debug Logging

Enable detailed logging:

ROSELINE_LOG_LEVEL=Debug dotnet run --project RoselineMCP/RoselineMCP.csproj

Tracing Individual Tool Calls

Every tool call gets a per-invocation correlation ID (a GUID). It's cheap to generate so it's always created, but it's only surfaced when you need it: it's included in every JSON error response (correlationId) and attached to that call's log lines via ILogger.BeginScope, so a user reporting a failure can hand you one ID that ties back to the full server-side log entry โ€” without needing to grep timestamps.

For deeper, opt-in tracing of each tool invocation (start/stop, duration, success/failure) as a System.Diagnostics.Activity span, set RoselineMCP:EnableDiagnosticLogging to true (it's already true in appsettings.Development.json):

ROSELINE_RoselineMCP__EnableDiagnosticLogging=true dotnet run --project RoselineMCP/RoselineMCP.csproj

This uses the built-in ActivitySource/Activity APIs rather than the OpenTelemetry SDK, so it adds no extra dependency. Spans are logged exclusively through the existing ILogger pipeline, which is already routed to stderr โ€” never to stdout (the MCP JSON-RPC channel) โ€” and nothing is ever sent over the network; when the flag is off (the default), no listener is registered and the spans cost essentially nothing.

Roadmap

  • Additional analyzer rule sets (SonarAnalyzer, FxCop)
  • Auto-fix suggestions with confidence scoring
  • CI/CD integration for automated analysis pipelines
  • Multi-solution support in a single session
  • Incremental analysis (only changed files)
  • Custom analyzer rule configuration via MCP

Want to contribute? Pick any roadmap item and open a PR!

Documentation

  • Documentation site -- overview, tool reference, and the token-savings benchmark (built from website/, deployed to GitHub Pages)
  • docs/API.md -- Full request/response reference for every MCP tool, service interfaces, models, and the error-response contract
  • docs/AGENT-BENCHMARK.md -- End-to-end A/B: does an AI agent actually spend fewer tokens with RoselineMCP? (honest answer โ€” a large-codebase win, break-even on small)
  • docs/ARCHITECTURE.md -- Layered architecture, data flow, and design patterns
  • PROMPTS.md -- Example prompts and end-to-end workflows for each tool
  • CHANGELOG.md -- Release history and breaking changes
  • SECURITY.md -- Vulnerability reporting and the MSBuild code-execution caveat
  • CONTRIBUTING.md -- Development setup and PR process

Contributing

Contributions are welcome! Please read CONTRIBUTING.md first.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit using conventional commits (git commit -m 'feat: add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT ยฉ 2026 Atypical Consulting SRL

Acknowledgments


Built with care by Atypical Consulting -- opinionated, production-grade open source.

Contributors

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last Updated
2.0.0 0 7/3/2026
1.4.0 0 7/3/2026
1.3.3 0 7/3/2026
1.3.2 0 7/3/2026
1.3.1 0 7/3/2026
1.3.0 0 7/3/2026
1.2.1 41 7/2/2026