slnmap

Slnmap (sln-map) · v0.12.2 · MIT

Which React screens break if you change this C# handler? Claude Code doesn't know. Fix that.

Slnmap builds one local knowledge graph across your C# backend and React frontend — so your AI agent checks dependencies, impact, and architecture before it edits your code, on either side of the wire.

$ dotnet tool install -g Slnmap

Requires the .NET SDK 9.0+ (Node 18+ too, for the React side). Then run analyze analyze-ts link and connect via MCP.

install + MCP setup guide included

100% local. Your code never leaves your machine. Don't take our word for it — the source is open.

terminal — claude code
$ slnmap analyze ./MySolution.sln analyzing 10 projects with Roslyn… Analyzed 10 projects · 1,334 symbols · 3,495 edges in 28s $ claude > update PUT /api/basket/{id}/items ⏺ slnmap:impact_analysis( "BasketController.UpdateQuantities") [Endpoint] PUT /api/basket/{id}/items @depth 1 [FrontendCallSite] PUT basketService.ts:42:10 @depth 2 I'll update the handler and the React call site in basketService.ts — the one your context window wouldn't have shown me.
0 projects·0 symbols·0 edges·0s

eShopOnWeb (10 projects) — real run, v0.10.0

AI coding agents are powerful — and structurally blind.

It breaks hidden dependencies.

Your agent renames a method and misses 3 call sites behind an interface — or two React screens that call the endpoint it just changed. You find out in the PR — or in production.

It violates your architecture.

Suggestions that put data access in your domain layer — because it can't see the boundaries you spent years defending.

It loses the plot on large solutions.

500 files don't fit in a context window. Structure does. Your agent needs a map, not a bigger window.

From blind edits to informed ones — across the whole stack.

quickstart.NET SDK 9.0+ · Node 18+

$ slnmap analyze ./MySolution.sln # C# graph, via Roslyn

$ slnmap analyze-ts ./frontend # + React/TS call sites

$ slnmap link # join them: which screens call which handlers

$ slnmap serve # connect over MCP

01

Map both sides

analyze builds the C# graph with Roslyn — symbols, calls, implementations, endpoints — in under a minute. analyze-ts adds your React/TypeScript call sites (Node 18+), and link joins them: which frontend call site hits which backend handler. One graph, on disk, both stacks.

02

Connect

One line in your MCP config plugs Slnmap into Claude Code. No cloud account, no API keys, nothing to sign up for.

03

Ask

Your agent now answers “which React screens break if I change this C# handler?” — before touching anything.

keep it fresh — new in v0.10sub-second re-analysis

$ slnmap watch ./MySolution.sln

[19:19:53] re-analyzed 1 file(s) in 0.93s — graph 1,336 nodes / 3,497 edges, saved in 0.17s

slnmap watch keeps the compiler workspace warm and re-analyzes on every save — about a second per change on eShopOnWeb (real output, unedited), instead of a full workspace reload per run. Run slnmap serve beside it and your agent's answers stay fresh while you type.

The question this was built to answer.

After slnmap link joins your React call sites to their C# handlers, two things become possible that weren't before.

impact_analysis reaches into the frontend

impact_analysis("BasketController.UpdateQuantities"):

[Endpoint] PUT /api/basket/{id}/items @depth 1

[FrontendCallSite] PUT src/services/basketService.ts:42:10 @depth 2

Change the handler, see the exact React call site that breaks — one graph, zero guessing. Real output, unedited (eShopOnWeb; also in the README).

find_orphan_calls names the exact mismatch

1 orphaned call site(s) (verb-mismatch):

verb-mismatch (1):

POST src/services/usersService.ts:41:12 (/organizationusers) — no POST registered; GET /api/OrganizationUsers exists

The exact production bug that started this project: a frontend POST with no matching backend registration, caught and named by reason — never a guess. Route and message are real, from the v0.12.0 field trial (changelog); the file path above is illustrative, not the original codebase's.

Evaluated and fixed in public, not just built in public.

Three generations of pre-launch scrutiny, each one catching a different class of bug before it shipped. The full story is on dev.to; the receipts are in the changelog.

Gen 1 — independently scored, 8/10.

A field evaluation against a 26,000-node production codebase found one confident-lie defect class — fields reported "no usages" when real usages existed. Fixed and shipped within 48 hours.

Gen 2 — shaped by production feedback.

The MCP error-handling overhaul was designed from an r/mcp community thread — failures now come back machine-checkable, with a corrective message instead of a stack trace.

Gen 3 — three field trials, three bug generations.

