MCP server for analyzing Blazor component architecture, bindings, cascading values, and routing in .NET projects
BlazeDex demonstrates strong naming conventions (verb_noun pattern: get_, find_, list_) and comprehensive descriptions (avg 180+ chars). All 15 tools have detailed, LLM-optimized descriptions explaining WHAT, WHEN, and coverage ceilings. Input schemas are present with type declarations and parameter descriptions. However, output schemas are not explicitly documented in the source code, responses are inferred from response class names (e.g., GetComponentApiResponse) but the actual field structure is not visible. Error handling is present (try/catch, structured error responses) but lacks recovery guidance in most tools. No tool annotations (readOnlyHint, destructiveHint) detected despite all tools being read-only operations.
Inventory every @bind site in the solution, grouped either by (child component + parameter) when groupBy="component" or by bound value symbol when groupBy="type". Filters IndexSnapshot.AttributeBindings to rows whose BindingKind starts with "bind-". Each group carries callSiteCount plus up to 3 example sites. Rows with a null grouping key (type mode with unresolved ValueSymbolFullName) are skipped rather than folded into an empty-string bucket. Coverage ceiling: interpolated @bind expressions may collapse into the unresolved bucket even when the binding kind is known.
Find every @bind / @bind-{Param} site whose resolved value expression points at the given property. Filters IndexSnapshot.AttributeBindings to the four @bind variants (bind-value, bind-event, bind-get, bind-set) and matches ValueSymbolFullName case-insensitively against the supplied fully qualified property name. Coverage ceiling: interpolated @bind expressions (e.g. @bind="@(Model.Foo)") where the inner expression cannot be resolved semantically return rows with resolved=false and a reason — never silently dropped.
Find a Blazor component by short name. Supports exact-match, case-insensitive substring prefix match, and (optionally) fuzzy Levenshtein match with a radius of max(2, name.Length/4). Returns rows ordered by descending score: exact matches score 1.0; fuzzy matches score 0.5 + (1 - distance/radius) * 0.5. Use this when you know the component's rough name but not its full type or file path — e.g. "which file defines WidgetExmple?" (typo intentional).
Find every .razor site where a Blazor component is used. Resolves OpenComponent<T> invocations from the Razor source generator and maps them back to their source .razor line via #line directives. Matches by short name (case-insensitive) or by fully qualified type name suffix.
Output schemas not explicitly documented. Response classes (GetComponentApiResponse, FindBindingTargetsResponse, etc.) exist but their field structures are not visible in source code. LLMs cannot plan downstream tool calls without knowing what fields to expect.
Tool annotations missing. All 15 tools are read-only (Risk: READ_ONLY declared) but no readOnlyHint annotation present in code. This prevents agents from understanding which tools are safe to call without confirmation.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 56 | <=2025-11-25 | v2 |
Find every component that declares a [Inject] dependency on the given service type. Matches by fully qualified service type name against ComponentApiRow.Injects. Trailing '?' on the query is stripped so nullable annotations do not defeat the match. Useful when tracing which views depend on a service you're about to rename, relocate, or remove.
Find every .razor markup site that wires a code-behind handler to an EventCallback. Resolves EventCallback.Factory.Create(this, Handler) invocations from the Razor source generator and maps them back to the source .razor line via #line directives. Matches by short name (case-insensitive) or by fully qualified method name suffix — e.g. "HandleValueChanged" or "WidgetExampleBase.HandleValueChanged".
Find every parent component that passes a given parameter to the specified child component. Filters IndexSnapshot.AttributeBindings where ChildComponentFullName suffix-matches componentQn and ParameterName equals parameterName (case-sensitive on the parameter name, case-insensitive suffix on the component FQN so callers may pass the short name). Anchor case: find_parameter_passers("FloatingInputText", "Label") resolves at least one call site in the indexed solution. Unresolved rows are surfaced with resolved=false + reason.
Detect route-template collisions — groups of two or more @page components that resolve to the same normalized route template. Normalization strips type constraints (e.g. '/users/{id:int}' -> '/users/{id}'), lowercases, collapses duplicate slashes, and trims trailing slashes. Useful when restructuring page routes or tracking down Blazor's 'Route template contains duplicate entry' router exception.
Find every Blazor component whose fully qualified name does NOT appear as the target of any ComponentUsageRow — LEFT ANTI JOIN of RazorComponents against ComponentUsages. Yellow-state (unresolved) components are preserved with the reason that blocked semantic resolution. By default excludes public components (external callers may be using them) and routable pages (which are entered by URL, not parent-component instantiation). Coverage ceiling: components referenced only through reflection, dynamic component factories, or string-name lookups cannot be detected and will be flagged as false positives — treat the list as a starting point, not a proof of deletion.
Classify every [CascadingParameter] on a component against the in-solution <CascadingValue> provider set and the curated framework cascade registry. Each consumer receives a confidence label: 'direct' (parent supplies the cascade), 'transitive' (an ancestor supplies it via BFS over ComponentUsages, hop count > 1), 'framework' (no in-solution provider but the value type matches a curated framework source), or 'unknown' (no match). Named-cascade collisions in the ancestor chain surface as a diagnostic reason. Consumers whose declared property type is INotifyPropertyChanged AND whose matched provider has IsFixed=true emit IsFixedMismatchWarning=true. Pure in-memory query over the index.
Return the public API surface of a single Blazor component — every [Parameter] property, every EventCallback/EventCallback<T> event, and every [Inject] service dependency. Matches by component short name (case-insensitive) or fully qualified type name suffix. When multiple components match the short name, the exact-name match wins and any other matches are returned in the 'alternates' field.
Return the current state of the in-memory index without triggering a rebuild. Call this first when a component query returns empty or unexpected results. State is one of: 'green' (healthy snapshot), 'yellow' (snapshot with parse errors), 'red' (snapshot with load errors), 'cold' (nothing built yet, no build in flight), 'building' (cold build or rebuild currently in flight on another concurrent tool call), 'error' (status read itself failed).
Enumerate every routable Blazor page in the loaded project — one row per @page / [RouteAttribute] template. Components with multiple @page directives yield multiple rows. Rows that cannot be literal-extracted are returned with resolved=false and a reason (never silently dropped). Optional glob filters by file path using * and ? wildcards (** for any path segment).
Enumerate every Blazor component (.razor file) known to the loaded project. Returns one row per component type with file path, short name, fully qualified name, and an is_page flag derived from @page / [Route] presence. Optional glob filters by file path using * and ? wildcards (** for any path segment).
Health-check tool. Returns "pong" to confirm the BlazeDex MCP server is reachable.
Error recovery guidance incomplete. Tools return structured errors (Error field in response) but do not guide LLMs on next steps. E.g., 'no component matches' should suggest 'Try list_razor_components() to see available components.'
ping tool is deprecated in MCP spec (2026-07-28). The tool exists and returns 'pong' but serves no purpose in stateless protocol. Should be removed or replaced with a capability-based health check.
Pagination defaults and caps are present (limit defaults to 50, capped at 500) but not consistently documented in all tool descriptions. Some tools (find_route_conflicts) have no pagination parameters despite potentially returning large result sets.