Skip to content

tomasfil/blazedex

Repository files navigation

BlazeDex — Blazor/Razor-aware MCP server for .NET 10

BlazeDex — Blazor MCP Server

License: Elastic-2.0 .NET MCP SDK Release CI

A Blazor/Razor-aware Model Context Protocol server for .NET 10. BlazeDex indexes your Blazor solution via Roslyn's full compilation pipeline and resolves every component usage, event-handler binding, and route back to the exact .razor:line:column through the Razor source generator's #line directives. No grep. No reflection. No string-match false positives.

Why BlazeDex

BlazeDex vs other Blazor MCP servers

Reflection-based servers (Components.MCP.Blazor and similar) inspect compiled assemblies — they cannot map usages back to source, cannot detect render-mode conflicts across the render tree, cannot lint dead routes.

Documentation servers (Radzen MCP, MudMCP, Fluent UI Blazor MCP) mirror one vendor library's documentation — they know nothing about your code.

BlazeDex does something neither can: it compiles your own solution through Roslyn's MSBuildWorkspace, walks the Razor source generator's *.razor.g.cs output, and exposes 20 tools that answer questions about your components, your routes, your code-behind partials — with every answer anchored to .razor:line:column through the Razor #line mapping.

This is for you if

  • You work on a Blazor solution and use Claude Code (or any other MCP-capable AI agent)
  • You want semantic answers about component graphs — usages, parameters, render-mode conflicts, dead code — without grepping
  • You want a read-only analysis layer that never touches your source tree except through one explicit edit tool

This is NOT for you if

  • You want an MCP server that mirrors a specific component library's documentation (→ see Radzen MCP, Fluent UI Blazor MCP, MudMCP)
  • You want a reflection-based runtime inspector against a live app (→ see Components.MCP.Blazor)
  • You're not using .NET 10 (required — we read the Razor source generator output)

Quickstart

1. Download the latest release and extract:

gh release download v0.1.0 -p "blazedex-mcp-v0.1.0-win-x64.zip"
mkdir -p "/c/tools/blazedex-mcp"
unzip -o blazedex-mcp-v0.1.0-win-x64.zip -d "/c/tools/blazedex-mcp"

2. Drop this .mcp.json into your Blazor project's repo root:

{
  "mcpServers": {
    "blazedex": {
      "command": "dotnet",
      "args": ["C:\\tools\\blazedex-mcp\\BlazeDex.Mcp.dll"],
      "env": {
        "BLAZEDEX_SOLUTION": "C:\\path\\to\\YourApp.sln"
      }
    }
  }
}

3. Ask Claude Code a question about your Blazor code:

Find every usage of the WidgetExample component.

Claude will call find_component_usages("WidgetExample") and return every .razor:line:column where the component is instantiated — resolved through the Razor generator's #line directives. No grep, no false positives from string matches in comments, no confusion between <MyButton/> and MyButton.SomeStaticMethod().

Full configuration, environment variables, troubleshooting: §3 onwards.

1. TL;DR

BlazeDex indexes a Blazor solution via Roslyn's MSBuildWorkspace, walks the Razor source generator's *.razor.g.cs output, and exposes 20 tools over stdio JSON-RPC for component discovery, usage tracing, API introspection, code-quality lints, and a single safe edit.

Concretely: ask Claude find_component_usages("WidgetExample") and you get back every <WidgetExample …/> markup site in the solution with the exact .razor:line:column source location, resolved through the Razor generator's #line directives. No grep. No false positives from string matches in comments. No extension-method confusion. No chasing the difference between <MyButton/> and MyButton.SomeStaticMethod().

That single example is the smallest unit of value BlazeDex provides. The other 19 tools follow the same shape — Roslyn-backed, source-anchored, yellow-but-never-red on broken code.

