@bloopai/debugger-mcp
Version:
An MCP server that provides interactive debugging capabilities to AI coding agents
236 lines (215 loc) • 5.24 kB
text/typescript
/**
* Represents the state of a debug session
*/
export enum SessionState {
INITIALIZING = 'initializing',
CONFIGURED = 'configured',
RUNNING = 'running',
STOPPED = 'stopped',
TERMINATED = 'terminated',
}
/**
* Information about a debug session
*/
export interface SessionInfo {
id: string;
targetType: string;
targetPath: string;
state: SessionState;
startTime: Date;
}
/**
* Result of setting a breakpoint
*/
export interface BreakpointResult {
breakpointId: string;
verified: boolean;
line: number;
message?: string;
}
/**
* Represents a breakpoint in a debug session
*/
export interface Breakpoint {
id: string;
filePath: string;
line: number;
verified: boolean;
condition?: string;
message?: string;
}
/**
* Result of evaluating an expression
*/
export interface EvaluationResult {
result: string;
type?: string;
variablesReference?: number;
namedVariables?: number;
indexedVariables?: number;
}
/**
* Represents a source file in a debug session (sanitized model)
*/
export interface ModelSource {
name?: string;
path?: string;
sourceReference?: number;
adapterData?: unknown;
// Potentially add other serializable properties from DebugProtocol.Source. e.g., presentationHint, origin
}
/**
* Represents a stack frame in a call stack (sanitized model)
*/
export interface ModelStackFrame {
id: number;
name: string;
source?: ModelSource;
line: number;
column: number;
instructionPointerReference?: string;
threadId?: number;
// Note: To prevent circular dependencies in JSON serialization, we omit direct references to a the parent Thread object.
}
/**
* Represents a thread in a debug session (sanitized model)
*/
export interface ModelThread {
id: number;
name: string;
}
/**
* Represents a variable in the debug session
*/
export interface Variable {
name: string;
value: string;
type?: string;
variablesReference: number;
namedVariables?: number;
indexedVariables?: number;
}
/**
* Listener for session state changes
*/
export type StateChangeListener = (
sessionId: string,
newState: SessionState,
oldState: SessionState,
) => void;
/**
* Error codes specific to the debugger
*/
export enum DebuggerErrorCode {
SESSION_NOT_FOUND = 'SESSION_NOT_FOUND',
INVALID_STATE = 'INVALID_STATE',
BREAKPOINT_ERROR = 'BREAKPOINT_ERROR',
EVALUATION_ERROR = 'EVALUATION_ERROR',
ADAPTER_ERROR = 'ADAPTER_ERROR',
TIMEOUT = 'TIMEOUT',
}
/**
* Base class for debugger errors
*/
export class DebuggerError extends Error {
constructor(
message: string,
public code: DebuggerErrorCode,
) {
super(message);
this.name = 'DebuggerError';
}
}
/**
* Error thrown when a session is not found
*/
export class SessionNotFoundError extends DebuggerError {
constructor(sessionId: string) {
super(
`Debug session with ID ${sessionId} not found`,
DebuggerErrorCode.SESSION_NOT_FOUND,
);
this.name = 'SessionNotFoundError';
}
}
/**
* Error thrown when a session is in an invalid state for an operation
*/
export class InvalidStateError extends DebuggerError {
constructor(
sessionId: string,
currentState: SessionState,
expectedStates: SessionState[],
) {
super(
`Session ${sessionId} is in state ${currentState}, expected one of: ${expectedStates.join(', ')}`,
DebuggerErrorCode.INVALID_STATE,
);
this.name = 'InvalidStateError';
}
}
/**
* Error thrown when a breakpoint operation fails
*/
export class BreakpointError extends DebuggerError {
constructor(
message: string,
public filePath: string,
public line: number,
) {
super(message, DebuggerErrorCode.BREAKPOINT_ERROR);
this.name = 'BreakpointError';
}
}
/**
* Error thrown when an expression evaluation fails
*/
export class EvaluationError extends DebuggerError {
constructor(
message: string,
public expression: string,
) {
super(message, DebuggerErrorCode.EVALUATION_ERROR);
this.name = 'EvaluationError';
}
}
/**
* Wrapper class for DebugSession from ergonomic-debugger-client
* to hold additional metadata like targetType, targetPath, and startTime.
*/
import {
DebugSession,
DAPSessionHandler,
LoggerInterface,
SessionStatus,
} from '@bloopai/ergonomic-debugger-client';
export class WrappedDebugSession {
public readonly originalSession: DebugSession;
public readonly id: string;
public readonly targetType: string;
public readonly targetPath: string;
public readonly startTime: Date;
private readonly logger: LoggerInterface;
constructor(
mcpSessionId: string,
originalSession: DebugSession,
targetType: string,
targetPath: string,
startTime: Date,
logger: LoggerInterface,
) {
this.id = mcpSessionId;
this.originalSession = originalSession;
this.targetType = targetType;
this.targetPath = targetPath;
this.startTime = startTime;
this.logger = logger;
}
public get dapSessionHandler(): DAPSessionHandler {
return this.originalSession.sessionHandler;
}
public get status(): SessionStatus {
const handler = this.dapSessionHandler;
return handler ? handler.status : ('terminated' as SessionStatus);
}
}