aspnetcore-debugger-mcp

What you can do with it

Nine everyday scenarios. Each shows what you’d ask Claude in plain English and what Claude might come back with. The wording is illustrative — the actual response depends on your code — but the shape of the conversation is real, and the values shown come from real runs.


Is the debugger set up correctly?

You

Before we start — is the debugger ready? I’m not sure if it picked up the right binary on my Mac.

Claude

I’ll check.

Yes — the bundled netcoredbg is healthy on your machine.

You’re good to launch a debug session whenever you want.

(under the hood: one call to debugger_health — reports RID, resolved netcoredbg path, source (bundled / env var / PATH), and --version)


Run my app in a different environment for one session

You

Run my API in Production mode against the staging DB — I want to see what config it actually picks up. Don’t change any of my files.

Claude

I’ll launch with the env vars set so ASP.NET Core picks up appsettings.Production.json on top of appsettings.json, and override the connection string in-memory only.

Launched with:

ASPNETCORE_ENVIRONMENT=Production
ConnectionStrings__Default=Server=staging.internal;Database=app

Then I called your /config-dump endpoint:

Environment       : Production
ConnectionString  : Server=staging.internal;Database=app
Logging:LogLevel  : Warning           (from appsettings.Production.json)
FeatureFlags:Beta : false             (from appsettings.json — no Production override)

No files were edited — the next run reverts to whatever your shell defaults to. If you want this combination saved, that’s a normal edit to appsettings.Production.json, separate from the debug session.

(under the hood: debug_launch with the env parameter — ASP.NET Core’s config layering does the rest)


Why is my endpoint returning the wrong data?

You

GET /hello/world is returning null for the greeting. Can you figure out why?

Claude

I’ll run your app, stop inside the /hello/{name} handler, and read the real values.

Here’s what I see at the moment the request hits:

Paused in Program.cs at line 6

    4: app.MapGet("/hello/{name}", (string name) =>
    5: {
→   6:     var greeting = $"Hello, {name}!";
    7:     var length = greeting.Length;
    8:     return Results.Ok(new { greeting, length });

Local values:
  name = "world"
  greeting = null   (not assigned yet)

The route parameter name came in as "world" like you’d expect. The reason the response looks wrong is in the lines below — there’s a string? name = null; further down that shadows the route parameter, and that’s the name that ends up in the JSON response.

Want me to test it by setting the local to a non-null value and continuing? If the response comes back correct, we’ve confirmed the diagnosis.

(under the hood: launch · breakpoint at line 6 · wait for request · read locals · evaluate expression)


Try a fix without editing my code

You

What if userId were "u-001" instead of empty? Would the rest of the function work?

Claude

Setting userId to "u-001" in the paused frame and continuing…

The function returned a real User object: { Id: "u-001", Name: "Alice", … }.

So the function itself works correctly when given a valid id. The bug is in the caller — something upstream is passing an empty string instead of the parsed id. Worth checking the code that builds the request.

(under the hood: change a value in a live frame · resume · check the result)


Why did my app throw this exception?

You

My app is throwing a NullReferenceException somewhere on this request. Catch it for me and tell me what’s going on.

Claude

I’ll set a break on unhandled exceptions and re-run the request.

Caught one. Here’s the full picture:

So you’ve declared a local name on line 7 that’s never assigned, and then dereferenced it on line 8. The ! is silencing the nullability warning but not the runtime crash.

Fix: either give it a real value or remove the local entirely (your route already has a name parameter that’s not null).

(under the hood: exception breakpoint · wait for the throw · one-call exception autopsy with the chain, frames, locals, and source snippet)


Show me the path a request takes through my code

You

Trace what happens when I hit GET /order/42. I want to see which methods get called and the parameter values at each one.

Claude

I’ll instrument the methods in your order pipeline (Controller → Service → Repository → SqlClient → EnrichmentService) and hit the endpoint. The instrumentation runs at near-normal speed — no manual breakpoints, no visible pauses.

Here’s the trace:

[+  679ms] → OrderController.GetOrder()       id=42, data=null
[+  711ms] --→ OrderService.LookupOrder()     id=42, raw=null, enriched=null
[+  735ms] ----→ OrderRepository.FetchById()  id=42
[+  759ms] ------→ SqlClient.ExecuteQuery()   sql="SELECT * FROM orders WHERE id = 42"
[+  783ms] ----→ EnrichmentService.Enrich()   raw="rows(sql=SELECT * FROM orders WHERE id …"

The arrows show the call depth — SqlClient.ExecuteQuery is 3 layers deep, called via Repository → Service → Controller. EnrichmentService.Enrich is at the same level as FetchById because the Service called Enrich after the Repository returned.

Every line is one real method entry with the actual argument values at that moment. The request completed normally and returned 200.

(under the hood: server-side tracing — methods you name get auto-captured + auto-resumed; your code runs at near-normal speed)


Where am I right now in the call stack?

You

I’ve hit a breakpoint deep inside the handler — show me the full call chain and what’s in scope at each level.

Claude

Microsoft.AspNetCore.Server.Kestrel...HttpProtocol.ProcessRequests()
     │
     ▼
Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware.Invoke()
     │
     ▼
[Native Frames]
     │
     ▼
Program.<>c.<<Main>$>b__0_0()   [Program.cs:6]  ◄ paused here
  name = "world", greeting = null, length = 0

You’re paused inside the request handler at line 6, called via the Kestrel pipeline. The immediately useful values are on the bottom frame — name = "world" from the URL, greeting and length aren’t assigned yet. The middleware frames above are mostly Kestrel internals you can ignore unless something’s going wrong in the pipeline itself.

(under the hood: one tool call returns the stack, the locals at every frame, and a rendered tree)


Why is my app hung?

You

My app is unresponsive. Can you check what every thread is doing and tell me what they’re waiting on?

Claude

Pausing and looking at every thread…

3 threads are blocked on synchronization primitives:

The other 4 threads are idle.

Looks like a classic sync-over-async pattern: Thread 1 called .Wait() on a Task that’s presumably waiting for one of the locks the other threads hold. Without the runtime telling me who owns which lock, I can’t draw the cycle for you — but the stack traces of threads 8 and 12 should point at the lock object.

(under the hood: pause-all + per-thread stack walk + classify the top frame against known blocking primitives)


Show me what the server is logging

You

Drain the server’s output since I last asked — I want to see what ASP.NET logged.

Claude

info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 GET http://localhost:5099/hello/world - null null
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 GET http://localhost:5099/hello/world - 200 - application/json; charset=utf-8 13.4ms
info: MyApp.UserService[0]
      Looking up user u-001

Two requests, both 200, plus your own ILogger lines. No errors.

(under the hood: the server buffers everything the debuggee writes to stdout/stderr; this drains the buffer)


See also