{"slug": "show-hn-slnmap-roslyn-based-code-graph-mcp-server-for-net-codebases", "title": "Show HN: Slnmap – Roslyn-based code graph MCP server for .NET codebases", "summary": "Slnmap, an open-source Roslyn-based code graph MCP server for .NET codebases, is now available under the MIT license, enabling AI coding agents to perform compiler-accurate impact analysis across entire solutions. The tool, which requires .NET SDK 9.0+, exposes thirteen read-only tools including impact_analysis, find_usages, and list_endpoints, and supports ASP.NET Core Minimal APIs (v0.7.0) and attribute-routed controllers (v0.8.0). It runs locally and serves the map to agents or editors over MCP, helping agents answer questions like 'what breaks if I change this interface?' with every caller and implementation across projects.", "body_md": "*Slnmap (sln-map) — a semantic map of your .sln for AI coding agents.*\n\n**Open source under the MIT license.**\n\n**Your AI agent can't refactor .NET code it can't see.** Ask an agent *\"what breaks if I change this\ninterface?\"* and it guesses from the files in its context — missing callers in other projects and\nfiles it never opened. Slnmap gives the agent a precise, compiler-accurate map of your whole solution,\nso it answers correctly: every caller, every implementation, across every project. Fewer broken\nchanges, no hallucinated dependencies. It runs locally and serves the map to your agent or editor over\n[MCP](https://modelcontextprotocol.io).\n\n**1. Install** the global tool (requires the [.NET SDK](https://dotnet.microsoft.com/download) 9.0+):\n\n```\ndotnet tool install --global Slnmap\n```\n\nIf this is the first .NET global tool ever installed on the machine, the tools directory\n(`~/.dotnet/tools`\n\n) may not be on your `PATH`\n\nyet — open a new terminal before running `slnmap`\n\n.\n\n**2. Analyze** your solution (or a single `.csproj`\n\n) — this builds `slnmap.db`\n\nin the current folder:\n\n```\nslnmap analyze path/to/YourSolution.sln\n```\n\n**3. Connect** your MCP client. For Claude Code, add this to `.mcp.json`\n\nin your project. Use an\n**absolute** path to the `slnmap.db`\n\nyou just built — an MCP client's working directory is usually not\nyour project folder, so a relative path can silently resolve to the wrong (or a missing) file:\n\n```\n{\n  \"mcpServers\": {\n    \"slnmap\": {\n      \"command\": \"slnmap\",\n      \"args\": [\"serve\", \"--db\", \"C:/path/to/your/project/slnmap.db\"]\n    }\n  }\n}\n```\n\nOn macOS/Linux, use a POSIX absolute path instead, e.g. `/home/you/project/slnmap.db`\n\n.\n\nOr register it from the command line:\n\n```\nclaude mcp add slnmap -- slnmap serve --db C:/path/to/your/project/slnmap.db\n```\n\nRestart your MCP client after registering.Fully quit and relaunch it — starting a new conversation or reconnecting mid-session is not enough; a running session will not see the new tools until the client process restarts.\n\nThat's it. Ask your agent an architecture question and it will call Slnmap.\n(Run `slnmap doctor`\n\nfirst if anything looks off — see [Troubleshooting](#troubleshooting).)\n\nThe server exposes thirteen read-only tools. Give them fully qualified names; results are capped and counts-first. (A note the tools also carry: an FQN does not reveal whether a member is an explicit interface implementation.)\n\n| Tool | Example question |\n|---|---|\n`find_symbol` |\n\"Find the `IBasketService` interface.\" |\n`get_dependencies` |\n\"What does `CartController.Index` depend on?\" |\n`impact_analysis` |\n\"What breaks if I change `IBasketService` ?\" |\n`get_architecture_overview` |\n\"Show me the projects and how they depend on each other.\" |\n`find_usages` |\n\"Where is `BasketService.GetBasket` used?\" |\n`find_implementations` |\n\"Who implements `IBasketService` / overrides this virtual member?\" |\n`get_type_hierarchy` |\n\"Show the base and derived type tree for `BaseEntity` .\" |\n`find_tests_for_symbol` |\n\"Which tests exercise `BasketService.AddItemToBasket` ?\" |\n`get_project_dependencies` |\n\"How do the projects reference each other, and where is the coupling worst?\" |\n`find_circular_dependencies` |\n\"Are there dependency cycles between projects or namespaces?\" |\n`get_symbol_source` |\n\"Show me the actual source of `IBasketService` .\" |\n`list_endpoints` |\n\"List every HTTP endpoint, or just the `POST` s under `/api/basket` .\" |\n`find_endpoint` |\n\"Which endpoint serves `/api/basket/42/items` , and which method handles it?\" |\n\nFor an interface (or interface member), `impact_analysis`\n\nfollows both the interface's callers **and**\nits concrete implementations/overrides — so the answer includes code that only touches the interface,\nacross projects, in files nobody has open.\n\nHTTP endpoints are first-class graph nodes — from **ASP.NET Core Minimal APIs** (v0.7.0) *and*\n**attribute-routed controllers** (v0.8.0): each `MapGet`\n\n/`MapPost`\n\n/… registration and each\n`[Route]`\n\n/`[HttpGet(\"…\")]`\n\naction appears as `VERB /route/template`\n\nlinked to its handler method,\nso `impact_analysis`\n\nand `find_usages`\n\non a handler surface the actual routes that break. Route\ntemplates are resolved statically — `MapGroup`\n\nprefixes, `const`\n\npatterns, the common\nCleanArchitecture registration conventions, class-level `[Route]`\n\n(including inherited ones and\n`[controller]`\n\n/`[action]`\n\ntokens), and controller base classes reached through packages\n(Ardalis.ApiEndpoints works out of the box). Anything that can't be resolved statically is counted\nand reported, never guessed — and controllers routed *conventionally* (`MapControllerRoute`\n\n, no\nroute attributes) are detected and disclosed rather than silently absent.\n\nThe exact parameter names, for clients that call the tools directly. Most tools take `fqn`\n\n— the\nsymbol's fully qualified name — not `symbol`\n\n, `name`\n\n, or `type`\n\n; a wrong parameter name fails the\ncall.\n\n| Tool | Parameters | Description |\n|---|---|---|\n`find_symbol` |\n`query` (required), `kind` (optional) |\nSearch symbols by name or FQN, case-insensitive substring; returns kind, FQN, and file for up to 20 matches. |\n`get_architecture_overview` |\n(none) |\nProjects, project-to-project dependencies, node/edge counts by kind, and top-level namespaces. |\n`get_symbol_source` |\n`fqn` (required), `context_lines` (optional, 0–20, default 5) |\nPrint a symbol's source, read from its file at the declaration span. |\n`find_usages` |\n`fqn` (required) |\nWhere a symbol is called or referenced — containing member, file, and line, up to 50. |\n`get_dependencies` |\n`fqn` (required), `direction` (optional: , `outgoing` /`incoming` , default `outgoing` )`depth` (optional, 1–3, default 1) |\nA symbol's dependencies grouped by relationship kind (Calls, Implements, Inherits, References). |\n`find_implementations` |\n`fqn` (required) |\nConcrete types implementing an interface / deriving from a base, or members overriding a virtual/interface member. |\n`get_type_hierarchy` |\n`fqn` (required), `direction` (optional: , `up` /`down` /`both` , default `both` )`depth` (optional, 1–10, default 5) |\nBase and/or derived type tree as an indented text tree. |\n`get_project_dependencies` |\n`project` (optional, default `all` ) |\nProject-to-project reference map with cross-project reference counts and a hotspot line. |\n`impact_analysis` |\n`fqn` (required) |\nEvery symbol that transitively depends on the given one (depth 5) — counts first, then nearest-first. |\n`find_tests_for_symbol` |\n`fqn` (required) |\nTest members that transitively exercise a symbol, grouped by project with file:line. |\n`find_circular_dependencies` |\n`scope` (optional: `project` /`namespace` , default `project` ) |\nDependency cycles reported as path chains, worst offenders first. |\n`list_endpoints` |\n`verb` (optional: , `GET` /`POST` /`PUT` /`DELETE` /`PATCH` )`prefix` (optional route prefix, e.g. `/api/vendors` ) |\nHTTP endpoints (Minimal APIs + attribute-routed controllers) grouped by project: `VERB /route → handler — file:line` ; unresolved registrations and conventionally-routed controllers disclosed in trailing notes. |\n`find_endpoint` |\n`route` (required: a template or a concrete path), `verb` (optional) |\nEndpoints matching a route — case-insensitive, `{param}` holes bind concrete segments; a miss suggests near matches. |\n\n```\nslnmap analyze <solution>   # build or update the code graph (incremental on re-run)\nslnmap serve                # serve the graph to MCP clients over stdio\nslnmap status               # show node/edge counts and when it was last analyzed\nslnmap viz                  # export the graph as a self-contained interactive HTML file\nslnmap doctor               # check the environment can run Slnmap\n```\n\nThese five verbs are the whole CLI. Symbol, usage, and impact querying is MCP-only — there is no\n`find`\n\n/`usages`\n\n/`impact`\n\ncommand; connect an MCP client to `slnmap serve`\n\nto query the graph.\n\n`--db <path>`\n\nselects the database file (default `slnmap.db`\n\n). `-v`\n\n/`--verbose`\n\nprints per-document\nprogress on its own line per update — useful in an interactive terminal, but it floods piped or\nredirected output (logs, CI), so omit it there.\n\n```\nslnmap viz --output graph.html      # export the whole graph\nslnmap viz --project YourProject    # export one project's subtree; others render as collapsed stubs\n```\n\nOpens as a single HTML file — double-click it, no server or internet connection required. It starts collapsed to one node per project; click a project, namespace, or class to drill into it. Like the rest of Slnmap, the export is self-contained: the graph library is embedded in the file, so nothing is fetched from a CDN and it works fully offline.\n\n.NET tools do not update themselves, and Slnmap makes no network calls — so it will never nag you about (or check for) new versions. To update:\n\n```\ndotnet tool update -g Slnmap\n```\n\nTo hear about releases, watch the GitHub repo (**Watch → Custom → Releases**); each release ships\nwith notes in the [changelog](/EMahmoudNabil/slnmap/blob/main/CHANGELOG.md). After a major-version update, re-run\n`slnmap analyze`\n\nif the tool asks for it — release notes call out when a graph rebuild is needed.\n\nSlnmap is a standard .NET solution — clone, build, and test it with the SDK:\n\n```\ngit clone https://github.com/EMahmoudNabil/slnmap.git\ncd slnmap\ndotnet build -c Release\ndotnet test  -c Release\n```\n\nTo run the CLI without installing the global tool:\n\n```\ndotnet run --project src/Slnmap.Cli -- analyze path/to/YourSolution.sln\n```\n\nAnalyzes C# solutions targeting .NET 8 and .NET 9 (earlier targets are untested — feedback welcome); runs on Windows, macOS, and Linux; works with any MCP client (tested with Claude Code).\n\n**100% local — and now you can verify it.** Slnmap runs on your machine, reads your source with\nRoslyn, and writes a single local SQLite file. The MCP server reads only that local file. There is no\ntelemetry, no network calls, and no cloud service — analysis works fully offline. Now that the CLI and\nMCP server are open source, that claim is auditable: read the code, or watch the process — nothing\nleaves your machine.\n\nMeasured on [ eShopOnWeb](https://github.com/dotnet-architecture/eShopOnWeb) (10 projects,\n\n`net8.0`\n\n),\n.NET 9 SDK, on a 2-core laptop. Each timing is the median of 3 runs; full methodology, machine spec,\nand pinned commit are in [BENCHMARKS.md](/EMahmoudNabil/slnmap/blob/main/BENCHMARKS.md).\n\n| Metric | Result |\n|---|---|\n| Graph size | 1,332 nodes / 3,014 edges |\n| Cold analyze (10 projects) | ~20.9 s (median of 3) |\n| Re-analyze after a one-file change | ~18.7 s (median of 3 — see note) |\n`impact_analysis` on `IBasketService` (29 dependents, last measured v0.5.0) |\n~240–290 ms (end-to-end MCP round-trip) |\n\nNumbers are for v0.6.0: fully-qualified type references (no `using`\n\nshortcut) now produce edges,\nand events are modeled as graph nodes (see the [changelog](/EMahmoudNabil/slnmap/blob/main/CHANGELOG.md)) — the fully-qualified-\nreference fix accounts for nearly all of this release's edge growth (89 of 92 new edges) versus\nv0.5.0 (1,311 / 2,922 edges). Timings are flat within normal run-to-run noise; the analyzer's\nper-document work is otherwise unchanged. Full before/after detail, including the v0.5.0 and\nv0.3.0 baselines, is in [BENCHMARKS.md](/EMahmoudNabil/slnmap/blob/main/BENCHMARKS.md).\n\nTo estimate your own solution's cold analyze time, scale by size rather than anchoring on any single\nnumber above: field measurements on real-world solutions (antivirus real-time protection on, no\nexclusions) come out at roughly **55–60 seconds per 1,000 analyzed documents**. Treat it as\napproximate — hardware and antivirus overhead move it either way.\n\n**Incremental re-analysis.** Re-analysis re-walks only the changed file and its dependents, but each\nrun still pays a full workspace load of the solution — because the CLI is run-and-exit and does not\nkeep a warm workspace. In practice that means re-analysis is currently **about as fast as a cold run,\nnot faster**. A resident ** watch mode** that keeps the workspace warm (targeting sub-second\nre-analysis) is the top item on the roadmap.\n\nRun ** slnmap doctor** first — it checks the three things that actually block analysis and prints a\nfix for each:\n\n``` bash\n$ slnmap doctor\n[ok] .NET SDK: 1 SDK(s) installed; newest: 9.0.314 …\n[ok] MSBuild workspace: Roslyn MSBuild workspace initialized …\n[ok] Graph directory: Writable: /path/to/cwd\n```\n\n**\"No .NET SDKs are installed\" / MSBuild fails to load projects.** Slnmap analyzes via`MSBuildWorkspace`\n\n, which runs design-time builds using your installed .NET SDK. Install the SDK (not just the runtime) from[https://dotnet.microsoft.com/download](https://dotnet.microsoft.com/download). On**Windows**, if projects still fail to load, install the** Visual Studio Build Tools**(or Visual Studio) so MSBuild and the targeting packs resolve.** Analysis reports warnings but finishes.**That is expected and safe: a project that can't be loaded (e.g. a missing SDK or targeting pack) is reported as a warning and skipped — Slnmap indexes everything that*did*load rather than failing the whole run (a*partial load*). By default these are condensed into a single`Warnings: N (M unique)`\n\nsummary line; run`slnmap analyze --verbose`\n\nfor the full, grouped detail.**The first analysis of a large solution takes a while.** Cold analysis compiles every project once; as a rough guide from field measurements, expect around**55–60 seconds per 1,000 analyzed documents**(approximate). Re-runs are faster on graph work but still reload the workspace — see the performance note above. This is normal; the graph is cached in`slnmap.db`\n\nbetween runs.**Windows Defender (or other antivirus) slows analysis.** Real-time protection scans every file Roslyn reads while compiling your solution. Adding an exclusion for your repository folder can speed analysis up, but changing exclusions requires local admin rights — corporate users without them may need an IT ticket. No exclusion is required for correctness: analysis completes fine without one, and the ~55–60 s per 1,000 documents guide above was measured with real-time protection on and no exclusions in place.Ensure the .NET global tools directory (`slnmap: command not found`\n\nafter install.`~/.dotnet/tools`\n\n) is on your`PATH`\n\n, then open a new shell.\n\nSlnmap uses the Roslyn compiler platform to build a precise semantic graph of your solution — every type and member, and the relationships between them (calls, implementations, inheritance, references). The graph is stored locally and served to your AI agent or editor over MCP. Updates are incremental and crash-safe: an interrupted run never corrupts your existing graph.\n\nSlnmap is open source under the [MIT license](/EMahmoudNabil/slnmap/blob/main/LICENSE).\n\nThe CLI and MCP server are MIT-licensed and will stay that way. Future hosted or team-oriented features may be commercial.\n\nFor questions or to report an issue, open a [GitHub issue](https://github.com/EMahmoudNabil/slnmap/issues)\nor contact ** hello@slnmap.dev**. Contributions are welcome — see\n\n[CONTRIBUTING.md](/EMahmoudNabil/slnmap/blob/main/CONTRIBUTING.md).", "url": "https://wpnews.pro/news/show-hn-slnmap-roslyn-based-code-graph-mcp-server-for-net-codebases", "canonical_source": "https://github.com/EMahmoudNabil/slnmap", "published_at": "2026-08-12 15:00:59+00:00", "updated_at": "2026-08-12 15:12:49.103118+00:00", "lang": "en", "topics": ["developer-tools", "ai-tools", "ai-agents"], "entities": ["Slnmap", "Roslyn", "MCP", ".NET SDK", "ASP.NET Core", "Claude Code"], "alternates": {"html": "https://wpnews.pro/news/show-hn-slnmap-roslyn-based-code-graph-mcp-server-for-net-codebases", "markdown": "https://wpnews.pro/news/show-hn-slnmap-roslyn-based-code-graph-mcp-server-for-net-codebases.md", "text": "https://wpnews.pro/news/show-hn-slnmap-roslyn-based-code-graph-mcp-server-for-net-codebases.txt", "jsonld": "https://wpnews.pro/news/show-hn-slnmap-roslyn-based-code-graph-mcp-server-for-net-codebases.jsonld"}}