⚠️ DRAFT DOCUMENTATION This API reference reflects the v2.x monorepo architecture with dynamic adapter loading.
- IDebugAdapter Interface
- SessionManager API
- ProxyManager API
- AdapterRegistry API
- Event System
- Type Definitions
The core interface that all language adapters must implement.
Source: packages/shared/src/interfaces/debug-adapter.ts
readonly language: DebugLanguage; // Language identifier
readonly name: string; // Human-readable adapter nameInitializes the adapter and prepares it for use.
When called: After adapter creation, before any operations
Expected behavior: Validate environment, set up internal state
Emits: 'initialized' event on success
Cleans up resources and connections.
When called: When session ends or adapter is no longer needed
Expected behavior: Close connections, clean up resources
Emits: 'disposed' event
Returns the current adapter state.
Returns: One of: UNINITIALIZED, INITIALIZING, READY, CONNECTED, DEBUGGING, DISCONNECTED, ERROR
Quick check if adapter is ready for debugging.
Returns: true if adapter can accept debug operations
Gets the currently active thread ID during debugging.
Returns: Thread ID or null if not debugging
Comprehensive environment check for debugging readiness.
Returns:
{
valid: boolean;
errors: ValidationError[];
warnings: ValidationWarning[];
}Example:
const result = await adapter.validateEnvironment();
if (!result.valid) {
console.error('Environment issues:', result.errors);
}Lists all dependencies needed for debugging.
Returns: Array of dependency information with install commands
Finds or validates the language runtime executable.
Parameters:
preferredPath- User-specified path (optional)
Returns: Resolved executable path
Throws: AdapterError if executable not found
Platform-aware default executable name.
Returns: e.g., 'python', 'node', 'go'
Paths to search for the executable.
Returns: Array of paths (usually from PATH environment variable)
Constructs the command to launch the debug adapter process.
Parameters:
{
sessionId: string;
executablePath: string;
adapterHost: string;
adapterPort: number;
logDir: string;
scriptPath: string;
scriptArgs?: string[];
launchConfig: GenericLaunchConfig;
}Returns:
{
command: string; // Executable to run
args: string[]; // Command line arguments
env?: Record<string, string>; // Environment variables
}Debug adapter module identifier.
Returns: e.g., 'debugpy.adapter', 'js-debug'
Command to install the debug adapter.
Returns: e.g., 'pip install debugpy', 'bundled with @debugmcp/adapter-javascript'
Converts generic config to language-specific format (async to permit build/compilation steps before launch).
Parameters: Generic launch configuration Returns: Promise resolving to language-specific configuration with additional fields
Default configuration values for the language.
Returns: Common default settings
Checks if the adapter supports attaching to running processes.
Returns: true if attach is supported
Checks if the adapter supports detaching without terminating the debuggee.
Returns: true if detach is supported
Transforms generic attach config to language-specific format. Only called if supportsAttach() returns true.
Parameters: Generic attach configuration Returns: Language-specific attach configuration
Gets default attach configuration for this language.
Returns: Default attach configuration with language-specific defaults
Optionally provides a launch barrier that customizes how ProxyManager coordinates a specific DAP request (e.g., fire-and-forget launches).
Parameters:
command- The DAP command nameargs- Optional command arguments
Returns: An AdapterLaunchBarrier instance or undefined
Sends a DAP request (usually delegated to ProxyManager).
Parameters:
command- DAP command nameargs- Command arguments
Returns: DAP response
Processes incoming DAP events.
Critical: Must update internal state based on events!
Example:
handleDapEvent(event: DebugProtocol.Event): void {
if (event.event === 'stopped') {
this.currentThreadId = event.body?.threadId;
this.transitionTo(AdapterState.DEBUGGING);
}
this.emit(event.event, event.body);
}Processes DAP responses if special handling needed.
Establishes connection to debug adapter.
Parameters: Host and port for connection
Emits: 'connected' event on success
Closes debug adapter connection.
Emits: 'disconnected' event
Connection status check.
Returns: true if connected to debug adapter
User-friendly installation guide for the debugger.
Returns: Multi-line instructions with platform-specific commands
Error message when runtime is not found.
Returns: Helpful error with installation hints
Converts generic errors to language-specific messages.
Parameters: Original error
Returns: User-friendly error message
Checks if a DAP feature is supported.
Parameters: Feature from DebugFeature enum
Returns: true if supported
Requirements for enabling a feature.
Returns: Array of requirements (dependencies, versions, etc.)
Full DAP capabilities declaration.
Returns: Object matching DAP Capabilities specification
Manages debug sessions and coordinates adapters with ProxyManager.
Source: src/session/session-manager.ts (thin facade); actual implementations are in src/session/session-manager-operations.ts, src/session/session-manager-data.ts, and src/session/session-manager-core.ts. Session persistence is in src/session/session-store.ts.
Creates a new debug session.
Parameters:
{
language: DebugLanguage;
name?: string;
executablePath?: string;
}Returns: Session information with unique ID
Starts debugging for a session.
Parameters:
{
sessionId: string;
script: string;
launchConfig?: Partial<LaunchConfig>;
executablePath?: string;
args?: string[];
env?: Record<string, string>;
cwd?: string;
}Returns: Debug result with success status
setBreakpoint(sessionId: string, file: string, line: number, condition?: string): Promise<Breakpoint>
Sets a breakpoint in a file. Internally sends a DAP setBreakpoints request for all breakpoints in the same source file.
Returns: Breakpoint information
Resumes execution from a breakpoint.
Steps over the current line.
Steps into a function call.
Steps out of the current function.
Pauses execution.
Terminates the debug session.
getStackTrace(sessionId: string, threadId?: number, includeInternals?: boolean): Promise<StackFrame[]>
Gets the current call stack. If threadId is omitted, the session's current thread ID is used. If includeInternals is false (default), language-specific internal frames are filtered out via the adapter policy.
Gets variable scopes for a stack frame.
Gets variables in a scope.
evaluateExpression(sessionId: string, expression: string, frameId?: number, context?: string): Promise<EvaluateResult>
Evaluates an expression in the current context. Returns a structured EvaluateResult with result, type, variablesReference, and optional error text.
Note: The context parameter is accepted by the API but the DAP evaluate request is always sent with context: 'variables' internally, regardless of the value passed.
Attaches the debugger to a running process.
Detaches the debugger from an attached process.
Lists all threads in the debug session.
Gets local variables by traversing all stack frames and their scopes, using the language adapter's policy to extract relevant locals. If includeSpecial is false (default), internal/special variables are filtered out.
Retrieves session information.
Lists all active sessions.
Tears down the proxy and removes the session from the store.
Manages debug adapter process lifecycle and DAP communication.
Source: src/proxy/proxy-manager.ts
Creates a new ProxyManager with an adapter (or null for language-agnostic support) and injected dependencies (process launcher, filesystem, logger, optional runtime environment).
Starts the debug adapter process and establishes connection.
Sends a DAP request and waits for response.
Stops the debug adapter process and cleans up.
Returns the currently tracked thread ID.
Returns whether the proxy process is running.
ProxyManager forwards DAP events from the adapter:
- Individually typed and re-emitted:
stopped,continued,terminated,exited,initialized - All other DAP events (including
thread,output,breakpoint,module, etc.) are forwarded as the genericdap-eventevent with(event: string, body: unknown)signature - Plus adapter lifecycle events:
error,exit,dry-run-complete,adapter-configured
Manages available debug adapters.
Source: src/adapters/adapter-registry.ts
Registers a new adapter factory.
Example:
await registry.register('python', new PythonAdapterFactory());Creates an adapter instance (async).
Throws: AdapterNotFoundError if language not supported
Checks if a language has a registered adapter.
Lists all registered languages.
All adapters emit these events:
interface AdapterEvents {
// DAP events
'stopped': (event: DebugProtocol.StoppedEvent) => void;
'continued': (event: DebugProtocol.ContinuedEvent) => void;
'terminated': (event: DebugProtocol.TerminatedEvent) => void;
'exited': (event: DebugProtocol.ExitedEvent) => void;
'thread': (event: DebugProtocol.ThreadEvent) => void;
'output': (event: DebugProtocol.OutputEvent) => void;
'breakpoint': (event: DebugProtocol.BreakpointEvent) => void;
'module': (event: DebugProtocol.ModuleEvent) => void;
// Lifecycle events
'initialized': () => void;
'connected': () => void;
'disconnected': () => void;
'error': (error: AdapterError) => void;
// State events
'stateChanged': (oldState: AdapterState, newState: AdapterState) => void;
}Critical: Understanding event order is crucial! See DAP Sequence Reference
Common sequences:
- Breakpoint hit:
stopped(reason: 'breakpoint') - Continue: Request → (no event if explicit) → Running
- Program end:
exited→terminated - User stop:
terminated(may haveexitedif killed)
enum DebugLanguage {
PYTHON = 'python',
JAVASCRIPT = 'javascript',
RUST = 'rust',
GO = 'go',
JAVA = 'java',
DOTNET = 'dotnet',
MOCK = 'mock',
}
enum AdapterState {
UNINITIALIZED = 'uninitialized',
INITIALIZING = 'initializing',
READY = 'ready',
CONNECTED = 'connected',
DEBUGGING = 'debugging',
DISCONNECTED = 'disconnected',
ERROR = 'error'
}
interface ValidationResult {
valid: boolean;
errors: ValidationError[];
warnings: ValidationWarning[];
}
interface AdapterCommand {
command: string;
args: string[];
env?: Record<string, string>;
}class AdapterError extends Error {
constructor(
message: string,
public code: AdapterErrorCode,
public recoverable: boolean = false
);
}
enum AdapterErrorCode {
// Environment errors
ENVIRONMENT_INVALID = 'ENVIRONMENT_INVALID',
EXECUTABLE_NOT_FOUND = 'EXECUTABLE_NOT_FOUND',
ADAPTER_NOT_INSTALLED = 'ADAPTER_NOT_INSTALLED',
INCOMPATIBLE_VERSION = 'INCOMPATIBLE_VERSION',
// Connection errors
CONNECTION_FAILED = 'CONNECTION_FAILED',
CONNECTION_TIMEOUT = 'CONNECTION_TIMEOUT',
CONNECTION_LOST = 'CONNECTION_LOST',
// Protocol errors
INVALID_RESPONSE = 'INVALID_RESPONSE',
UNSUPPORTED_OPERATION = 'UNSUPPORTED_OPERATION',
// Runtime errors
DEBUGGER_ERROR = 'DEBUGGER_ERROR',
SCRIPT_NOT_FOUND = 'SCRIPT_NOT_FOUND',
PERMISSION_DENIED = 'PERMISSION_DENIED',
// Generic errors
UNKNOWN_ERROR = 'UNKNOWN_ERROR'
}// 1. Create session
const sessionInfo = await sessionManager.createSession({
language: 'python',
name: 'My Debug Session'
});
// 2. Set breakpoints (one call per breakpoint)
await sessionManager.setBreakpoint(sessionInfo.sessionId, 'app.py', 10);
await sessionManager.setBreakpoint(sessionInfo.sessionId, 'app.py', 20);
// 3. Start debugging
await sessionManager.startDebugging({
sessionId: sessionInfo.sessionId,
script: 'app.py',
launchConfig: { stopOnEntry: true }
});
// 4. Listen for events via the ProxyManager for the session
// Note: SessionManager is not an EventEmitter. Subscribe to events through
// the ProxyManager associated with the session, or poll session state.
const session = sessionManager.getSession(sessionInfo.sessionId);
session?.proxyManager?.on('stopped', (threadId, reason) => {
console.log('Paused at:', reason);
});
// 5. Continue execution
await sessionManager.continue(sessionInfo.sessionId);class MyAdapter extends EventEmitter implements IDebugAdapter {
// Implement all required methods
// See MockDebugAdapter for complete example
}
// Register it
const registry = new AdapterRegistry({ enableDynamicLoading: false });
await registry.register('mylang', new MyAdapterFactory());
// Use it
const adapter = await registry.create('mylang', config);- Always handle events - Update adapter state based on DAP events
- Emit events - Notify listeners of state changes
- Provide context in errors - Include helpful messages and recovery hints
- Log important operations - Use the provided logger for debugging
- Test thoroughly - Use mock adapter for integration tests