About codereach-mcp
CodeReach is an MCP server for ASP.NET Core and C# solutions that builds a Roslyn-based call graph to trace code to endpoints and jobs. It helps developers inspect routes, dependencies, symbol usage, and the impact of changes from an agent or shell.
Key features
- 01Roslyn semantic call graph
- 02Trace symbols to endpoints and jobs
- 03Map git diffs to affected entry points
- 04Inspect routes and authorization
- 05Analyze dependency injection registrations
- 06Incremental on-disk indexing
Use cases
- 01Find API routes that call a method
- 02Identify endpoints and jobs affected by a diff
- 03Audit routes lacking authorization
- 04Trace service and repository calls
MCP support
Exposes analysis tools and ready-made prompts to MCP clients, including traces, route listings, usage searches, and change-impact reports.
Configuration
Local server config is the same for every client. Copy it into your client’s MCP config file.
We haven’t collected a package or remote endpoint for this server. Follow the instructions in the project README.
Tools
Local servers expose tools only once running on your machine, and the maintainer has not provided a tool list.
Details
From the project READMECodeReach
Which endpoints and jobs reach this code, and what does your diff affect.
CodeReach is an MCP server for ASP.NET Core and C# solutions. It loads your solution with Roslyn, builds a call graph from the compiler's own semantic model, keeps it on disk, and answers questions an agent (or you, from a shell) would otherwise answer with grep and guesswork:
- What calls this method, through its interface, all the way up to a controller action, a minimal API handler or a background service?
- Which endpoints exist, with their full route and authorization, including your own permission attributes?
- I changed these lines. Which endpoints and jobs does that touch?
Status: 0.1.0, not yet published to NuGet. The commands below that use dnx work once it is.
Why not grep, or a tree-sitter index
Text and syntax tools cannot see what the compiler sees. In a layered application (controller, service interface, service, repository interface, repository) they stop at the first interface, count comments and strings, attach calls to the wrong overload, and report a shared generic base method as every repository's hotspot. CodeReach binds every name with Roslyn, so:
- a call through
IOrderServicereachesOrderService, and says so; PermissionKeys.Orders.DeleteandPermissionKeys.Products.Deleteare different symbols;OrderRepository.GetByIdAsynccounts only calls anOrderRepositorycan receive, even though the method lives inRepository<T>;- tests are excluded because their project references a test framework, not because of a name;
- every tool reads one graph, so a caller count, a usage count and a trace never disagree.
Run it
Requires the .NET 10 SDK, and a solution that builds.
{
"mcpServers": {
"codereach": {
"command": "dnx",
"args": ["CodeReach.Mcp", "--yes"]
}
}
}
The server indexes the single .slnx, .sln or .csproj in its working directory. To point it
elsewhere, append "--", "--solution", "path/to/App.slnx" to args.
From a clone of this repository:
dotnet run --project src/CodeReach.Mcp -- call trace_to_entrypoints '{"symbol":"OrderRepository.HardDeleteAsync"}' --solution samples/SampleShop
entry points that reach OrderRepository.HardDeleteAsync(Guid)
4 entry points (3 endpoint, 1 hosted-service), 1 unrooted tops; 10 symbols visited. Hidden: 2 call sites in test projects (include_tests=true shows them).
[endpoint] DELETE /api/Orders/{id:guid} auth: HasPermission(PermissionKeys.Orders.Delete = "orders.delete") [action]; Authorize [base ShopControllerBase]
OrdersController.Delete(Guid) src/Shop.Api/Controllers/OrdersController.cs:17
-> OrderPurger.PurgeAsync(Guid) called at src/Shop.Api/Controllers/OrdersController.cs:19 (bound to IOrderPurger.PurgeAsync(Guid))
-> OrderRepository.HardDeleteAsync(Guid) called at src/Shop.Application/Orders/OrderService.cs:47 (bound to IOrderRepository.HardDeleteAsync(Guid))
[hosted-service] OrderPurgeService
OrderPurgeService.ExecuteAsync(CancellationToken) src/Shop.Infrastructure/Jobs/OrderPurgeService.cs:9
-> OrderPurgeService.PurgeExpiredAsync() called at src/Shop.Infrastructure/Jobs/OrderPurgeService.cs:13
...
A local page, if you prefer looking to asking
codereach ui --solution path/to/App.slnx
opens a page in your browser with a command bar (type a method, a route, impact or di) and a health
report: endpoints without authorization, captive dependencies, unregistered services, and what your
uncommitted changes reach. It is served by the tool itself on 127.0.0.1 with a one-time token, answers from
the same tools as above, and stops with Ctrl+C. Nothing is hosted anywhere.
CodeReach is a plain MCP server that runs entirely on your machine: no account, no hosted service, nothing sent anywhere. It installs no hooks, skills or agent profiles, never edits your client configuration, and writes nothing into the solution it analyses. Its index lives in your user cache directory.
Tools
| Tool | Answers |
|---|---|
trace_to_entrypoints | Every endpoint, hosted service and other root that reaches a symbol, with one call path each |
impact | A git diff (uncommitted changes, a base ref, or diff text) mapped to the endpoints and jobs it affects |
routes | Endpoints with verb, full route template, handler and authorization; auth=none lists the unprotected ones |
callers / callees | The call relation with interface and virtual dispatch resolved, to a chosen depth |
find_usages | Every reference bound to a symbol, by kind (call, read, write, nameof, attribute); works for framework members |
find_symbol | Declarations by name |
entrypoints | All roots a trace can stop at |
architecture | Projects, how much each really uses the others, most-called methods, most-implemented interfaces |
type_hierarchy | What a type inherits and implements, every type deriving from it (direct or indirect), its members and what each implements or overrides |
di_registrations | Every AddScoped/AddSingleton/AddTransient/TryAdd/keyed/hosted/AddHttpClient/AddDbContext registration and what each constructor asks for; reports captive dependencies, injected but unregistered services, and double registrations |
status / reindex | Index state and freshness; force a refresh |
Prompts
Ready-made requests that tell the agent which tools to call, in order. Every MCP client shows them; in
Claude Code they appear as /mcp__codereach__<name>.
| Prompt | Does |
|---|---|
review-diff | What your change affects: endpoints with auth, jobs, implementations that must change too, DI problems |
before-change | The blast radius of changing one symbol, and which tests cover it |
add-feature | Finds how similar features are built here and plans the files to add, following the same layers |
audit-auth | Endpoints with no authorization or anonymous access, ranked by risk |
explain-endpoint | One endpoint from route to data access, through every layer |
A symbol is named as Type.Member, as path/File.cs:line, or with an id from an earlier answer. An
ambiguous name is refused with the candidates listed. Every tool is also a shell command:
codereach call <tool> '{json}', exiting 0 when answered, 1 on a finding, 2 when it could not run.
What every answer tells you
- How much the default filters hid. "Hidden: 7 call sites in test projects."
- Whether the analysis was complete. The last line is
analysis: complete, orPARTIALwith the projects or documents that failed to load or bind. A zero is only printed for a complete analysis. - Whether the index is current. A first line starting with
STALEmeans files changed and the refresh is still running. - What it could not see. A call chain that ends where nothing calls it is reported as unrooted (dependency injection, reflection, or dead code), not silently dropped.
Staying fresh
The first index of a large solution takes about as long as a build. After that the index is a file: a server that starts on unchanged sources answers in milliseconds and never loads Roslyn. When files change, a body-only edit re-extracts that one document; a change to declarations re-extracts the project and the projects that depend on it. Freshness is checked on every call and does not rely on file watching.
Configuration
Optional codereach.json next to the solution:
{
// Attributes that mean authorization but implement no framework contract.
"authAttributes": ["HasPermission"],
// Fluent endpoint methods that mean authorization, besides RequireAuthorization.
"authEndpointMethods": ["RequirePermission"],
// Source that should not be indexed.
"exclude": ["**/Migrations/**"],
// Extra entry points: a method that implements an interface member, derives from a base type, or carries an attribute.
"entryPoints": [
{ "kind": "command-handler", "implements": "MyApp.ICommandHandler`1", "method": "HandleAsync" }
]
}
Attributes that implement the framework's own authorization contracts are recognised without configuration, and so are MediatR handlers, MassTransit consumers, Quartz jobs, middleware, SignalR hubs and Azure Functions.
What it does not model
- Implicit user-defined conversions, and the calls behind
foreach,using,await, deconstruction and collection initializers. - Reflection, and constructors invoked by a dependency injection container (registrations themselves are
read by
di_registrations, except those made by assembly scanning or inside a library). - Calls through an interface with several implementations are reported for every implementation the receiver's static type allows, and each hop says how many candidates there were.
- Global authorization (a fallback policy, a global authorize filter) is detected and reported next to the route list, not applied to individual endpoints.
- Conventional (non-attribute) MVC routes are listed as
(conventional). - C# only. Razor Pages, gRPC and SignalR are reachable through entry-point rules but are not listed as routes.
Development
dotnet build
dotnet test --project tests/CodeReach.Tests
The tests index samples/SampleShop, a small fictional layered application that contains every trap
listed above, and compare the result with Roslyn's own reference finder, with complete hand-audited route
tables, and with a from-scratch index after each kind of incremental edit. Design and plan are in
docs/ARCHITECTURE.md and docs/PLAN.md.
License
MIT
Comments
New to MCP?
From what the protocol is to installing your first server, these answers cover most first questions.
An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.