2. Status & Compatibility

  • Version: v0.1.0 (initial public release).
  • Runtime: .NET 10 SDK required (net10.0 target framework).
  • MCP SDK: ModelContextProtocol 1.2.0 (official Anthropic SDK), stdio transport.
  • Roslyn: Microsoft.CodeAnalysis.CSharp.Workspaces 5.3.0 + Workspaces.MSBuild 5.3.0, with Microsoft.Build.* pinned to 17.11.48 (MSBL001 workaround — see Troubleshooting).
  • Cache: Tier 1 in-memory always; Tier 2 on-disk SQLite (Microsoft.Data.Sqlite 10.0.5) for warm restarts.
  • Tested against: a real Blazor WebAssembly solution (~3 projects, ~500 razor files, cold Roslyn build 10–16 seconds, well within the spec §10 budget of <30 seconds). All 20 tools are exercised end-to-end against this corpus.
  • Operating systems: Windows is the primary supported platform and the only one independently verified in v0.1.0. macOS and Linux should work via the portable MSBuild runtime that MSBuildLocator resolves at startup, but they are not independently verified in v0.1 — please file an issue if you exercise BlazeDex on a non-Windows host so we can capture the gotchas.
  • Test target architecture: Blazor WebAssembly with the standard {Component}.razor + {Component}.razor.cs partial-class convention. Blazor Server and Blazor United (Interactive Server / WebAssembly / Auto render modes) parse correctly via the same generator pipeline; the render-mode lints in particular target the Blazor United model.
  • Thread model: single-process MCP server, one solution loaded at a time, fan-out across projects within that solution.

3. Install

You can either grab a prebuilt zip from the GitHub Releases page or build from source. Both produce the same binary layout — a self-contained framework-dependent publish folder containing BlazeDex.Mcp.dll, its dependencies, and the runtime config files.

3.a Prebuilt release (recommended)

Download the latest release zip with the gh CLI and unpack it into a stable location on disk. We recommend C:\tools\blazedex-mcp\ on Windows so paths in your .mcp.json stay short and predictable:

gh release download v0.1.0 -p "blazedex-mcp-v0.1.0-win-x64.zip"
mkdir -p "/c/tools/blazedex-mcp"
unzip -o blazedex-mcp-v0.1.0-win-x64.zip -d "/c/tools/blazedex-mcp"

After extraction the directory should contain BlazeDex.Mcp.dll plus its supporting assemblies. Verify with:

ls "/c/tools/blazedex-mcp/BlazeDex.Mcp.dll"

3.b From source

Clone the repository and publish in Release configuration. The dotnet publish step compiles, links, and copies all framework-dependent assets into a single output folder you can reference from any MCP client.

git clone https://github.com/tomasfil/blazedex.git
cd blazedex
dotnet publish src/BlazeDex.Mcp -c Release -o artifacts/publish/BlazeDex.Mcp

The artifacts/publish/BlazeDex.Mcp/ folder is now self-sufficient — you can copy it anywhere, including into C:\tools\blazedex-mcp\ if you want to keep the same on-disk layout as the prebuilt release.

If you intend to track upstream changes, leave the clone in place and re-run the dotnet publish command after each git pull. Publishing into the same output directory will overwrite the previous build cleanly, provided no MCP client process is currently holding the DLL open.

4. Configure

BlazeDex is configured per-project through a .mcp.json file in your target Blazor repository (the repo whose solution you want indexed), plus a small set of environment variables that point the server at the right .sln or .csproj.

The MCP server itself never reads anything from the project file — it inherits its configuration entirely from the host shell environment that Claude Code (or another MCP client) launches it with.

4.a .mcp.json template

Copy docs/mcp.json.example from this repository into your target project's .mcp.json and adjust the paths. A minimal Windows configuration looks like this:

{
  "mcpServers": {
    "blazedex": {
      "command": "dotnet",
      "args": ["C:\\tools\\blazedex-mcp\\BlazeDex.Mcp.dll"],
      "env": {
        "BLAZEDEX_SOLUTION": "C:\\path\\to\\YourApp.sln"
      }
    }
  }
}

The command field invokes the .NET runtime, the args array points it at the published BlazeDex.Mcp.dll, and the env block injects the target solution path into the spawned process. The env block is the most reliable way to scope configuration per project — it travels with the repo and never depends on user-environment side effects.

4.b Environment variables

The full reference for environment variables lives in docs/env.md. The four variables you can set are:

  • BLAZEDEX_SOLUTION — full path to your .sln file. Preferred. Loads every project in the solution and exposes solution-wide queries (cross-project component usages, dependency-graph drift handling, render-mode lints across the whole graph).
  • BLAZEDEX_PROJECT — full path to a single .csproj. Single-project fallback. Useful when a solution is too large or too broken to load wholesale; you lose cross-project queries but retain everything inside the chosen project.
  • BLAZEDEX_WATCHER — set to 0 or false to disable the passive FileSystemWatcher fast-path hint. The stat-based fingerprint check still runs on every call, so correctness is unaffected — only the in-process latency hint is disabled.
  • BLAZEDEX_VERIFIED_CLEAN_WINDOW_MS — fast-path window in milliseconds (default 250). When the watcher has reported clean status within this window, the next tool call skips the stat-walk. Lower the value if you suspect rapid filesystem changes are slipping through the window.

