An MCP server that provides architecture validation and codebase analysis tools for .NET solutions, including spec checking, migration burndown tracking, rule explanation, scope context lookup, and codebase graph generation.
LoadBearing provides 5 architecture analysis tools with detailed descriptions (194-1024 chars, well above baseline 194 avg). All tools have input schemas with type definitions and descriptions. However, schemas are inferred from method signatures rather than explicitly registered; tool definitions are not directly visible in the provided source. Output schemas are documented in descriptions but not formally specified. Error handling guidance is present in descriptions (e.g., 'modelIncomplete: true', 'failedProjects') but lacks actionable recovery steps. No tool annotations (readOnlyHint, destructiveHint) despite all being read-only operations. Parameter naming is domain-specific and precise (diffBase, rules, overview, skeleton, index) but lacks enum constraints where applicable (e.g., 'rules' accepts glob patterns as free-form strings).
Run the architecture spec against the bound solution and return the JSON check report (schemaVersion 3): rules[] keyed by id, plus summary counts. Violations are data — a red rule is a finding, not an error. The rules parameter narrows what is evaluated, and the report then covers only those. Narrow with overview, skeleton or index (coarser grain) or rules (fewer rules); an over-budget report coarsens its own grain, as far as index, rather than being cut — and index lists every rule ID, which is what rules globs match. subjectTypes/subjectGeneratedTypes appear together on a rule whose subject contained generator output, pass or fail: how many types it swept and how many nobody wrote. Both absent means none were. Narrowing the rule with .Authored() removes them. If projects fail to load, or their NuGet packages did not resolve, the report still returns, stamped modelIncomplete: true and failedProjects/restoreFailedProjects — a verdict reached against a partial model; report that, never plain green. Under a .slnf solution filter, uncheckedProjects names the declared projects the run never checked — a clean report then covers a subset; say so. unsupportedProjects names the declared projects this product cannot read at all (C# only), each with its reason — no rule can be violated in one, so a clean report over a polyglot solution is not a clean solution either. multiTargetedProjects names the projects that compiled for several frameworks, each with the framework its shared types' facts follow — what another framework's #if guards was never in the model, so a clean report over such a project covers one framework's view of it.
Return the architecture scope card(s) covering a path — a quarantined scope's dragons + sanctioned surface, a cautioned scope's dragons, or a layer's local rules — or a pointer line when none apply. If projects fail to load or to restore, the answer opens with a caveat naming them: cards from unloaded projects cannot be placed, and a rule about a package the restore never fetched was never measured, so treat a no-coverage answer as unproven there. A .slnf solution filter gets the same caveat for the declared projects it left unchecked: treat a no-coverage answer as unproven under them as well.
Tool definitions inferred from method signatures; explicit McpServerTool registration not visible in provided source. Schema repair via ReinjectErasedSchema suggests custom converters hide parameter shapes from the exporter, requiring post-hoc restoration. This pattern is fragile and makes schema validation difficult.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite all 5 tools being read-only analysis operations. Annotations help LLMs reason about safety and retry semantics.
Parameter 'rules' accepts semicolon-separated glob patterns as free-form strings. No enum constraint or pattern validation. LLMs may pass invalid globs; error message 'Matching no rule is an error listing the available IDs' requires the LLM to parse a list from error text.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 50 | <=2025-11-25 | v2 |
Return one rule's because, fix, posture payload, and linked prose as text.
Return the JSON codebase survey (schemaVersion 1): projects[] with namespace inventories, projectEdges[] (source/target, declared vs observed dependencies), and externalEdges[] grouped by namespace root. Every project the workspace loaded is here, which is wider than the solution: solutionMember false marks a passenger a ProjectReference dragged in, and an absent key means membership was unreadable. projectEdges[] carry only references the code declares: where one source file is compiled into several projects, a project referencing its own compiled-in copy is not an edge to the declarer the type was attributed to, and multiplyDeclaredTypes[] names those types with every declaring project and the one whose facts won — arch.Project() on any declarer selects them, with rule verdicts answering from the winner's facts (the key is absent when the solution has none). shadowedTypes[] is the other coverage key: a full name a project declares that a referenced assembly also supplies means two types, so a rule naming it reaches both while arch.Project() over the declaring project reaches only the declaration. generated qualifies the types count on a project and on each namespace (absent when zero): how many of them a generator emitted, which is what arch.Project() would sweep and .Authored() would drop. A namespace whose two counts are equal is wholly generator output — never make it a layer glob. targetFrameworks rides every project's row and names what it declares, normalized (a project predating the SDK reads net48); factsFollow rides only a multi-targeted one and names the framework its shared types' facts came from — what another framework's #if guards is not in the model. isPackable, locksPackages and packageReferences are the artifact facts, evaluated rather than read off the project file, so a value an SDK defaults or a props file above the solution sets is the one reported; packageReferences is what the project declares, never the transitive closure. Needs no spec — call it before one exists to plan layers and rules. Needs the solution restored and built: if projects fail to load, or their NuGet packages did not resolve, it returns an error naming them rather than a survey missing them or missing their external edges. Narrow with overview, skeleton or index (coarser grain) or projects (fewer projects); an over-budget survey coarsens its own grain, as far as index, rather than being cut — and index lists every project name, which is what projects globs match. Under a .slnf solution filter, uncheckedProjects names the declared projects the run never loaded — a project absent from the survey may simply be out of view. unsupportedProjects is the third coverage key and the one that bounds the survey's subject: the declared projects this product cannot read at all (C# only), each with its reason, so projects[] shorter than the solution is a stated fact rather than something to infer by opening the solution file.
Return the JSON migration burndown (schemaVersion 2): per-rule grandfathered/stale counts and promotion suggestions. If projects fail to load, or their NuGet packages did not resolve, the burndown still returns, stamped modelIncomplete: true and failedProjects/restoreFailedProjects — counts from a partial model; report that rather than quoting them as whole. Under a .slnf solution filter, uncheckedProjects names the declared projects the run never checked; they contribute no violations, so every count reads low. unsupportedProjects names the declared projects this product cannot read at all (C# only): their zero is permanent, not burndown.
Output schemas documented in prose descriptions but not formally specified as JSON Schema. LLMs cannot parse 'rules[] keyed by id' or 'projectEdges[] (source/target, declared vs observed)' without explicit schema definitions.
Error handling describes conditions (modelIncomplete, failedProjects) but does not guide recovery. E.g., 'modelIncomplete: true' is returned but no guidance on whether to retry, ask user, or proceed with partial results.