Every version, its notes, and its downloads.
Pulled straight from GitHub Releases at build time. Grab the .mcpb for a one-click Claude Desktop install, or the .nupkg to pin a version.
- v3.1.1latestSep 21, 2026
3.1.1 (2026-09-21)
Fixed
- services: stop an unresolved analyzer reference from aborting the relationship tools (#242) (#244) (144f3f4)
- tools: refuse a non-absolute project on writes into a checkout with linked worktrees (#245) (#247) (5709bc6)
- tools: refuse an omitted-project write into a checkout with linked worktrees (#240) (#243) (4573421)
- Aug 27, 2026
3.1.0 (2026-08-27)
Added
- ci: enforce Conventional Commit PR titles (#164) (#211) (217d34c)
- tools: state limitations and show an example in every tool description (#179) (#193) (7c11f69)
Fixed
- confirm: end every write prompt on the resolved target (#173) (#202) (de33948)
- confirm: name the project in the csproj apply_fixes prompt (#203) (#214) (7c9df1d)
- docs: sync the published median token figure with the generated benchmark data (#182) (#195) (1f4770a)
- fixes: enforce and report ApplyFixes' single-project scope (#156) (#185) (b39dc6e)
- fixes: only rewrite files whose diff actually changed (#175) (#209) (2e498ba)
- loader: fall back to a standalone project load for an explicit .csproj hitting an ambiguous ancestor (#213) (#218) (684c332)
- loader: ignore AppleDouble shadow files in auto-discovery and refuse ambiguous solution walks (#172) (#192) (0941603)
- services: anchor verification error paths to the response's resolvedPath (#199) (#201) (e9a682b)
- services: distrust a stat-only fingerprint match captured while a tracked file was still racy (#235) (#236) (21fb4cf)
- services: fail fast on an already-cancelled token before the git clone (#215) (#222) (6ccaace)
- services: name analyzer references that load nothing and register their fixers (#183) (#188) (fd7b6d8)
- services: relativize paths against resolvedPath, not Solution.FilePath (#181) (#194) (fe5e56c)
- services: signal ambiguous-solution-walk precisely instead of catching ArgumentException (#226) (#229) (754c653)
- tests: give ElicitationTests' confirmation-timeout wait a generous, diagnostic ceiling (#224) (#225) (8b28266)
- tests: give GuardServiceTests' Entered wait a generous, diagnostic timeout (#219) (#221) (7783673)
- tests: remove GuardServiceTests' Entered stamp-collision race (#233) (#234) (1bcede2)
- tests: run the environment-mutating configuration tests in one sequential collection (#189) (#200) (4610bba)
- website: align the per-file and per-suite benchmark figures with the generated data (#196) (#205) (d89c53a)
- website: derive the per-kind tool counts and analyzerLoad tools from tools.ts (#207) (#216) (3db07af)
- website: derive the site's tool count from tools.ts (#197) (#206) (9e3ce39)
- website: redraw the index.astro Program.cs showcase illustration (#212) (#227) (5eae929)
- website: regenerate package-lock.json and gate npm ci (#190) (#223) (98da5c4)
- website: restore missing spaces at astro line-wrap boundaries (#217) (#231) (69aae04)
- Aug 22, 2026
3.0.0 (2026-08-21)
⚠ BREAKING CHANGES
- verify: a
previewOnly: falsecall may now decline to write. The call still succeeds (ok: true), butappliedcomes backfalseand the response carries the diff and the introduced errors instead. Callers that assumed the write happened must readapplied.apply_fixeshad noappliedfield before this release — without it a refusal was indistinguishable from a success, since the response still carriespreviewOnly: false, a patch and afixedCount. PassallowIntroducedErrors: trueto restore the previous write-anyway behaviour.
Added
- guard: report the compile verdict after every file write (#168) (#171) (57bb097)
- verify: verify edits against the compiler before writing, add check_compilation (#133) (#145) (eb19739)
Fixed
- confirm: do not ask a human to approve a write that changes nothing (#162) (#174) (0ab3433)
- confirm: render write-confirmation prompts centrally and escape caller input (#161) (#170) (587080f)
- confirm: say EditMember writes one file, not the whole solution (#154) (#157) (7a62090)
- confirm: say which scope ApplyFixes writes when the target is a solution (#149) (#152) (a32e5a7)
- loader: report the resolved solution path in every project-loading response (#139) (#143) (1cd7943)
- loader: resolvedPath reports the file actually opened (#151) (#177) (36a340d)
- report permission failures as AnalysisError and skip unreadable directories (#150) (#153) (d68791f)
- services: skip unreadable directories during auto-discovery (#158) (#169) (52d1417)
- tests: make the option-binding tests independent of ambient ROSELINE_ variables (#132) (#140) (bd03629)
- tests: neutralize every casing of ROSELINE_ in the option-binding tests (#141) (#144) (e82f842)
- tools: name the resolved checkout on the failure envelope (#139) (#176) (7a36010)
- tools: name the resolved project in the write-confirmation prompt (#138) (#142) (4cad859)
Changed
- verify: a
- Aug 19, 2026
Added
RoselineMCP:ConfirmDestructiveWritesTimeout(default300000ms, 5 minutes) — bounds how long the write-confirmation elicitation waits for the client's answer. Set it viaappsettings.jsonorROSELINE_RoselineMCP__ConfirmDestructiveWritesTimeout=<ms>;0or less removes the bound and restores the previous, indefinite wait. This changes default behavior: a client that advertises elicitation support, accepts the confirmation request and then never answers — a CI job, a headless agent, a human who walked away — used to blockapply_fixes/edit_member/rename_symbolforever, becauseRoselineMCP:DefaultTimeoutis an analysis budget and by construction does not apply to the human round-trip. The server now stops waiting after the timeout — note that a client whose elicitation handler never returns may still not read the response, since the SDK's client dispatches server-initiated requests on its read loop; the bound is on RoselineMCP's side of the wire. It returns a preview, not a write: silence is not consent, sopreviewOnlycomes backtrueandnotes[]explains that the confirmation timed out. Writing without a human remains an explicit operator decision (ConfirmDestructiveWrites=false), so the security posture is no weaker than before — only the hang is gone. The clock is deliberately separate fromDefaultTimeout: a human reading a real diff may legitimately exceed an analysis budget.RoselineMCP:ConfirmDestructiveWrites(defaulttrue) — an operator switch that turns off the write-confirmation elicitation. The write tools (ApplyFixes,EditMember,RenameSymbol) ask the connected client to confirm before writing when the caller passedpreviewOnly: false; on an unattended host that prompt is not a second guard but a stop, because MCP elicitation is a separate channel from tool permissions and no client-side setting can pre-answer it — soclaude -pruns, CI jobs and overnight agent loops blocked on a human keypress. Set it viaappsettings.jsonorROSELINE_RoselineMCP__ConfirmDestructiveWrites=falseand no elicitation is sent at all (rather than one being auto-accepted); the explicitpreviewOnly: falseopt-in then stands as the only guard before a write — seeSECURITY.md. Interactive installs are unaffected: leave it at its default and behavior is unchanged. The server logs a warning at startup when the switch is off, so a gate-off deployment is identifiable from its stderr rather than being indistinguishable from a confirmed one.
Fixed
- A write confirmation that times out can no longer be read as consent when the SDK reports the
abandoned prompt as something other than a cancellation. The confirmation gate downgraded to a
preview only on
OperationCanceledException; every other exception fell through to a catch-all meaning "this client cannot elicit — honor the explicit opt-in" and returned proceed. Cancelling an in-flight JSON-RPC request is not guaranteed to surface as an OCE, so a transport or protocol exception raised by our own deadline would have written to disk on a confirmation nobody answered — the exact inversion of the gate. The timeout branch now filters on the deadline rather than on the exception type, so any failure caused by it downgrades to a preview; genuine caller cancellations and broken sessions still propagate unchanged. - The
RoselineMCP:DefaultTimeoutclock no longer runs while a human is being asked to confirm a write. It was armed before the confirmation elicitation, so its 120 s budget was spent on think-time — the very thing the confirmation's separate clock exists to prevent. Two consequences, both gone: a human who approved apreviewOnly: falsecall more than 120 s after it started got{"ok": false, "error": {"type": "TimeoutError"}}instead of the write they had just authorized; and with the newConfirmDestructiveWritesTimeoutdefault (300 s) exceedingDefaultTimeout, the timeout path could never have delivered the documented preview-and-note either. The analysis budget now starts once the confirmation resolves, soDefaultTimeoutmeasures analysis — as documented — rather than analysis plus however long the human took. - The
EditMemberwrite-confirmation prompt no longer asks the human to approve a writein ''whenprojectwas omitted (the documented auto-discovery default) — it now names "the auto-discovered project", matchingApplyFixes.RenameSymbol's prompt likewise names the project it resolved, instead of describing a solution-wide rename without saying which solution.
Changed
- Upgraded the MCP SDK from
ModelContextProtocol1.4.1 to 2.2.0, which negotiates protocol revision 2026-07-28 by default. No tool's wire shape, parameters, or response envelope changes. - Client-side log forwarding is now inert for clients on protocol 2026-07-28 or later.
SEP-2577
deprecated the MCP Logging feature in that revision:
logging/setLevelis rejected, and a server must not emitnotifications/messagefor a request that did not carry anio.modelcontextprotocol/logLevel_metafield — which the SDK's ownMcpClientprovides no way to set (on such a session it injects per-request_metaand strips that key). So the tool-failure log notifications RoselineMCP sends viaAsClientLoggerProvider()are delivered only to clients that negotiate 2025-11-25 or earlier; the code is kept for them and stays a no-op otherwise. Nothing is lost for anyone: the correlation ID that those notifications carried is still in every error envelope (error.correlationId) and in the server's own stderr log, which is exactly what SEP-2577 names as the replacement. Deprecated features remain in the spec for at least twelve months. - Releases now publish to NuGet.org via Trusted Publishing instead of a long-lived
NUGET_API_KEYsecret:publish-nuget.ymlexchanges the GitHub OIDC token for a key valid ~1 hour, the same way the registry publish already proved this repo's identity. The only remaining secret isNUGET_USER, the nuget.org profile name. Both prerequisites are in place as of 2026-07-27: the Trusted Publishing policy is registered on nuget.org (package ownerphmatray, naming this repository andpublish-nuget.yml) andNUGET_USERis set. The long-livedNUGET_API_KEYrepository secret is deliberately kept until one real release has been published and verified — seePUBLISH.md. - The write-confirmation gate now lives in one place.
apply_fixes,edit_memberandrename_symboleach carried their own copy of the block deciding whether to ask, what a declined or unanswered prompt means for the call, what to log, and which note to attach — one policy with three edit sites. All three now call a singleToolExecutionHelper.ResolveWriteModeAsync, and the one part of the prompt that had drifted — how the target project is named — is single-sourced throughToolExecutionHelper.DescribeWriteTarget. No behavior change: no tool's parameters, response shape, prompt wording or notes text differ. This removes the cause of the three divergent confirmation messages already fixed under Fixed above, rather than fixing them again;ElicitationTestsnow pins all three prompts (andedit_member's decline path, which had no end-to-end cover) so the same divergence cannot re-form.
Documentation
RoselineMCP:RunAnalyzers = falseno longer claims to stop all analyzer-assembly execution — source generators run regardless, and the docs now say so.SECURITY.mdpromised the switch "disables all analyzer execution (bundled and project-referenced alike)", andCLAUDE.mdandREADME.mdrepeated it. Source generators ship through the sameAnalyzerReferencesand are equally arbitrary in-process code from the analyzed repository, but they run as part of building any compilation rather than as part of the diagnostics pass — whichRunAnalyzersis the only thing gating. Every semantic path therefore executes them: all seven navigation tools (viaSymbolResolver),ApplyFixes(viaCodeFixService) andAnalyzeSolution(viaSolutionAnalyzerService). Verified on Roslyn 5.6.0 / .NET SDK 10.0.302 — a project whose only content is a[GeneratedRegex]partial method compiles throughMSBuildWorkspacewith the generated implementation bound and zero errors, which is only possible if the generator ran. The consequence for an operator is the point: someone who setRunAnalyzers=falsebefore pointing RoselineMCP at an untrusted repository believed they had closed a code-execution surface that was still fully open. Suppressing generators is not offered because it would not be honest — strippingAnalyzerReferencesremoves the generated types too, so every symbol resolving through generated code would be reported as a compile error. The switch narrows the surface; isolation, not configuration, is the mitigation, and the operator recommendations now lead with that. No behavior changed — only the guarantee the documentation advertised.RoselineMCP:WorkspaceCache = falseis documented as what it is: an isolation/debugging switch, never a way to save memory. The docs described it only as "loads a fresh workspace on every call", which reads as the memory-frugal option; measured, it is the opposite — disposing the workspace after every call costs +26 % resident memory (~374 MB vs ~296 MB after two calls) and ~45× second-call latency (0.92 s vs 0.02 s), because a disposed workspace's memory is never returned to the OS and the reload allocates on top of it. An operator who set it to reduce a server's footprint was getting a regression.docs/ARCHITECTURE.mdgains the measured memory profile behind that correction (~78 MB before any workspace exists — runtime plus the Roslyn/MSBuild/Roslynator assembly set, not the cache; ~300 MB once real work has been served; disposal plus a forced compacting GC moves the working set 276 MB → 276 MB), so the cache's 4-entry LRU bound is visible as the only lever that affects it. Releasing cached workspaces on idle was evaluated against these numbers and rejected.docs/ARCHITECTURE.mdnow states that the stdio transport, notUseConsoleLifetime, is what stops the host when a client closes stdin, with the four measured EOF paths (after handshake, before handshake, mid-tool-call, and stdin held open).UseConsoleLifetimehandles only SIGINT/SIGTERM, and reading it as the whole lifetime story suggests a stranded-server bug that does not exist.- Dependency versions asserted in prose corrected against
RoselineMCP.csproj, which the README already names as the source of truth:ModelContextProtocol1.4.0 → 1.4.1 (README tech stack and tool-annotations section,CLAUDE.md), MSBuild 18.7.1 → 18.8.2, andMicrosoft.Extensions.Hosting10.0.9 → 10.0.10.
- Jul 4, 2026
Fixed
- The token-savings benchmark (
RoselineMCP.TokenBenchmark) now measures the model-visible MCP wire text: each tool payload is wrapped in theToolResult<T>envelope and serialized with the MCP SDK's own serializer (McpJsonUtilities.DefaultOptions— minified camelCase, default JSON escaping), verified byte-identical to the text content block the real server emits over stdio. Previous figures measured each tool's bare, un-enveloped DTO with an indented serializer the SDK never uses. Re-measured headline: median 85% → 89%, pooled (size-weighted) 88% → 93% (568 tasks; on identical code the methodology correction alone moves the median 86% → 89% — minification outweighs the envelope + escaping overhead). All published numbers (README, site, OG card, manifest, docs) are synced. The benchmark also no longer depends on its working directory: tool-emitted relative paths resolve against the loaded solution's root, and a failed baseline file read now skips that task with a message instead of crashing the run. - Solution/project auto-discovery is now nearest-level-first: the working directory wins when it has exactly one candidate, then each parent directory (up to 3) in order, then immediate subdirectories — so a solution in the cwd is no longer reported as "ambiguous" just because an ancestor directory (e.g. the main checkout above a git worktree) also has one; only a single level with multiple candidates of its own is an ambiguity.
serverInfo.versionin the MCPinitializehandshake now reports the real package semver (the assembly's InformationalVersion minus any+buildmetadatasuffix) instead of the MinVer-pinned{Major}.0.0.0AssemblyVersion — a released 2.1.0 build introduced itself as2.0.0.0.- Social/Open Graph card (
og.png) refreshed: the baked-in token-savings figure is now the median (85% at the time; since re-measured to 89%, see above — was the stale pooled 81%), and the card is regenerable from a checked-in template (website/og-card.html) instead of existing only as a rendered PNG;og:image:altupdated to match.
- The token-savings benchmark (
- Jul 4, 2026
Added
- New
get_symbol_at_positionnavigation tool: resolves afile:line(:column)position (from a diagnostic, stack trace, grep hit, orfind_referencesresult) to the symbol living there — returning its name, fullName, kind, signature, definition location, and whether the position is the symbol's own declaration — so agents no longer have to read the file to guess a symbol name. Line-only queries prefer declarations on the line over referenced symbols. - Analyzer diagnostics are real: the diagnostics tools now run Roslyn analyzers, and Roslynator
fixes actually work. Previously every diagnostics path used
compilation.GetDiagnostics()(compiler-only), so RCS*/custom-analyzer diagnostics could never appear inanalyze_solution/list_diagnosticsandapply_fixescould never see them — and the Roslynator packages are analyzer-asset-only (nolib/), so their fix providers never even loaded. Now the Roslynator analyzer/fixer assemblies are bundled with RoselineMCP (ananalyzers/folder next toRoselineMCP.dll, shipped in the dotnet tool and Docker image), loaded at runtime (AnalyzerCatalog), and executed viaCompilationWithAnalyzerstogether with the target project's own analyzer references (deduped by analyzer type) in one shared pass (DiagnosticComputationService) behind all three diagnostics tools. Roslynator's ~440 fixable rules are discovered as code fix providers, solist_diagnosticssuggests RCS IDs as fixable andapply_fixesgenuinely fixes them. A broken analyzer is logged and skipped — never failing the tool call. NewRoselineMCP:RunAnalyzerssetting (defaulttrue); set tofalsefor the old, faster compiler-only behavior. Note that running a target project's own analyzers executes third-party code at analysis time — see the new SECURITY.md section.
Fixed
list_diagnostics/apply_fixesno longer select a project by substring match against project file paths (asking forFoocould analyzeFooBar) — project selection inside a solution now matches the exact (case-insensitive) name, via the sharedProjectLoader.- Docs drift found in the v2.0.0 audit: corrected the README's Roslyn version (5.3.0 → 5.6.0), repaired the changelog reference links (stale
[Unreleased]compare, missing 1.3.x–2.0.0 definitions), reframed the benchmark headlines around the robust median (85%, pooled 88% kept as a labeled secondary figure) and labeled the agent benchmark's ~50% as the forced-use ceiling (~13% realistic, n=1), refreshed the NuGet packageDescriptionto the v2 positioning, and added the missingmaxparameter to the READMEgetTypeHierarchysnippet. ApplyFixesno longer reportsok: truewith anError: …note when the operation itself fails (e.g. project not found) — such failures now return the documented classified error envelope (ok: falsewith e.g.NotFoundError), like every other tool.ApplyFixes,EditMember, andRenameSymbolnow write changed files back with their original encoding (BOM included) instead of silently re-encoding everything as BOM-less UTF-8.- Symbol search and resolution now span every project in the loaded solution — previously only the anchor project was searched, so symbols declared in a sibling project it doesn't reference (e.g. the Tests project) were invisible to
search_symbols(including the file outline) and madeget_symbol_info,find_references,find_implementations,get_call_graph,get_type_hierarchy,edit_member, andrename_symbolfail with "Symbol not found". analyze_solutionreports honest numbers.diagnosticSummarynow counts every diagnostic passing the filters — previously each project's diagnostics were capped atmaxDiagnosticsbefore counting, undercounting any project with more.topDiagnosticsis now the true solution-wide top-N by severity — previously it kept the first N diagnostics encountered in project order, so warnings from an early project could crowd out errors from a later one.- Configuration (
appsettings.json/appsettings.{Environment}.json) now loads from the install directory (AppContext.BaseDirectory) instead of the process working directory — a target repository's ownappsettings.jsoncan no longer reconfigure the server, the settings packaged with the dotnet tool are actually found, and the needless reload-on-change file watchers are gone. Removed the deadRoselineMCP:MaxDiagnosticskey fromappsettings.json. - MSBuild registration now picks the newest installed SDK instead of whatever
MSBuildLocatorenumerates first, andCreateWorkspacefails fast with an actionable error when no MSBuild/.NET SDK instance could be registered (instead of surfacing a confusing workspace load failure later). - Whitespace-only changes are no longer silently dropped from diffs (the diff engine ignored
whitespace unconditionally): a whitespace-only
edit_memberno longer reports "No changes were produced" and skips the write even withpreviewOnly: false,apply_fixespatches no longer omit whitespace-only changes that were written to disk, andcreate_patch'signoreWhitespaceparameter now actually controls the behavior (defaultfalse);create_patchline counts also no longer miss content lines that themselves start with++/--. - Docs
/releasespage could miss the just-published release. The page is generated from the GitHub Releases listing API at build time and is rebuilt immediately after the publish workflow, but that listing endpoint can trail/releases/latestby a few minutes — so a new release could be absent from the page until a manual re-deploy (as happened for v2.0.0). The build now cross-checks/releases/latest, retries the listing until it includes that tag (bounded so the build never hangs), and merges the latest release in directly as a fallback.
Changed
apply_fixes,edit_member, andrename_symbolnow emitchangedFilesand patch-header paths relative to the solution root with forward slashes (falling back to the project directory when no.slnis loaded), aligning them with the base the navigation tools have used since 2.0.0 — previously they were relative to the project directory. If a client resolved these paths against the project directory, resolve against the solution root instead.list_diagnosticsandapply_fixesnow load theirprojectthrough the sharedIProjectLoader(same as the navigation/edit tools):projectis now optional (auto-discovered from the working directory when omitted),.slnpaths are accepted, and the loaded workspace is cached across calls.ApplyFixesnow fixes all occurrences of a diagnostic ID in a single FixAll (batch) pass when the provider supports it, instead of re-compiling the project after every individual fix; providers without FixAll support keep the per-occurrence path, and the response shape is unchanged.- Docker image: now published ReadyToRun against the per-arch musl RID, precompiling IL to native code so the first tool call no longer pays most of the JIT cost.
Performance
- The navigation/edit tools now cache the MSBuild workspace across calls (~590 ms reload saved per call after the first), invalidated by a cheap on-disk fingerprint (mtime + size of the
.sln, every.csproj, and every document) so any file change — including RoselineMCP's own edits — triggers a fresh reload; disable withRoselineMCP:WorkspaceCache = false. analyze_solutionanalyzes projects in parallel (bounded by the processor count) instead of one at a time; results are merged deterministically and progress values still strictly increase.
- New
- Jul 3, 2026
Added
- Server-level tool guidance to drive adoption. The server now sends MCP
instructions— a decision policy telling the model to prefer these structural tools over reading whole files (especially on large codebases) — and each read-only tool's description is rewritten as a decision rule ("prefer over Read/Grep to answer 'where is this used'") rather than a feature list. In end-to-end testing this flipped the agent from never calling the tools to using them unprompted on large solutions. Seedocs/AGENT-BENCHMARK.md. projectis now optional on the Roslyn-backed tools (search_symbols,get_symbol_info,find_references,find_implementations,get_call_graph,get_type_hierarchy,edit_member,rename_symbol) — when omitted it is auto-discovered from the working directory (searching the cwd, a few parent directories, and immediate subdirectories) — and a.slnpath is now accepted whereverprojectis passed. Reduces the friction that made agents fail calls guessing the project (they naturally tried the.sln, which used to fail).
Changed
BREAKING: leaner response shapes for the read-only navigation tools and
get_symbol_info— a token-efficiency pass trimmed redundant and always-present fields from the JSON these tools return (tool names and input parameters are unchanged). Concretely:- Relative file paths. Every
file/definitionFileis now solution-root-relative with forward slashes (e.g.RoselineMCP/Services/Foo.cs) instead of an absolute path — acrosssearch_symbols,get_symbol_info,find_references,find_implementations,get_call_graph, andget_type_hierarchy. truncatedis omitted whenfalse. Its absence now means "not truncated" — forsearch_symbols,find_references,find_implementations, everyget_call_graphnode, andget_type_hierarchy'sderivedTypesTruncated.find_referencesdrops thecolumnfield from each reference (now justfile,line,snippet).get_call_graphdrops each node'ssignature; the nodefullNamenow renders parameter types as simple names (e.g.RoselineMCP.Services.Foo.Bar(string, CancellationToken)), still parameter-qualified so overloads stay distinct — callget_symbol_infofor a method's full signature.- Redundant fields dropped from symbol summaries and
get_symbol_info.accessibilityis gone (it is already insidesignature) fromget_symbol_infoand the project-wide summaries;containingTypeis gone from the full summaries (it is already the prefix offullName). The single-file outline ofsearch_symbolsstill emitscontainingType, but now as the simple, unqualified type name. get_symbol_infonow omitsmodifiers,baseTypes,interfaces,documentation, andsourcewhen they are empty/absent, so a minimal symbol collapses toname,fullName,kind, andsignature.
Net effect: tool output is ~35% smaller, lifting the benchmark headline savings from a pooled 81% to 88% (median per task 76% → 85%) on RoselineMCP's own source. These are breaking changes to the read-only tools' response wire shapes; update any client that parsed the removed fields or relied on absolute paths.
- Relative file paths. Every
deploy-docs.ymlretries the GitHub Pages deploy up to 3× — it intermittently returns "Deployment failed, try again later" (a Pages backend hiccup, not a build failure) that clears on re-run. The first two attempts tolerate failure, so a transient miss no longer fails the job.
Documentation
- End-to-end agent benchmark (
docs/AGENT-BENCHMARK.md) — a controlled A/B (vanilla Claude Code vs. + RoselineMCP, same task, same model, quality-gated) measuring whether an agent actually consumes fewer tokens in practice. Finding: ~50% fewer tokens at equal quality on large-file codebases, break-even on tiny repos, and the model must be steered to use the tools. - Tools page aligned to the v1.4.0 contract. Added a response-envelope callout
(
{ ok, data }/{ ok, error },structuredContent/outputSchema), surfaced each tool's humanTitleand capability pills (progress,confirms/elicitation), gave every tool an anchor link, and dropped the stalenewbadges (those tools shipped in 1.3.0). The page had been showing the pre-1.4.0 flat response shape. - Docs site: added a GitHub "Star" button in the top bar showing the star count. Renders a build-time snapshot instantly, then a tiny client-side fetch refreshes it to the current count (falls back to the build-time value on rate-limit/error).
- Server-level tool guidance to drive adoption. The server now sends MCP
- Jul 3, 2026
Added
- MCP structured content + output schema — every tool now advertises an
outputSchemaand emitsstructuredContent(UseStructuredContent = true), so clients get a machine-readable, schema-validated result in addition to the JSON text. - Progress notifications for long-running tools —
AnalyzeSolution,ApplyFixes, andRenameSymbolnow report progress via MCP progress notifications. - Human-readable tool titles and an honest
OpenWorldhint — every tool advertises aTitle;OpenWorldisfalsefor the local-only tools andtrueonly forAnalyzeSolution(which can clone a Git URL). - Write confirmation via MCP elicitation — the write tools (
ApplyFixes,EditMember,RenameSymbol) ask the client to confirm before writing whenpreviewOnly: false; declining downgrades the call to a preview (nothing is written). - Failure logging via MCP logging notifications — tool failures are surfaced to the client's log stream through MCP logging notifications that carry the correlation ID.
Changed
- BREAKING: tools now return a typed
ToolResult<T>envelope instead of a hand-serialized JSON string. The response wire shape changed: success payloads are now nested underdata({ "ok": true, "data": { ... } }) and failures undererror({ "ok": false, "error": { "type", "message", "hint?", "correlationId" } }). The human-readable message moved from the top-levelerrorfield toerror.message;type/hint/correlationIdmoved undererror. Seedocs/API.md. server.jsonwebsiteUrlnow points at the documentation site (https://atypical-consulting.github.io/RoselineMCP/) instead of the GitHub repo. Reaches the live MCP Registry entry on the next published version.
- MCP structured content + output schema — every tool now advertises an
- Jul 3, 2026
Fixed
- MCP Registry publish 403'd on namespace casing. The registry namespace derived from GitHub
OIDC is case-sensitive and matches the org's canonical login (
Atypical-Consulting), butserver.json'snameand the README ownership marker used lowercase (io.github.atypical-consulting/...), so the first publish wasForbidden. Corrected both toio.github.Atypical-Consulting/roseline-mcp. (The lowercase GHCR image name is unrelated and stays lowercase, as Docker requires.) - Docs
/releasespage didn't refresh on new releases. Therelease:trigger ondeploy-docs.ymlnever fired because the release is created by the publish workflow'sGITHUB_TOKEN, and GitHub does not start workflows from token-created events. Switched to aworkflow_runtrigger on thePublish NuGetworkflow's completion, which keys off the workflow (whose original trigger was a human tag push) and fires regardless of the publish outcome.
- MCP Registry publish 403'd on namespace casing. The registry namespace derived from GitHub
OIDC is case-sensitive and matches the org's canonical login (
- Jul 3, 2026
Documentation
- Docs site: a Releases page generated from GitHub Releases at build time (notes rendered from
each release, plus direct
.mcpb/.nupkgdownload buttons), a new Claude Desktop (1-click) install tab, and a note that RoselineMCP is listed in the official MCP Registry. The Astro build fetches the Releases API (authenticated in CI to avoid rate limits) and degrades to a GitHub link-out if the fetch fails.
Added
- One-click install for Claude Desktop (MCPB bundle). A
mcpb/manifest.json(MCPB spec 0.3) describes RoselineMCP as adnx-launched server; the release now builds and attaches aRoselineMCP.mcpbto each GitHub Release, so users can install with a dialog instead of editing JSON config. The bundle only wraps thednx RoselineMCPlaunch (the .NET 10 SDK is still required, since analysis loads projects through MSBuild), so it stays tiny and platform-agnostic. - Automated MCP Registry publishing.
publish-nuget.ymlnow has apublish-registryjob that, after a successful NuGet publish, waits for the version to index, then authenticates via GitHub OIDC (mcp-publisher login github-oidc, no secret) and publishes.mcp/server.jsonto the official registry (registry.modelcontextprotocol.io) — so the server is discoverable by any client/aggregator that reads the registry. Ownership is proven by anmcp-name:marker added to the packedREADME.md, which the registry cross-checks against the NuGet package. The manifest$schemawas migrated from the deprecated2025-10-17to the current2025-12-11(a URL-only change; the format is unchanged for stdio package servers). Takes effect on the next tagged release.
Security
- Pinned
Microsoft.Bcl.Memoryto10.0.9(aligned with thenet10.0TFM) inRoselineMCP.TokenBenchmarkto override the9.0.4thatMicrosoft.ML.Tokenizers2.0.0pulled in transitively, which was vulnerable to CVE-2026-26127 (GHSA-73j8-2gch-69rq, high severity — Base64Url out-of-bounds-read DoS). The benchmark harness is never packaged and is not referenced by the shippedRoselineMCPpackage, so published users were never exposed; this clears theNU1903restore warning. Remove the pin onceMicrosoft.ML.Tokenizersreferences a patched build.
- Docs site: a Releases page generated from GitHub Releases at build time (notes rendered from
each release, plus direct
- Jul 3, 2026
Changed
publish-nuget.ymlnow creates a GitHub Release and verifies the artifact before publishing. A git tag is not a GitHub Release, and nothing was creating one — so tagged versions published to NuGet without a corresponding Release (v1.3.0had to be backfilled by hand). The release job now: (1) fails the build if the packed.nupkgis missing.mcp/server.jsonor its embedded version doesn't match the tag — a guard that would have caught the originaldnx-fetches-1.0.0bug at the source rather than in the wild; and (2) after a successful NuGet push, creates (or heals) the matching GitHub Release with notes extracted from this CHANGELOG and the.nupkgattached.
Dependencies
Microsoft.ML.TokenizersandMicrosoft.ML.Tokenizers.Data.Cl100kBase1.0.3→2.0.0(RoselineMCP.TokenBenchmarkonly — not part of the shipped package) (#76)- Website:
astro5.x→7.0.0(#77) and CI Node20→24(#75) actions/upload-pages-artifactaction4→5(#74)
- Jul 3, 2026
v1.3.0 — Code navigation & editing tools
[1.3.0] - 2026-07-03
Added
- Token-efficient code navigation tools — six new read-only MCP tools that let an AI agent
retrieve precise structural/semantic information via Roslyn instead of reading whole files
(source code typically dominates an agent's token budget):
search_symbols— find symbols by wildcard/substring name pattern, or outline a single fileget_symbol_info— a symbol's kind, accessibility, modifiers, signature, base types, interfaces, XML docs, and definition location (optionally its source) — the compact "go to definition" payloadfind_references— every use site of a symbol across the solution, as location + snippetfind_implementations— implementations of an interface/member, overrides, or derived typesget_call_graph— a depth-bounded caller/callee graph with cycle detectionget_type_hierarchy— a type's base-class chain, interfaces, and derived types
- Surgical code-editing tools — two new write tools that emit a member-level change (not a
whole-file rewrite), keeping the tokens an agent produces proportional to the change. Both
default to preview mode (
previewOnly: true) likeApplyFixes, so nothing is written to disk unless the caller passespreviewOnly: falseexplicitly:edit_member— replace, add, or delete a single type memberrename_symbol— rename a symbol and update every reference across the solution (Roslyn rename)
IProjectLoader/ProjectLoaderservice that loads a project — and its containing solution when present, so references and renames span projects — into a fresh workspace per call, plusICodeNavigationServiceandICodeEditServiceand their response models.- Token-savings benchmark (
RoselineMCP.TokenBenchmark) — a reproducible harness that runs the real services against RoselineMCP's own source and measures each tool's output against the source an agent would otherwise read, tokenized with cl100k_base. Systematic sweeps; results stamped with commit + date. Reproduce withdotnet run --project RoselineMCP.TokenBenchmark -c Release. - Documentation site (
website/, Astro) with an overview, the tool reference, and the honest benchmark (charts + methodology + limitations), deployed to GitHub Pages via.github/workflows/deploy-docs.yml. Across 477 navigation tasks the read-only tools showed a pooled 81% / median 74% token reduction versus reading the corresponding files.
Changed
search_symbolsfile outline is now token-lean. The benchmark caught the outline costing tokens (it repeated the file path and fully-qualified name on every symbol); it now returns a lean projection (name, kind, signature, line), flipping its median from −45% to +30%.SymbolSummaryalso omits null fields from its JSON. Project-wide search is unchanged.
Fixed
dnx-based installs pulled an ancient1.0.0..mcp/server.jsonhardcodedversion/packages[0].versionat1.0.0— a version that was never released (releases start at1.2.0) — so any client resolving the MCP manifest was told to fetch1.0.0. Worse, despitePackageType=McpServerthe manifest was never packed into the.nupkg(it lives at the repo root with no<None Include>wiring it in), so the McpServer package shipped without its own manifest. Fixed by: (1) correcting the manifest to the current release, (2) packing../.mcp/server.jsoninto the package at.mcp/server.json, and (3) stamping the version into the manifest from the release tag inpublish-nuget.yml(mirroringMinVerVersionOverride) so it can never drift out of lockstep with the package version again.
- Token-efficient code navigation tools — six new read-only MCP tools that let an AI agent
retrieve precise structural/semantic information via Roslyn instead of reading whole files
(source code typically dominates an agent's token budget):
- Jul 2, 2026
v1.2.1 — Reference-project hardening
First real published release of RoselineMCP: reference-project hardening covering security defaults, real Git-URL analysis, correctness fixes, CI/CD, packaging, and a full documentation accuracy pass. See CHANGELOG.md for the itemized [1.2.0]/[1.2.1] entries.
Install
dotnet tool install -g RoselineMCPOr via Docker:
docker pull phmatray/roseline-mcp:1.2.1Note on versioning
v1.2.0's tag push published Docker Hub/GHCR images successfully but hit a CI bug that blocked the NuGet.org publish (fixed in this release — see CHANGELOG).v1.2.1republishes identical application content to both registries and is NuGet.org's first successful release.