Every cross-stack release shipped only after a trial against a codebase outside its own test corpus: v0.11.0 caught a silently-invisible HTTP verb (superagent's .del()), v0.12.1 caught the linker reporting false ambiguity between unrelated routes, and v0.12.2 caught a fluent method chain silently miscounting call sites plus a string-concatenated URL silently dropped instead of disclosed. All three fixed before anyone outside this project saw them.

Never guessed, always disclosed.

Anything not statically resolvable is counted and reported, never guessed. On the same 26,000-node codebase: 658 of 658 HTTP route registrations resolved, zero guessed; on the cross-stack field trial, 407 of 434 frontend call sites (93.8%) linked, and every one of the rest individually disclosed by exact reason.

See the shape of your solution.

slnmap viz exports the graph as a single interactive HTML file — no server, no CDN, works fully offline. It opens collapsed to one node per project; click to drill into a namespace or class and see its dependency edges.

slnmap viz output: an interactive dependency graph of eShopOnWeb's 10 projects, with weighted edges showing call, reference, implements, inherits, and endpoint-handler counts between them

eShopOnWeb (10 projects) — real output, unedited.

Questions you should be asking

Three levels of understanding code:

  • text (grep/embeddings) finds what looks similar
  • syntax (tree-sitter) sees structure but can't resolve which method a call actually hits
  • semantics (Roslyn) resolves calls through interfaces, DI, and generics

Slnmap is the third level — the only one where "what breaks if I change this?" has a correct answer. And unlike your IDE's internal understanding, it's exposed as tools your AI agent can query before it edits.

Yes — the CLI and MCP server are MIT-licensed, and they'll stay that way. Future hosted or team-oriented features may be commercial. Star or contribute on GitHub.

Fifteen read-only MCP tools your agent can call — two of them cross-stack:

  • find_orphan_calls — frontend call sites with no matching endpoint, grouped by exact reason (no-match, verb-mismatch, verb-unknown).
  • list_frontend_callsites — every React/TS HTTP call site with its live linking status.
  • find_symbol — locate a type or member by name anywhere in the solution.
  • get_dependencies — see what a given symbol depends on.
  • impact_analysis — what breaks if you change a symbol: every caller and implementation, across projects — and, once slnmap link has run, every React call site downstream of the C# handler it hits.
  • list_endpoints — every HTTP endpoint your solution registers (Minimal APIs and attribute-routed controllers), grouped by project, filterable by verb or route prefix.
  • find_endpoint — the endpoint that handles a route or a concrete request path, like /api/vendors/42 — plus which frontend call sites hit it.
  • get_architecture_overview — the projects and how they depend on each other.
  • find_usages — everywhere a symbol is used.
  • find_implementations — who implements an interface or overrides a member.
  • get_type_hierarchy — the base and derived type tree.
  • find_tests_for_symbol — which tests exercise a symbol.
  • get_project_dependencies — the project reference map, with the most-coupled hotspot.
  • find_circular_dependencies — dependency cycles between projects or namespaces.
  • get_symbol_source — the actual source of a symbol, straight from the graph's stored location.

Run slnmap watch (new in v0.10) — it analyzes once, keeps the compiler workspace warm, and re-analyzes on every file save. On eShopOnWeb (10 projects), a one-file change lands in the graph in about a second: re-analyzed in 0.93s, saved in 0.17s — versus paying a full workspace reload for each run-and-exit slnmap analyze. Run slnmap serve beside it and your agent's answers stay fresh while you type. Structural changes (csproj/sln) trigger an announced full reload — membership is never guessed. Prefer one-shot? slnmap analyze still re-walks only changed files without dropping edges owned by files it didn't touch, and upgrading the tool triggers a one-time full rebuild automatically. Either way your queries stay instant — the graph is already on disk.

No — every tool response is token-budgeted by design. Summaries first, drill-down on demand. The point is to give your agent structure instead of flooding it with source.

No. Analysis runs locally and the graph lives on your machine. No cloud, no telemetry on your code. Ever.

The tool itself runs on the .NET SDK 9.0+, and analyzes C# solutions targeting .NET 8 and 9 (earlier targets are untested — feedback welcome). analyze-ts additionally requires Node 18+ and analyzes React/TypeScript frontends. More languages and frameworks based on user feedback.

HTTP endpoints are extracted from ASP.NET Core Minimal APIs (including MapGroup prefixes and the CleanArchitecture-template MapGroup(this) convention) and attribute-routed controllers (including [controller]/[action] tokens and inherited [Route] from base controllers).

This audience trusts disclosed limits more than feature lists, so here they are:

  • Blazor & Razor Pages — conventional routing and Razor Pages are detected and disclosed, not modeled; .razor markup is counted (file totals only) but not analyzed (#30).
  • MediatR-style dispatch — runtime request/handler dispatch isn't traced; impact_analysis/find_usages stop at the request record, correctly not claiming a link they can't see — walk through the record to reach the handler.
  • Angular & Vue HTTP clients — call sites on clients besides axios and fetch (Angular's HttpClient included) are honestly disclosed as unresolved, never silently dropped or guessed at.
  • Monorepos — single, flat tsconfig.json frontends are field-verified; project-references/monorepo tsconfigs aren't yet — point analyze-ts at each package individually in the meantime.

Any MCP client can connect — it's a standard MCP server over stdio. Claude Code is first-class and what it's tested with; Cursor and other MCP clients use the same server.

Right now — it's v0.12.2, free and open source (MIT). Install from NuGet today and connect it to Claude Code in a few minutes. No signup, no waitlist.

Give your agent a map — of both stacks.

v0.12.2 — free and open source (MIT). Install it and connect it to Claude Code in a few minutes.

$ dotnet tool install -g Slnmap

Requires the .NET SDK 9.0+ (Node 18+ too, for the React side). Then run analyze analyze-ts link and connect via MCP.