4.c Inheriting your shell environment

The MCP server inherits its environment variables from the process that launches it. If you set BLAZEDEX_SOLUTION only in a single shell, Claude Code launched from a different shell will not see it.

On Windows, set BLAZEDEX_SOLUTION as a user environment variable (setx BLAZEDEX_SOLUTION "C:\path\to\YourApp.sln") and restart your editor, or pass it explicitly through the env block of .mcp.json as shown above. Passing it through .mcp.json is the most predictable approach because the configuration travels with the project.

On macOS and Linux, export the variable in ~/.zshrc or ~/.bashrc (whichever your editor inherits) and restart the editor session. Per-project .mcp.json env blocks remain the most reliable approach on every platform.

5. First Run

5.a Cold build

The first tool call against a fresh process triggers a full Roslyn cold build of the configured solution.

On the test corpus (~3 projects, ~500 razor files) this takes 10–16 seconds and is well inside the spec §10 budget of <30 seconds. Larger solutions scale roughly linearly with project count and file count.

The cold build owns the call — every other tool invocation against the same process serves from the in-memory Tier 1 cache (sub-millisecond) until something on disk changes. After the cold build, get_index_status will report a lastBuildMs value matching the wall-clock time you observed for the first call.

5.b Sanity checks

After Claude Code has launched the MCP server for your project, ask it to call the two diagnostic tools:

  1. ping — should return the literal string "pong". If this fails, the server is not running or stdio transport is misconfigured.
  2. get_index_status — should return a JSON object whose state field is green. The first call may block on the cold build; subsequent calls return immediately.

A typical first run on a green project looks like this:

> ping
"pong"

> get_index_status
{
  "state": "green",
  "projectCount": 3,
  "componentsIndexed": 160,
  "lastBuildMs": 11420,
  "loadErrors": [],
  "parseErrors": []
}

If state comes back as yellow, BlazeDex loaded the solution successfully but some files have compilation errors — affected rows will come back with resolved: false and a reason, but unrelated rows are still fully correct.

If state comes back as red, the whole solution failed to load (missing SDK, unrestored packages, environment variables not set). Other tools will return empty results without throwing in the red state — call get_index_status first to find out why.

5.c State semantics in detail

  • Green — clean build; every row has resolved: true; loadErrors and parseErrors are empty. This is the steady state for a healthy project.
  • Yellow — best-effort build; some .razor or .cs files have errors, the rows that touch them come back with resolved: false and a human-readable reason in the reason field, all other rows are fully correct. Yellow is not a failure — it is BlazeDex's "I gave you what I could" state. Spec §10 calls this the yellow > red discipline: a partial answer beats throwing an exception.
  • Red — catastrophic failure. The solution did not load at all. loadErrors lists the diagnostics. Tool calls return empty arrays without throwing, so Claude Code can keep operating against the rest of your toolset while you fix the root cause.

5.d What you should expect from latency

  • First call (cold): 10–20 seconds on a ~3-project, ~500-razor-file solution. Roslyn cost dominates; nothing BlazeDex can do other than warm-load from the Tier 2 SQLite cache when available.
  • Warm Tier 2 load: 18–22 milliseconds wall-clock from process start to first row. Survives process restart. Same fingerprint check as Tier 1 — the warm-load is never trusted without revalidation.
  • Warm Tier 1 call: sub-millisecond. The fingerprint walk is ~50 ms for a 500-file solution, but the watcher fast-path skips it when the watcher has reported clean within the last BLAZEDEX_VERIFIED_CLEAN_WINDOW_MS (default 250 ms).
  • Drift-triggered rebuild: 10–16 seconds, identical to cold. Partial rebuild is deferred — see Known Limitations.

6. Tool Catalog

BlazeDex v0.1.0 exposes 20 tools grouped into six functional buckets. Every tool wraps its body in a try/catch at the MCP boundary; exceptions become structured error rows in the response and never propagate to the client.

