Skip to content

Latest commit

 

History

History
562 lines (401 loc) · 14.6 KB

File metadata and controls

562 lines (401 loc) · 14.6 KB

mcp-debugger API Reference

⚠️ DRAFT DOCUMENTATION
This API reference is based on mcp-debugger v0.10.0 and will be updated as the architecture evolves.

Table of Contents

  1. IDebugAdapter Interface
  2. SessionManager API
  3. ProxyManager API
  4. AdapterRegistry API
  5. Event System
  6. Type Definitions

IDebugAdapter Interface

The core interface that all language adapters must implement.

Source: src/adapters/debug-adapter-interface.ts

Properties

readonly language: DebugLanguage;  // Language identifier
readonly name: string;             // Human-readable adapter name

Lifecycle Methods

initialize(): Promise<void>

Initializes 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

dispose(): Promise<void>

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

State Management Methods

getState(): AdapterState

Returns the current adapter state.

Returns: One of: UNINITIALIZED, INITIALIZING, READY, CONNECTED, DEBUGGING, DISCONNECTED, ERROR

isReady(): boolean

Quick check if adapter is ready for debugging.

Returns: true if adapter can accept debug operations

getCurrentThreadId(): number | null

Gets the currently active thread ID during debugging.

Returns: Thread ID or null if not debugging

Environment Validation Methods

validateEnvironment(): Promise<ValidationResult>

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);
}

getRequiredDependencies(): DependencyInfo[]

Lists all dependencies needed for debugging.

Returns: Array of dependency information with install commands

Executable Management Methods

resolveExecutablePath(preferredPath?: string): Promise<string>

Finds or validates the language runtime executable.

Parameters:

  • preferredPath - User-specified path (optional)

Returns: Resolved executable path
Throws: AdapterError if executable not found

getDefaultExecutableName(): string

Platform-aware default executable name.

Returns: e.g., 'python', 'node', 'go'

getExecutableSearchPaths(): string[]

Paths to search for the executable.

Returns: Array of paths (usually from PATH environment variable)

Adapter Configuration Methods

buildAdapterCommand(config: AdapterConfig): AdapterCommand

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
}

getAdapterModuleName(): string

Debug adapter module identifier.

Returns: e.g., 'debugpy.adapter', 'js-debug'

getAdapterInstallCommand(): string

Command to install the debug adapter.

Returns: e.g., 'pip install debugpy', 'bundled with @debugmcp/adapter-javascript'

Debug Configuration Methods

transformLaunchConfig(config: GenericLaunchConfig): Promise<LanguageSpecificLaunchConfig>

Converts generic config to language-specific format (async since v2.1.0).

Parameters: Generic launch configuration Returns: Promise resolving to language-specific configuration with additional fields

getDefaultLaunchConfig(): Partial<GenericLaunchConfig>

Default configuration values for the language.

Returns: Common default settings

Path Translation Methods

translateScriptPath(scriptPath: string, context: PathContext): string

Handles language-specific path requirements.

Parameters:

{
  isContainer: boolean;
  workspaceRoot: string;
  platform: NodeJS.Platform;
}

Returns: Translated path suitable for the debug adapter

translateBreakpointPath(filePath: string, context: PathContext): string

Translates paths for breakpoint locations.

Parameters: Same as translateScriptPath
Returns: Translated breakpoint file path

DAP Protocol Methods

sendDapRequest<T>(command: string, args?: unknown): Promise<T>

Sends a DAP request (usually delegated to ProxyManager).

Parameters:

  • command - DAP command name
  • args - Command arguments

Returns: DAP response

handleDapEvent(event: DebugProtocol.Event): void

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);
}

handleDapResponse(response: DebugProtocol.Response): void

Processes DAP responses if special handling needed.

Connection Management Methods

connect(host: string, port: number): Promise<void>

Establishes connection to debug adapter.

Parameters: Host and port for connection
Emits: 'connected' event on success

disconnect(): Promise<void>

Closes debug adapter connection.

Emits: 'disconnected' event

isConnected(): boolean

Connection status check.

Returns: true if connected to debug adapter

Error Handling Methods

getInstallationInstructions(): string

User-friendly installation guide for the debugger.

Returns: Multi-line instructions with platform-specific commands

getMissingExecutableError(): string

Error message when runtime is not found.

Returns: Helpful error with installation hints

translateErrorMessage(error: Error): string

Converts generic errors to language-specific messages.

Parameters: Original error
Returns: User-friendly error message

Feature Support Methods

supportsFeature(feature: DebugFeature): boolean

Checks if a DAP feature is supported.

Parameters: Feature from DebugFeature enum
Returns: true if supported

getFeatureRequirements(feature: DebugFeature): FeatureRequirement[]

Requirements for enabling a feature.

Returns: Array of requirements (dependencies, versions, etc.)

getCapabilities(): AdapterCapabilities

Full DAP capabilities declaration.

Returns: Object matching DAP Capabilities specification

SessionManager API

Manages debug sessions and coordinates adapters with ProxyManager.

Source: src/session/session-manager.ts

Core Methods

createSession(params: CreateSessionParams): Promise<SessionInfo>

Creates a new debug session.

Parameters:

{
  language: DebugLanguage;
  name?: string;
  config?: Partial<LaunchConfig>;
}

