debug-live
Drive an interactive VS Code debugger to investigate bugs, failing tests, wrong/null variable values, unexpected runtime behavior, and other "it doesn't work"…
npx skills add https://github.com/microsoft/debugmcp --skill debug-liveDebugMCP — Interactive Debugging Skill
This skill teaches an agent how to use the DebugMCP MCP server effectively. The MCP server itself exposes only tools (with brief, behavioral descriptions); the workflow, root cause analysis framework, and language-specific guidance live here.
The
allowed-toolslist above uses the tool names registered by the DebugMCP MCP server. Some runtimes namespace MCP tools (e.g.mcp__debugmcp__start_debugging); adapt as needed.
When to invoke this skill
Invoke this skill as the first investigation step whenever you would otherwise guess at runtime behavior:
- Any reported bug, failing test, exception, or unexpected output.
- A variable holds an unexpected
null/undefined/ wrong type / wrong value. - A function returns something the caller didn't expect.
- A code path executes (or fails to execute) when you didn't predict it would.
- You're about to read a large amount of code "trying to figure out what happens at runtime."
Core workflow
-
Set a starting breakpoint. Use
add_breakpointwith the file path and the 1-based line number you want to pause on. Place it at the earliest point that's still relevant to the suspected issue. -
Optionally add strategic breakpoints. Decision points, error-handling branches, data boundaries (where input enters, where output is produced).
-
Start the session. Call
start_debuggingwith the source file path. For a single test, passtestName; the server routes through VS Code's Testing API so test runners likedotnet test/pytest/jestwork correctly. The call returns when the program either hits a breakpoint (stopped) or runs to completion without pausing (terminated). -
Navigate and inspect. Use
step_over,step_into,step_out,continue_executionto move through code. Usepause_executionto interrupt a freely-running program (e.g. a busy loop or embedded target) when there is no breakpoint to stop at. Uselist_variable_namesto see what is in scope (names and types only, no values), thenget_variables_valueswith the specificvariableNamesyou care about, andevaluate_expressionto test hypotheses live (call methods, read properties, run list comprehensions, etc.).get_variables_valuesrequires explicitvariableNames— it will not dump the whole scope. This is deliberate: a scope dump hands you unrelated process state such as API keys, tokens and environment variables. Values that still look like credentials are replaced with<redacted: possible secret>; don't try to work around it. -
Find the root cause (see framework below). Don't stop at the first wrong thing you see — trace it back to why.
-
Clean up. Call
clear_all_breakpointswhen you're done so you don't pollute the next session, andstop_debuggingif the session is still active.
🚨 Root cause analysis framework
Never stop at symptoms — always find the root cause
When you encounter an issue during debugging (null variable, unexpected value, thrown error, wrong branch taken), apply this systematic approach.
Symptom vs root cause
- Symptom: what you observed is wrong (e.g. "variable
useris null"). - Root cause: why the symptom occurred (e.g. "
useris null becausegetUserById()returned null because the DB query failed because the connection string inappsettings.jsonpoints at the wrong host").
Investigation process
- Identify the symptom. What exactly is wrong? Which line, which variable, which thrown exception? Record the current state.
- Ask "why?" Why is this value wrong? Why did this function return this? Why did this condition evaluate this way?
- Trace backwards. Set a breakpoint before the symptom, restart, and step forward to watch where the wrong state first appears.
- Repeat until you reach the origin. Keep asking "why" until you hit a fundamental cause — usually where data enters the system, a config is read, or an assumption is first violated.
⚠️ Warning signs you're stopping too early
- You found a
null/undefinedvariable but didn't check why it's that way. - You see an error but didn't trace where it originates.
- You identified "bad data" but didn't find why the data is bad.
- You found a failing condition but didn't check why it fails.
✅ Signs you've found the root cause
- You can explain the complete chain from root cause → symptom.
- Fixing this one thing would prevent the symptom from occurring.
- The issue is at a fundamental level (data input, configuration, logic invariant).
- You understand not just what is wrong but why it's wrong.
Practical examples
Example 1 — Null variable
❌ Symptom-only: "The user object is null on line 45."
✅ Root cause: "user is null because getUserById() returned null because the DB
query failed because the connection string is incorrect in the configuration file."
Investigation:
useris null → set breakpoint ingetUserById().getUserById()returns null → set breakpoint inside the function.- DB query fails → check connection parameters.
- Connection string wrong → root cause identified.
Example 2 — Function exits early
❌ Symptom-only: "processOrder() exits early due to invalid payment status."
✅ Root cause: "processOrder() exits early because payment validation fails when
the payment service doesn't receive the required currency field, which wasn't
included in the request due to a missing form field in the UI."
Investigation:
- Function exits early → breakpoint at validation check.
- Payment status invalid → debug payment validation logic.
currencymissing → trace back to request formation.- UI form missing
currencyfield → root cause identified.
Example 3 — Unexpected value
❌ Symptom-only: "Calculation result is NaN."
✅ Root cause: "The result is NaN because one input is a string instead of a
number, because parseFloat() fails when the input contains currency symbols that
weren't stripped by the sanitization function."
Investigation:
- Result is
NaN→ check input parameters. - Parameter is a string → find where conversion should happen.
parseFloat()fails → check what's being parsed.- Currency symbols not stripped → root cause identified.
Root cause investigation checklist
Before ending the debug session, confirm you can answer:
- What is the immediate symptom?
- What function / code caused this symptom?
- What input or condition caused that function to behave incorrectly?
- Where did that input or condition originate?
- Can I trace this back further to a more fundamental cause?
- If I fix this root cause, will it prevent the symptom from occurring?
Breakpoint strategy
- Start broad, then narrow. Begin at the entry point of the suspect function. As you isolate the issue, add tighter breakpoints around the problematic region.
- Use line numbers.
add_breakpointtakes a 1-basedline; re-check the line after edits since numbers shift when code changes. - Prefer logpoints for loops/hot paths. When you want to observe how a value evolves
across many iterations without stopping, use
add_logpointwith{expression}interpolation (e.g.iter {i}: total={total}) instead of repeatedly continuing from a breakpoint. Logpoints also avoid distorting timing-sensitive code. - Don't overuse breakpoints. A handful of well-placed pauses beats dozens of noisy
ones. After each session,
clear_all_breakpointsto start fresh. - For test debugging, pass
testNametostart_debugging. The server routes through VS Code's Testing API so test runners (dotnet test,pytest,jest, etc.) are driven correctly and the debugger attaches to the child test-host process.
Tool-call patterns
Investigating a bug in calculate.py
add_breakpoint fileFullPath=/repo/src/calculate.py line=42
start_debugging fileFullPath=/repo/src/calculate.py workingDirectory=/repo
# session pauses on the breakpoint
list_variable_names scope=local
get_variables_values variableNames=["raw","total"] scope=local
evaluate_expression expression="type(raw).__name__"
step_into
# … iterate until root cause found …
clear_all_breakpoints
Debugging a single xUnit test in C#
add_breakpoint fileFullPath=C:\Repo\Calculator.Tests\CalculatorTests.cs line=18
start_debugging fileFullPath=C:\Repo\Calculator.Tests\CalculatorTests.cs workingDirectory=C:\Repo testName=Add_ReturnsSum
# pauses inside the test
step_into
list_variable_names
get_variables_values variableNames=["result","expected"]
Verifying a fix without re-launching VS Code
restart_debugging
# session restarts with the same configuration; breakpoints persist
continue_execution
Language-specific guidance
Load the relevant reference file for the language you're debugging:
- Python →
references/troubleshooting/python.md - JavaScript / TypeScript →
references/troubleshooting/javascript.md - Java →
references/troubleshooting/java.md - C# →
references/troubleshooting/csharp.md - C++ →
references/troubleshooting/cpp.md - Go →
references/troubleshooting/go.md
Each reference covers prerequisites (which VS Code extension to install), framework-specific
configuration (e.g. enabling pytest test discovery, building .NET projects before
launch), and common pitfalls.
Multiple VS Code windows
VS Code normally brings a window to the foreground when its debugger stops. If a breakpoint or step in one workspace interrupts work in another VS Code window, recommend these native VS Code settings:
{
"debug.focusWindowOnBreak": false,
"debug.focusEditorOnBreak": false
}
debug.focusWindowOnBreak prevents the debugged window from taking operating-system focus.
The optional debug.focusEditorOnBreak setting also keeps focus out of the stopped source
editor. Do not change either persistent setting without the user's approval.
Things to avoid
- ❌ Adding temporary logs, print statements, or console output before debugging. Invoke this skill and inspect live state first. Use a debugger logpoint for non-breaking observation.
- ❌ Speculating about runtime values when you could just inspect them. That's what
get_variables_valuesandevaluate_expressionare for. - ❌ Calling
start_debuggingwithout first setting a breakpoint. The program will run to completion and you'll learn nothing. - ❌ Stopping at the first wrong value you find. That's a symptom. Trace it back.
- ❌ Leaving breakpoints set across sessions. Future runs will pause in unexpected
places. Always
clear_all_breakpointswhen done. - ❌ Awaiting interactive input when the program reads stdin. DebugMCP drives the VS Code debugger; if the program blocks on stdin, no tool call can unblock it. Pick a code path that doesn't require interactive input, or pre-supply input via the launch config / fixture.