6.a Discovery (5 tools)

  • list_razor_components(glob?, limit, offset) — enumerate every .razor component in the indexed solution, with optional glob filter and pagination. Returns the source path, code-behind path (if present), and the component's fully-qualified name.
  • list_pages(glob?) — list every routable component, derived from @page directives and [Route(…)] attributes on partial classes. Each row carries the route template plus the source location of the directive.
  • find_component(name) — locate a component by short name or fully-qualified name. Returns the canonical row including all codebehind partners (.razor, .razor.cs, .razor.css) when present.
  • find_components_injecting(serviceTypeName) — find every component whose [Inject] chain (including inherited base classes across project boundaries) references a given service type. Useful for blast-radius analysis when changing a DI registration.
  • find_route_definitions(routeTemplateGlob?) — enumerate every route template in the solution, optionally filtered by a glob over the template string. Each row carries the route plus the component that owns it.

6.b Usage (5 tools)

  • find_component_usages(componentName, limit, offset) — return every markup site that instantiates a given component. For example, find_component_usages("WidgetExample") returns every consuming page's .razor:line:column with resolved: true. Resolution flows through the Razor generator's #line directives via Location.GetMappedLineSpan() — never hand-parsed.
  • find_handler_bindings(methodQualifiedName) — find every markup site that wires a code-behind handler through EventCallback.Factory.Create(this, HandlerName). For example, find_handler_bindings("WidgetExampleBase.HandleValueChanged") returns the .razor:line:column of the binding site.
  • find_parameter_passers(componentName, parameterName) — find every markup site that passes a value to a specific [Parameter] of a given component. Resolves through the Razor generator's AddComponentParameter(seq, nameof(Type.PropName), valueExpr) pattern.
  • find_binding_targets(componentName, parameterName) — find every markup site that uses @bind-{Parameter} syntactic sugar against a specific component parameter. Returns both the binding target expression and its .razor:line:column location.
  • find_bind_inventory(componentName?) — solution-wide inventory of @bind-… usage, optionally filtered to one component. Useful for two-way binding audits and migration planning.

6.c API (3 tools)

  • get_component_api(componentQualifiedName) — return the full surface area of a component: parameters (with [EditorRequired], [SupplyParameterFromQuery], capture-unmatched-values flags), cascading parameters, render fragments, injects, methods, fields, events, class-level attributes, and generic constraints. Walks the inheritance chain across project boundaries via INamedTypeSymbol.BaseType so base-class members are folded in automatically.
  • get_component_tree(componentName, depth?) — render the component instantiation tree rooted at a given component, walking OpenComponent<T> invocations recursively up to the optional depth limit. Each node carries the .razor:line:column source anchor.
  • get_cascading_chain(componentName) — trace the [CascadingParameter] flow from a consumer back to its provider(s). Limited to the static cascading model in v0.1 — see Known Limitations for what this does not yet cover.

6.d Quality (4 tools)

  • find_unused_components(includeTestProjects?) — list every component in the solution that has zero find_component_usages results. Optionally folds test projects into the analysis. The first stop for dead-code cleanup.
  • find_route_conflicts() — return route templates that resolve ambiguously (two or more components claiming the same @page literal, or templates whose constraints overlap). Each conflict row lists every offending component.
  • find_render_mode_conflicts() — return components whose render-mode attributes conflict with their parent's render mode in Blazor United (e.g., a RenderModeServer component instantiated inside a RenderModeWebAssembly parent). Each row carries both anchors.
  • find_dead_routes() — return route definitions that are reachable through @page directives but never linked to from any <NavLink> or programmatic NavigationManager.NavigateTo call. Useful for finding orphaned admin pages and stale endpoints.

6.e Edit (1 tool)

  • add_parameter(componentQualifiedName, parameterName, parameterType, defaultValueExpression?, isEditorRequired?) — the only edit tool in v0.1.0. Adds a [Parameter] public {Type} {Name} { get; set; } declaration to the named component's code-behind partial class via Roslyn's SymbolEditor. Validates that the parameter does not already exist before writing, runs dotnet format on the modified file, and surfaces the diff in the response. All other edit operations are deferred to spec Phase 3 (see Known Limitations).

6.f Diagnostics (2 tools)

  • ping() — returns the literal string "pong". Use this as the first call after launching the MCP server to confirm the stdio transport is working.
  • get_index_status() — returns the current state of the index: state (green/yellow/red), projectCount, componentsIndexed, lastBuiltAtUtc, lastBuildMs, loadErrors, parseErrors, tier2Loaded, watcherHealth. The first thing to call when something looks wrong.

7. Troubleshooting

7.a state: red after the first call