Returns: Session information with unique ID

startDebugging(params: StartDebuggingParams): Promise<DebugResult>

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

setBreakpoints(sessionId: string, file: string, breakpoints: SourceBreakpoint[]): Promise<Breakpoint[]>

Sets breakpoints in a file.

Returns: Array of verified breakpoints with actual locations

continue(sessionId: string, threadId?: number): Promise<void>

Resumes execution from a breakpoint.

stepOver(sessionId: string, threadId?: number): Promise<void>

Steps over the current line.

stepInto(sessionId: string, threadId?: number): Promise<void>

Steps into a function call.

stepOut(sessionId: string, threadId?: number): Promise<void>

Steps out of the current function.

pause(sessionId: string): Promise<void>

Pauses execution.

terminate(sessionId: string): Promise<void>

Terminates the debug session.

getStackTrace(sessionId: string, threadId: number): Promise<StackFrame[]>

Gets the current call stack.

getScopes(sessionId: string, frameId: number): Promise<Scope[]>

Gets variable scopes for a stack frame.

getVariables(sessionId: string, variablesReference: number): Promise<Variable[]>

Gets variables in a scope.

evaluateExpression(sessionId: string, expression: string, frameId?: number): Promise<string>

Evaluates an expression in the current context.

Session Management

getSession(sessionId: string): SessionInfo | null

Retrieves session information.

listSessions(): SessionInfo[]

Lists all active sessions.

deleteSession(sessionId: string): Promise<void>

Removes a session and cleans up resources.

ProxyManager API

Manages debug adapter process lifecycle and DAP communication.

Source: src/proxy/proxy-manager.ts

Key Methods

constructor(adapter: IDebugAdapter, config: ProxyConfig)

Creates a new ProxyManager with an adapter.

start(config: StartConfig): Promise<void>

Starts the debug adapter process and establishes connection.

sendDapRequest(command: string, args?: any): Promise<any>

Sends a DAP request and waits for response.

stop(): Promise<void>

Stops the debug adapter process and cleans up.

Events

ProxyManager forwards all DAP events from the adapter:

  • stopped, continued, terminated, exited
  • thread, output, breakpoint, module
  • Plus adapter lifecycle events

AdapterRegistry API

Manages available debug adapters.

Source: src/adapters/adapter-registry.ts

Methods

register(language: string, factory: IAdapterFactory): void

Registers a new adapter factory.

Example:

registry.register('python', new PythonAdapterFactory());

create(language: string, config: AdapterConfig): IDebugAdapter

Creates an adapter instance.

Throws: AdapterNotFoundError if language not supported

isLanguageSupported(language: string): boolean

Checks if a language has a registered adapter.

getSupportedLanguages(): string[]

Lists all registered languages.

Event System

Adapter Events

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;
}

DAP Event Sequences

Critical: Understanding event order is crucial! See DAP Sequence Reference

Common sequences:

  1. Breakpoint hit: stopped (reason: 'breakpoint')
  2. Continue: Request → (no event if explicit) → Running
  3. Program end: exited → terminated
  4. User stop: terminated (may have exited if killed)

Type Definitions

Core Types

enum DebugLanguage {
  PYTHON = 'python',
  MOCK = 'mock',
  // Future: NODE = 'node', GO = 'go', etc.
}

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>;
}

Error Types

class AdapterError extends Error {
  constructor(
    message: string,
    public code: AdapterErrorCode,
    public recoverable: boolean = false
  );
}

enum AdapterErrorCode {
  ENVIRONMENT_INVALID = 'ENVIRONMENT_INVALID',
  EXECUTABLE_NOT_FOUND = 'EXECUTABLE_NOT_FOUND',
  ADAPTER_NOT_INSTALLED = 'ADAPTER_NOT_INSTALLED',
  CONNECTION_FAILED = 'CONNECTION_FAILED',
  // ... more codes
}

Usage Examples

Creating and Starting a Debug Session

// 1. Create session
const sessionInfo = await sessionManager.createSession({
  language: 'python',
  name: 'My Debug Session'
});

// 2. Set breakpoints
await sessionManager.setBreakpoints(
  sessionInfo.sessionId,
  'app.py',
  [{ line: 10 }, { line: 20 }]
);

// 3. Start debugging
await sessionManager.startDebugging({
  sessionId: sessionInfo.sessionId,
  script: 'app.py',
  launchConfig: { stopOnEntry: true }
});

// 4. Listen for events
sessionManager.on('stopped', (event) => {
  console.log('Paused at:', event.body.reason);
});

// 5. Continue execution
await sessionManager.continue(sessionInfo.sessionId);

Creating a Custom Adapter

class MyAdapter extends EventEmitter implements IDebugAdapter {
  // Implement all required methods
  // See MockDebugAdapter for complete example
}

// Register it
const registry = new AdapterRegistry(dependencies);
registry.register('mylang', new MyAdapterFactory());

// Use it
const adapter = registry.create('mylang', config);

Best Practices

  1. Always handle events - Update adapter state based on DAP events
  2. Emit events - Notify listeners of state changes
  3. Provide context in errors - Include helpful messages and recovery hints
  4. Log important operations - Use the provided logger for debugging
  5. Test thoroughly - Use mock adapter for integration tests

See Also