@ai-capabilities-suite/mcp-debugger-server
Version:
Enterprise-grade MCP server providing advanced debugging capabilities for Node.js and TypeScript applications. Features 25+ debugging tools including breakpoints, variable inspection, execution control, CPU/memory profiling, hang detection, source map sup
1,271 lines (1,019 loc) • 26.9 kB
Markdown
# MCP Debugger Server - API Documentation
## Overview
This document provides detailed API documentation for the MCP Debugger Server, including JSDoc-style documentation for all public APIs, CDP protocol interactions, and error codes.
## Table of Contents
- [Core Classes](#core-classes)
- [CDP Protocol Interactions](#cdp-protocol-interactions)
- [Error Codes](#error-codes)
- [Type Definitions](#type-definitions)
## Core Classes
### McpDebuggerServer
The main server class that implements the MCP protocol and exposes debugging tools.
```typescript
/**
* MCP Debugger Server
*
* Provides debugging capabilities for Node.js and TypeScript applications
* through the Model Context Protocol.
*
* @class McpDebuggerServer
* @example
* ```typescript
* const server = new McpDebuggerServer();
* await server.start();
* ```
*/
class McpDebuggerServer {
/**
* Creates a new MCP Debugger Server instance
*
* Initializes the MCP server with debugging capabilities and registers
* all available debugging tools.
*
* @constructor
*/
constructor();
/**
* Start the MCP server
*
* Connects the server to stdio transport and begins listening for
* MCP protocol messages.
*
* @async
* @returns {Promise<void>}
* @throws {Error} If the server fails to start
*/
async start(): Promise<void>;
/**
* Stop the MCP server and cleanup all sessions
*
* Terminates all active debug sessions, disconnects from all processes,
* and closes the MCP server connection.
*
* @async
* @returns {Promise<void>}
*/
async stop(): Promise<void>;
}
```
### SessionManager
Manages multiple concurrent debug sessions.
```typescript
/**
* Session Manager
*
* Manages the lifecycle of debug sessions, including creation, retrieval,
* and cleanup. Ensures session isolation and resource management.
*
* @class SessionManager
*/
class SessionManager {
/**
* Create a new debug session
*
* Spawns a Node.js process with the Inspector Protocol attached and
* creates a new DebugSession instance to manage it.
*
* @async
* @param {DebugSessionConfig} config - Session configuration
* @returns {Promise<DebugSession>} The created debug session
* @throws {Error} If the process fails to start or inspector fails to attach
*
* @example
* ```typescript
* const session = await sessionManager.createSession({
* command: 'node',
* args: ['app.js'],
* timeout: 30000
* });
* ```
*/
async createSession(config: DebugSessionConfig): Promise<DebugSession>;
/**
* Get an existing debug session by ID
*
* @param {string} sessionId - The session ID
* @returns {DebugSession | null} The session or null if not found
*/
getSession(sessionId: string): DebugSession | null;
/**
* Remove a debug session and cleanup resources
*
* Terminates the process, disconnects the inspector, and removes
* the session from the manager.
*
* @async
* @param {string} sessionId - The session ID to remove
* @returns {Promise<void>}
*/
async removeSession(sessionId: string): Promise<void>;
/**
* Cleanup all active sessions
*
* Called during server shutdown to ensure all resources are released.
*
* @async
* @returns {Promise<void>}
*/
async cleanupAll(): Promise<void>;
}
```
### DebugSession
Represents a single debug session with a Node.js process.
```typescript
/**
* Debug Session
*
* Manages a single debugging session with a Node.js process, including
* breakpoints, execution control, and variable inspection.
*
* @class DebugSession
*/
class DebugSession {
/**
* Session unique identifier
* @type {string}
*/
readonly id: string;
/**
* Set a breakpoint at a specific location
*
* Uses the Chrome DevTools Protocol to set a breakpoint. If a condition
* is provided, the breakpoint will only pause when the condition evaluates
* to true.
*
* @async
* @param {string} file - Absolute or relative file path
* @param {number} line - Line number (1-indexed)
* @param {string} [condition] - Optional condition expression
* @returns {Promise<Breakpoint>} The created breakpoint
* @throws {Error} If the breakpoint cannot be set
*
* @example
* ```typescript
* const bp = await session.setBreakpoint('/path/to/file.js', 42, 'x > 10');
* ```
*/
async setBreakpoint(
file: string,
line: number,
condition?: string
): Promise<Breakpoint>;
/**
* Remove a breakpoint by ID
*
* @async
* @param {string} breakpointId - The breakpoint ID
* @returns {Promise<boolean>} True if removed, false if not found
*/
async removeBreakpoint(breakpointId: string): Promise<boolean>;
/**
* Toggle a breakpoint's enabled state
*
* @async
* @param {string} breakpointId - The breakpoint ID
* @returns {Promise<Breakpoint | null>} The updated breakpoint or null
*/
async toggleBreakpoint(breakpointId: string): Promise<Breakpoint | null>;
/**
* Get all breakpoints in this session
*
* @returns {Breakpoint[]} Array of all breakpoints
*/
getAllBreakpoints(): Breakpoint[];
/**
* Resume execution until the next breakpoint or program termination
*
* Sends the Debugger.resume CDP command to continue execution.
*
* @async
* @returns {Promise<void>}
* @throws {Error} If the session is not paused
*/
async resume(): Promise<void>;
/**
* Step over the current line
*
* Executes the current line and pauses at the next line in the same scope.
* Uses the Debugger.stepOver CDP command.
*
* @async
* @returns {Promise<void>}
* @throws {Error} If the session is not paused
*/
async stepOver(): Promise<void>;
/**
* Step into the current line
*
* Executes the current line and pauses at the first line inside any
* called function. Uses the Debugger.stepInto CDP command.
*
* @async
* @returns {Promise<void>}
* @throws {Error} If the session is not paused
*/
async stepInto(): Promise<void>;
/**
* Step out of the current function
*
* Executes until the current function returns and pauses at the calling
* location. Uses the Debugger.stepOut CDP command.
*
* @async
* @returns {Promise<void>}
* @throws {Error} If the session is not paused
*/
async stepOut(): Promise<void>;
/**
* Pause execution
*
* Interrupts the running process and pauses at the current execution point.
* Uses the Debugger.pause CDP command.
*
* @async
* @returns {Promise<void>}
* @throws {Error} If the session is already paused
*/
async pause(): Promise<void>;
/**
* Evaluate an expression in the current execution context
*
* Uses Debugger.evaluateOnCallFrame to evaluate the expression in the
* context of the current call frame.
*
* @async
* @param {string} expression - JavaScript expression to evaluate
* @returns {Promise<EvaluationResult>} The evaluation result
* @throws {Error} If evaluation fails or session is not paused
*
* @example
* ```typescript
* const result = await session.evaluateExpression('user.name + " " + user.age');
* console.log(result.value); // "John 30"
* ```
*/
async evaluateExpression(expression: string): Promise<EvaluationResult>;
/**
* Get the current call stack
*
* Returns the complete call stack with function names, file locations
* (absolute paths), and line numbers.
*
* @async
* @returns {Promise<StackFrame[]>} Array of stack frames
* @throws {Error} If the session is not paused
*/
async getCallStack(): Promise<StackFrame[]>;
/**
* Switch to a different stack frame
*
* Changes the context for variable inspection to the specified frame.
* Frame 0 is the top frame (current location).
*
* @param {number} frameIndex - The frame index (0-based)
* @throws {Error} If the frame index is invalid
*/
switchToFrame(frameIndex: number): void;
/**
* Get object properties
*
* Uses Runtime.getProperties CDP command to retrieve all properties
* of an object by its object ID.
*
* @async
* @param {string} objectId - The object ID from a previous inspection
* @returns {Promise<Property[]>} Array of object properties
*/
async getObjectProperties(objectId: string): Promise<Property[]>;
/**
* Inspect an object with nested resolution
*
* Recursively inspects an object up to the specified depth, resolving
* nested objects and arrays.
*
* @async
* @param {string} objectId - The object ID
* @param {number} maxDepth - Maximum depth to traverse (default: 2)
* @returns {Promise<any>} The inspected object data
*/
async inspectObject(objectId: string, maxDepth: number): Promise<any>;
/**
* Add a watched variable
*
* Adds an expression to the watch list. The expression will be evaluated
* each time the process pauses.
*
* @param {WatchedVariable} watch - The watch configuration
*/
addWatchedVariable(watch: WatchedVariable): void;
/**
* Remove a watched variable
*
* @param {string} watchId - The watch ID (expression)
* @returns {boolean} True if removed, false if not found
*/
removeWatchedVariable(watchId: string): boolean;
/**
* Get all watched variables
*
* @returns {WatchedVariable[]} Array of watched variables
*/
getAllWatchedVariables(): WatchedVariable[];
/**
* Get watched variable changes since last pause
*
* @returns {Map<string, VariableChange>} Map of variable changes
*/
getWatchedVariableChanges(): Map<string, VariableChange>;
/**
* Get the current session state
*
* @returns {'paused' | 'running' | 'terminated'} The session state
*/
getState(): 'paused' | 'running' | 'terminated';
/**
* Check if the session is paused
*
* @returns {boolean} True if paused
*/
isPaused(): boolean;
/**
* Get the Node.js process
*
* @returns {ChildProcess | null} The process or null if terminated
*/
getProcess(): ChildProcess | null;
}
```
### HangDetector
Detects hanging processes and infinite loops.
```typescript
/**
* Hang Detector
*
* Monitors process execution to detect hangs and infinite loops using
* timeout-based detection and periodic call stack sampling.
*
* @class HangDetector
*/
class HangDetector {
/**
* Detect if a process hangs or enters an infinite loop
*
* Starts a debug session and monitors execution. If the process doesn't
* complete within the timeout, or if the execution location remains
* unchanged across multiple samples, a hang is detected.
*
* @async
* @param {HangDetectionConfig} config - Detection configuration
* @returns {Promise<HangDetectionResult>} The detection result
*
* @example
* ```typescript
* const result = await hangDetector.detectHang({
* command: 'node',
* args: ['script.js'],
* timeout: 5000,
* sampleInterval: 100
* });
*
* if (result.hung) {
* console.log('Hung at:', result.location);
* console.log('Stack:', result.stack);
* }
* ```
*/
async detectHang(config: HangDetectionConfig): Promise<HangDetectionResult>;
}
```
## CDP Protocol Interactions
The MCP Debugger Server uses the Chrome DevTools Protocol (CDP) to communicate with the Node.js Inspector. Below are the key CDP domains and commands used.
### Debugger Domain
The Debugger domain provides debugging functionality.
#### Debugger.enable
Enables the debugger for the target.
**CDP Command:**
```json
{
"method": "Debugger.enable"
}
```
**Usage:**
Called during session initialization to enable debugging capabilities.
#### Debugger.setBreakpointByUrl
Sets a breakpoint at a specific URL and line number.
**CDP Command:**
```json
{
"method": "Debugger.setBreakpointByUrl",
"params": {
"lineNumber": 41,
"url": "file:///path/to/file.js",
"columnNumber": 0,
"condition": "x > 10"
}
}
```
**Response:**
```json
{
"breakpointId": "1:41:0:file:///path/to/file.js",
"locations": [
{
"scriptId": "123",
"lineNumber": 41,
"columnNumber": 0
}
]
}
```
**Usage:**
Called by `setBreakpoint()` to create breakpoints.
#### Debugger.removeBreakpoint
Removes a breakpoint by ID.
**CDP Command:**
```json
{
"method": "Debugger.removeBreakpoint",
"params": {
"breakpointId": "1:41:0:file:///path/to/file.js"
}
}
```
**Usage:**
Called by `removeBreakpoint()` to delete breakpoints.
#### Debugger.resume
Resumes execution.
**CDP Command:**
```json
{
"method": "Debugger.resume"
}
```
**Usage:**
Called by `resume()` to continue execution.
#### Debugger.stepOver
Steps over the current line.
**CDP Command:**
```json
{
"method": "Debugger.stepOver"
}
```
**Usage:**
Called by `stepOver()` to execute the current line and pause at the next.
#### Debugger.stepInto
Steps into the current line.
**CDP Command:**
```json
{
"method": "Debugger.stepInto"
}
```
**Usage:**
Called by `stepInto()` to step into function calls.
#### Debugger.stepOut
Steps out of the current function.
**CDP Command:**
```json
{
"method": "Debugger.stepOut"
}
```
**Usage:**
Called by `stepOut()` to return from the current function.
#### Debugger.pause
Pauses execution.
**CDP Command:**
```json
{
"method": "Debugger.pause"
}
```
**Usage:**
Called by `pause()` to interrupt running execution.
#### Debugger.evaluateOnCallFrame
Evaluates an expression in the context of a call frame.
**CDP Command:**
```json
{
"method": "Debugger.evaluateOnCallFrame",
"params": {
"callFrameId": "frame-id",
"expression": "user.name",
"returnByValue": true
}
}
```
**Response:**
```json
{
"result": {
"type": "string",
"value": "John"
}
}
```
**Usage:**
Called by `evaluateExpression()` to evaluate expressions.
#### Debugger.paused (Event)
Fired when execution pauses.
**CDP Event:**
```json
{
"method": "Debugger.paused",
"params": {
"reason": "breakpoint",
"callFrames": [
{
"callFrameId": "frame-id",
"functionName": "myFunction",
"location": {
"scriptId": "123",
"lineNumber": 41,
"columnNumber": 0
},
"scopeChain": [...]
}
]
}
}
```
**Usage:**
Listened to by the session to update state and call frames.
#### Debugger.resumed (Event)
Fired when execution resumes.
**CDP Event:**
```json
{
"method": "Debugger.resumed"
}
```
**Usage:**
Listened to by the session to update state.
### Runtime Domain
The Runtime domain provides runtime information and object inspection.
#### Runtime.enable
Enables the runtime for the target.
**CDP Command:**
```json
{
"method": "Runtime.enable"
}
```
**Usage:**
Called during session initialization.
#### Runtime.getProperties
Gets properties of an object.
**CDP Command:**
```json
{
"method": "Runtime.getProperties",
"params": {
"objectId": "object-id",
"ownProperties": true
}
}
```
**Response:**
```json
{
"result": [
{
"name": "propertyName",
"value": {
"type": "string",
"value": "propertyValue"
}
}
]
}
```
**Usage:**
Called by `getObjectProperties()` and `inspectObject()`.
## Error Codes
All error responses follow this structure:
```json
{
"status": "error",
"code": "ERROR_CODE",
"message": "Human-readable error message"
}
```
### Session Errors
#### SESSION_NOT_FOUND
**Description:** The specified session ID doesn't exist.
**Causes:**
- Invalid session ID provided
- Session was already terminated
- Session expired
**Resolution:**
- Verify the session ID is correct
- Start a new session with `debugger_start`
#### SESSION_START_FAILED
**Description:** Failed to start the debug session.
**Causes:**
- Invalid command or arguments
- Process failed to spawn
- Inspector failed to attach
- Timeout waiting for inspector
**Resolution:**
- Verify the command and arguments are correct
- Check that Node.js is installed and accessible
- Increase the timeout parameter
- Check process stderr for error messages
### Breakpoint Errors
#### BREAKPOINT_SET_FAILED
**Description:** Failed to set the breakpoint.
**Causes:**
- Invalid file path
- Line number out of range
- Script not loaded yet
- Invalid condition expression
**Resolution:**
- Use absolute file paths
- Verify the line number is valid
- Wait for the script to load before setting breakpoints
- Check the condition expression syntax
#### BREAKPOINT_NOT_FOUND
**Description:** The specified breakpoint doesn't exist.
**Causes:**
- Invalid breakpoint ID
- Breakpoint was already removed
**Resolution:**
- Use `debugger_list_breakpoints` to get valid breakpoint IDs
- Verify the breakpoint wasn't already removed
### Execution Errors
#### CONTINUE_FAILED
**Description:** Failed to resume execution.
**Causes:**
- Session is not paused
- Process has terminated
- CDP command failed
**Resolution:**
- Ensure the session is paused before calling continue
- Check if the process is still running
#### STEP_OVER_FAILED
**Description:** Failed to step over.
**Causes:**
- Session is not paused
- Process has terminated
- At the end of execution
**Resolution:**
- Ensure the session is paused
- Check if there are more lines to execute
#### STEP_INTO_FAILED
**Description:** Failed to step into.
**Causes:**
- Session is not paused
- No function call on current line
- Process has terminated
**Resolution:**
- Ensure the session is paused
- Verify there's a function call to step into
#### STEP_OUT_FAILED
**Description:** Failed to step out.
**Causes:**
- Session is not paused
- Already at the top level
- Process has terminated
**Resolution:**
- Ensure the session is paused
- Verify you're inside a function
#### PAUSE_FAILED
**Description:** Failed to pause execution.
**Causes:**
- Session is already paused
- Process has terminated
- CDP command failed
**Resolution:**
- Check the session state before pausing
- Verify the process is still running
### Inspection Errors
#### INSPECT_FAILED
**Description:** Failed to evaluate expression.
**Causes:**
- Session is not paused
- Invalid expression syntax
- Variable not in scope
- Expression threw an error
**Resolution:**
- Ensure the session is paused
- Check the expression syntax
- Verify variables are in scope
- Handle expression errors gracefully
#### GET_STACK_FAILED
**Description:** Failed to get call stack.
**Causes:**
- Session is not paused
- No call frames available
- CDP command failed
**Resolution:**
- Ensure the session is paused
- Verify execution has started
#### NOT_PAUSED
**Description:** Operation requires the process to be paused.
**Causes:**
- Trying to inspect variables while running
- Trying to step while running
**Resolution:**
- Set a breakpoint and continue to it
- Use `debugger_pause` to pause execution
#### GET_LOCAL_VARIABLES_FAILED
**Description:** Failed to get local variables.
**Causes:**
- Session is not paused
- No local scope available
- CDP command failed
**Resolution:**
- Ensure the session is paused
- Verify you're inside a function
#### GET_GLOBAL_VARIABLES_FAILED
**Description:** Failed to get global variables.
**Causes:**
- Session is not paused
- No global scope available
- CDP command failed
**Resolution:**
- Ensure the session is paused
#### INSPECT_OBJECT_FAILED
**Description:** Failed to inspect object.
**Causes:**
- Invalid object ID
- Object no longer exists
- CDP command failed
**Resolution:**
- Verify the object ID is valid
- Re-evaluate the expression to get a fresh object ID
### Watch Errors
#### ADD_WATCH_FAILED
**Description:** Failed to add watched variable.
**Causes:**
- Invalid expression
- Internal error
**Resolution:**
- Check the expression syntax
#### REMOVE_WATCH_FAILED
**Description:** Failed to remove watched variable.
**Causes:**
- Internal error
**Resolution:**
- Retry the operation
#### WATCH_NOT_FOUND
**Description:** The specified watch doesn't exist.
**Causes:**
- Invalid watch ID
- Watch was already removed
**Resolution:**
- Use `debugger_get_watches` to get valid watch IDs
#### GET_WATCHES_FAILED
**Description:** Failed to get watched variables.
**Causes:**
- Internal error
**Resolution:**
- Retry the operation
### Frame Errors
#### SWITCH_FRAME_FAILED
**Description:** Failed to switch stack frame.
**Causes:**
- Invalid frame index
- Session is not paused
- No call frames available
**Resolution:**
- Use `debugger_get_stack` to get valid frame indices
- Ensure the session is paused
### Hang Detection Errors
#### HANG_DETECTION_FAILED
**Description:** Failed to detect hang.
**Causes:**
- Failed to start process
- Inspector failed to attach
- Internal error
**Resolution:**
- Verify the command and arguments
- Check process stderr for errors
- Retry with different parameters
### Cleanup Errors
#### STOP_SESSION_FAILED
**Description:** Failed to stop the session.
**Causes:**
- Session already stopped
- Internal error during cleanup
**Resolution:**
- The session may already be terminated
- Check if resources were released
#### REMOVE_BREAKPOINT_FAILED
**Description:** Failed to remove breakpoint.
**Causes:**
- CDP command failed
- Breakpoint already removed
**Resolution:**
- Verify the breakpoint exists
- Retry the operation
#### TOGGLE_BREAKPOINT_FAILED
**Description:** Failed to toggle breakpoint.
**Causes:**
- CDP command failed
- Breakpoint doesn't exist
**Resolution:**
- Verify the breakpoint exists
- Use `debugger_list_breakpoints` to check status
#### LIST_BREAKPOINTS_FAILED
**Description:** Failed to list breakpoints.
**Causes:**
- Internal error
**Resolution:**
- Retry the operation
## Type Definitions
### DebugSessionConfig
Configuration for creating a debug session.
```typescript
interface DebugSessionConfig {
/** The command to execute (e.g., "node", "npm") */
command: string;
/** Command arguments (e.g., ["test.js"]) */
args?: string[];
/** Working directory for the process */
cwd?: string;
/** Timeout in milliseconds (default: 30000) */
timeout?: number;
}
```
### Breakpoint
Represents a breakpoint in a debug session.
```typescript
interface Breakpoint {
/** Unique breakpoint identifier */
id: string;
/** Absolute file path */
file: string;
/** Line number (1-indexed) */
line: number;
/** Optional condition expression */
condition?: string;
/** Whether the breakpoint is enabled */
enabled: boolean;
/** CDP breakpoint ID (present if verified) */
cdpBreakpointId?: string;
}
```
### StackFrame
Represents a call stack frame.
```typescript
interface StackFrame {
/** Function name (or "<anonymous>") */
functionName: string;
/** Absolute file path */
file: string;
/** Line number (1-indexed) */
line: number;
/** Column number (0-indexed) */
column: number;
/** CDP call frame ID */
callFrameId?: string;
}
```
### EvaluationResult
Result of evaluating an expression.
```typescript
interface EvaluationResult {
/** The evaluated value */
value: any;
/** The value type (e.g., "string", "number", "object") */
type: string;
/** Object ID if the value is an object */
objectId?: string;
}
```
### Property
Represents an object property.
```typescript
interface Property {
/** Property name */
name: string;
/** Property value */
value: any;
/** Property type */
type: string;
/** Object ID if the value is an object */
objectId?: string;
}
```
### WatchedVariable
Represents a watched variable.
```typescript
interface WatchedVariable {
/** Watch identifier (expression) */
name: string;
/** Expression to evaluate */
expression: string;
/** Last evaluated value */
lastValue?: any;
}
```
### VariableChange
Represents a change in a watched variable.
```typescript
interface VariableChange {
/** Old value */
oldValue: any;
/** New value */
newValue: any;
}
```
### HangDetectionConfig
Configuration for hang detection.
```typescript
interface HangDetectionConfig {
/** The command to execute */
command: string;
/** Command arguments */
args?: string[];
/** Working directory */
cwd?: string;
/** Timeout in milliseconds */
timeout: number;
/** Sample interval for loop detection (default: 100ms) */
sampleInterval?: number;
}
```
### HangDetectionResult
Result of hang detection.
```typescript
interface HangDetectionResult {
/** Whether the process hung */
hung: boolean;
/** Location where the process hung (if hung) */
location?: string;
/** Call stack at hang location (if hung) */
stack?: StackFrame[];
/** Hang message (if hung) */
message?: string;
/** Whether the process completed normally (if not hung) */
completed?: boolean;
/** Exit code (if completed) */
exitCode?: number;
/** Execution duration in milliseconds */
duration: number;
}
```
## Best Practices
### Error Handling
Always handle errors gracefully:
```typescript
try {
const result = await session.evaluateExpression('user.name');
console.log(result.value);
} catch (error) {
if (error.code === 'NOT_PAUSED') {
// Pause the session first
await session.pause();
// Retry
const result = await session.evaluateExpression('user.name');
} else {
console.error('Evaluation failed:', error.message);
}
}
```
### Resource Cleanup
Always cleanup sessions when done:
```typescript
const session = await sessionManager.createSession(config);
try {
// Use the session
await session.setBreakpoint('file.js', 42);
await session.resume();
} finally {
// Always cleanup
await sessionManager.removeSession(session.id);
}
```
### Breakpoint Verification
Check if breakpoints are verified before relying on them:
```typescript
const bp = await session.setBreakpoint('file.js', 42);
if (!bp.cdpBreakpointId) {
console.warn('Breakpoint not verified - may not hit');
}
```
### Timeout Configuration
Use appropriate timeouts for different scenarios:
```typescript
// Short timeout for unit tests
const testSession = await sessionManager.createSession({
command: 'node',
args: ['test.js'],
timeout: 10000 // 10 seconds
});
// Longer timeout for integration tests
const integrationSession = await sessionManager.createSession({
command: 'node',
args: ['integration-test.js'],
timeout: 60000 // 60 seconds
});
```
## See Also
- [README.md](./README.md) - User documentation and usage examples
- [TESTING.md](./TESTING.md) - Testing documentation
- [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) - CDP specification
- [Node.js Inspector API](https://nodejs.org/api/inspector.html) - Node.js debugging API