The whole solution failed to load. Common causes:

  • .NET 10 SDK not installed. BlazeDex targets net10.0 and requires the .NET 10 SDK on the machine running the MCP server. Check with dotnet --list-sdks — you should see at least one 10.0.x entry. If you only have older SDKs, install .NET 10 from https://dot.net and restart your MCP host.
  • NuGet packages not restored. Run dotnet restore against your target solution at least once before launching the MCP server. The Roslyn MSBuildWorkspace cannot resolve ProjectReference closures if upstream projects are not restored.
  • Environment variables not set. Confirm BLAZEDEX_SOLUTION (or BLAZEDEX_PROJECT) is set in the environment that launches Claude Code. Pass them through the env block of .mcp.json if your shell environment is unreliable.
  • Path is wrong or contains the wrong slashes. Use double-backslashes inside JSON string literals on Windows: "C:\\path\\to\\YourApp.sln", not "C:\path\to\YourApp.sln". Forward slashes work too: "C:/path/to/YourApp.sln".
  • Solution file references missing or moved projects. Open the .sln in a text editor and confirm every Project("…") = "…", "…" line points at a path that exists relative to the solution file.

If the cause is not obvious from loadErrors, run dotnet build against the same solution from the command line. Any error there will reproduce in BlazeDex.

7.b state: yellow with resolved: false rows

Some files have compile errors. BlazeDex serves what it could resolve; affected rows come back with resolved: false and a reason string.

This is the spec's yellow > red discipline — yellow is correct behavior, not a bug. Fix the underlying compile errors in your editor and the next tool call will rebuild and clear the yellow state.

If you want to see exactly which files are failing, look at get_index_status.parseErrors — it lists each affected file with the diagnostic messages Roslyn raised.

7.c First call is slow (~10–20 seconds)

This is the expected Roslyn cold build. The first tool call against a fresh process loads every project in the solution, materializes the Razor generator's syntax trees, and walks them.

Subsequent calls hit the in-memory Tier 1 cache and complete in under a millisecond. On a warm restart the Tier 2 SQLite cache loads in 18–22 milliseconds.

If your cold build exceeds 30 seconds (the spec ceiling), file an issue with get_index_status output attached so we can tune the indexer for your project shape.

7.d Watcher disabled or unhealthy

Look at get_index_status.watcherHealth. If it reports disabled you have set BLAZEDEX_WATCHER=0 — re-enable it by unsetting the variable.

If it reports unhealthy the watcher tripped its sliding 10-second / 3-failure recreation budget (typically because the project lives on a network share or WSL bridge, both of which silently drop FileSystemWatcher events).

Correctness is unaffected because the per-call stat fingerprint always runs as the authoritative check; you only lose the latency hint. To force-disable the watcher and rely entirely on the stat fingerprint, set BLAZEDEX_WATCHER=0 and restart the MCP host.

7.e Lock errors when rebuilding the MCP

If you dotnet build BlazeDex itself while Claude Code is still holding the MCP process open, you will see file-lock errors on BlazeDex.Mcp.dll and friends. Quit Claude Code (or the MCP host) before rebuilding, or build in a different output directory.

The publish output under C:\tools\blazedex-mcp\ is loaded by the running process and cannot be overwritten in place. The CI release pipeline already uses dotnet build -c Release and dotnet publish into a separate artifacts/publish/ folder for exactly this reason.

7.f Verifying a healthy install

If you want a self-contained sanity check that does not depend on Claude Code, run dotnet test --no-build -c Release inside the BlazeDex repo to exercise the unit-test suite, then launch the server and call ping followed by get_index_status from your MCP client of choice. A green state plus a non-zero componentsIndexed confirms the install is healthy end-to-end.

8. Known Limitations

v0.1.0 is the first publishable cut. The following gaps are deliberately deferred to later phases — they are tracked in PLAN.md and the Phase 2/3 specs.

  • Edit operations are limited to add_parameter. Spec Phase 3 (rename, extract component, change-parameter-type, codebehind partial promotion, route refactoring) is deferred. v0.1 deliberately ships one safe edit so the wiring (Roslyn SymbolEditor, format pass, response diff, scope lock) is exercised end-to-end without a large surface area to maintain.
  • Drift handling triggers a full rebuild. When the per-call stat fingerprint detects any change, BlazeDex rebuilds the entire solution (10–16 seconds on the test corpus, well inside the <30-second budget). Partial rebuild via ProjectDependencyGraph reverse-dep closure is plumbed into the in-memory model but not yet wired into the rebuild path — MSBuildWorkspace does not support in-place project reload, so a fresh-workspace-per-affected-project approach cascades to a near-whole-solution reload once transitive ProjectReference closure is required for symbol resolution. Rows are already Roslyn-independent (pre-mapped via Location.GetMappedLineSpan() at index-build time) so a future step can switch drift handling to true partial rebuild without schema changes.
  • CascadingValue tracking is limited to get_cascading_chain. The static [CascadingParameter]<CascadingValue> provider/consumer chain is supported. Dynamic cascading values (programmatic providers, conditional cascade scopes, value-changed re-render flow) are deferred to spec Phase 2.
  • RenderFragment resolution is partial. The Phase 2 surface splits RenderFragment and RenderFragment<T> into a dedicated fragments bucket on get_component_api, but full template-content resolution (which markup actually fills the fragment, with full .razor:line:column provenance) is deferred.
  • Single solution per process. One BlazeDex MCP process handles one solution. To index two solutions concurrently, register two MCP servers in your .mcp.json with distinct BLAZEDEX_SOLUTION values and distinct command invocations.
  • Non-Windows hosts are not independently verified. macOS and Linux should work via the portable MSBuild runtime that MSBuildLocator resolves at startup, but v0.1.0 ships only with Windows verified end-to-end.
  • No streaming responses. All tool responses are returned as a single JSON-RPC message. Very large result sets are paginated via limit / offset parameters where the tool supports them.

9. License

BlazeDex is source available under the Elastic License 2.0.

In short: you can use, modify, and distribute BlazeDex freely, except:

  1. You may not provide BlazeDex to third parties as a hosted or managed service where the service gives users access to a substantial set of BlazeDex features or functionality.
  2. You may not circumvent any license-key functionality.
  3. You may not alter, remove, or obscure any copyright or licensing notices.

See LICENSE for the full terms. By contributing to this repository you agree to license your contributions under the same terms. See CONTRIBUTING.md for the sign-off requirement.

10. Architecture

For the design rationale and the full tool surface specification, see blazor-razor-mcp.md — the spec document that drove the v0.1 build. For the execution plan, deferred work, and design decisions made along the way, see PLAN.md. Both files live in the repository root and are checked in.

The high-level architecture is:

  • stdio transport. All logging is routed to stderr because stdout is reserved for the JSON-RPC protocol frame. Console.WriteLine is forbidden in server code.
  • MSBuildLocator.RegisterDefaults() runs as the first line of Program.cs, before any MSBuild assembly loads. This is non-negotiable — anything else triggers MSBL001.
  • Roslyn MSBuildWorkspace opens the configured .sln (or fallback .csproj), and GetCompilationAsync materializes the Razor source generator's *.razor.g.cs syntax trees in memory — no files are written to disk.
  • ProjectIndexer walks the syntax trees once per project, collects rows for every tool, and stashes them in per-project ProjectSnapshot records.
  • IndexService holds the in-memory Tier 1 cache, runs the per-call stat fingerprint check, and rebuilds from scratch on drift. The fingerprint covers last-write-time + size for every .razor, .razor.cs, .razor.css, .cs, .csproj, _Imports.razor, Directory.Build.props, and global.json under each loaded project directory.
  • Tier 2 SQLite cache (Microsoft.Data.Sqlite) serializes the row tables on shutdown and warm-loads them on startup in 18–22 milliseconds. The same fingerprint format is used for Tier 1 and Tier 2; warm-load runs the fingerprint check before serving so Tier 2 can never silently serve stale rows.
  • Passive FileSystemWatcher is a fast-path hint only. The stat fingerprint always runs as the authoritative check — watcher failures (network shares, WSL bridges, save bursts, symlinks, suspend/resume) cannot cause stale results, only slower paths.
  • Tool boundary try/catch wraps every [McpServerTool] method body. Exceptions become structured error rows; nothing escapes to the JSON-RPC client.

The cold-build budget of 10–16 seconds on the test corpus comfortably meets the spec §10 ceiling of <30 seconds. The anchor case — find_handler_bindings("WidgetExampleBase.HandleValueChanged") resolving back to the correct .razor:line:column through the Razor #line directives — is verified at every gate (cold Roslyn build, Tier 2 warm-load, and watcher-disabled paths).

About

Blazor/Razor Model Context Protocol server for .NET 10 — indexes your solution via Roslyn, resolves component usages to .razor:line:col. 20 tools for discovery, usage tracing, API introspection, quality lints, and safe edits.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors