@debugmcp/mcp-debugger
Version:
Run-time step-through debugging for LLM agents.
679 lines • 37.7 kB
JavaScript
/**
* Debug MCP Server - Main Server Implementation
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
// StdioServerTransport is used in index.ts, not here
import { ListToolsRequestSchema, CallToolRequestSchema, ErrorCode as McpErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js';
import { SessionManager } from './session/session-manager.js';
import { createProductionDependencies } from './container/dependencies.js';
import { SessionLifecycleState } from './session/models.js';
import path from 'path';
/**
* Main Debug MCP Server class
*/
export class DebugMcpServer {
server;
sessionManager;
logger;
constructorOptions;
supportedLanguages = [];
// Get supported languages from adapter registry
getSupportedLanguages() {
const adapterRegistry = this.getAdapterRegistry();
return adapterRegistry.getSupportedLanguages();
}
// Get language metadata for all supported languages
getLanguageMetadata() {
const adapterRegistry = this.getAdapterRegistry();
const languages = adapterRegistry.getSupportedLanguages();
// Map to metadata - in future, this info will come from adapter registry
return languages.map((lang) => {
switch (lang) {
case 'python':
return {
id: 'python',
displayName: 'Python',
version: '1.0.0',
requiresExecutable: true,
defaultExecutable: 'python'
};
case 'mock':
return {
id: 'mock',
displayName: 'Mock',
version: '1.0.0',
requiresExecutable: false
};
default:
return {
id: lang,
displayName: lang.charAt(0).toUpperCase() + lang.slice(1),
version: '1.0.0',
requiresExecutable: true
};
}
});
}
/**
* Validate session exists and is not terminated
*/
validateSession(sessionId) {
const session = this.sessionManager.getSession(sessionId);
if (!session) {
throw new McpError(McpErrorCode.InvalidParams, `Session not found: ${sessionId}`);
}
// Check the new lifecycle state instead of legacy state
if (session.sessionLifecycle === SessionLifecycleState.TERMINATED) {
throw new McpError(McpErrorCode.InvalidRequest, `Session is terminated: ${sessionId}`);
}
}
// Public methods to expose SessionManager functionality for testing/external use
async createDebugSession(params) {
// Validate language support
const adapterRegistry = this.getAdapterRegistry();
if (!adapterRegistry.isLanguageSupported(params.language)) {
const supported = adapterRegistry.getSupportedLanguages();
throw new McpError(McpErrorCode.InvalidParams, `Language '${params.language}' is not supported. Available languages: ${supported.join(', ')}`);
}
const name = params.name || `${params.language}-debug-${Date.now()}`;
try {
const sessionInfo = await this.sessionManager.createSession({
language: params.language,
name: name,
executablePath: params.executablePath // Use executablePath for consistency
});
return sessionInfo;
}
catch (error) {
const errorMessage = error.message || String(error);
this.logger.error('Failed to create debug session', { error: errorMessage, stack: error.stack });
throw new McpError(McpErrorCode.InternalError, `Failed to create debug session: ${errorMessage}`);
}
}
async startDebugging(sessionId, scriptPath, args, dapLaunchArgs, dryRunSpawn) {
this.validateSession(sessionId);
// In container mode, prepend /workspace/ to the path
if (process.env.MCP_CONTAINER === 'true') {
scriptPath = `/workspace/${scriptPath}`;
}
this.logger.info(`[DebugMcpServer.startDebugging] Using scriptPath: ${scriptPath}`);
const result = await this.sessionManager.startDebugging(sessionId, scriptPath, args, dapLaunchArgs, dryRunSpawn);
return result;
}
async closeDebugSession(sessionId) {
return this.sessionManager.closeSession(sessionId);
}
async setBreakpoint(sessionId, file, line, condition) {
this.validateSession(sessionId);
// In container mode, prepend /workspace/ to the path
if (process.env.MCP_CONTAINER === 'true') {
file = `/workspace/${file}`;
}
this.logger.info(`[DebugMcpServer.setBreakpoint] Using file path: ${file}`);
return this.sessionManager.setBreakpoint(sessionId, file, line, condition);
}
async getVariables(sessionId, variablesReference) {
this.validateSession(sessionId);
return this.sessionManager.getVariables(sessionId, variablesReference);
}
async getStackTrace(sessionId) {
this.validateSession(sessionId);
const session = this.sessionManager.getSession(sessionId);
const currentThreadId = session?.proxyManager?.getCurrentThreadId();
if (!session || !session.proxyManager || !currentThreadId) {
throw new McpError(McpErrorCode.InvalidRequest, "Cannot get stack trace: no active proxy, thread, or session not found/paused.");
}
return this.sessionManager.getStackTrace(sessionId, currentThreadId);
}
async getScopes(sessionId, frameId) {
this.validateSession(sessionId);
return this.sessionManager.getScopes(sessionId, frameId);
}
async continueExecution(sessionId) {
this.validateSession(sessionId);
const result = await this.sessionManager.continue(sessionId);
if (!result.success) {
throw new Error(result.error || 'Failed to continue execution');
}
return true;
}
async stepOver(sessionId) {
this.validateSession(sessionId);
const result = await this.sessionManager.stepOver(sessionId);
if (!result.success) {
throw new Error(result.error || 'Failed to step over');
}
return true;
}
async stepInto(sessionId) {
this.validateSession(sessionId);
const result = await this.sessionManager.stepInto(sessionId);
if (!result.success) {
throw new Error(result.error || 'Failed to step into');
}
return true;
}
async stepOut(sessionId) {
this.validateSession(sessionId);
const result = await this.sessionManager.stepOut(sessionId);
if (!result.success) {
throw new Error(result.error || 'Failed to step out');
}
return true;
}
constructor(options = {}) {
this.constructorOptions = options;
const containerConfig = {
logLevel: options.logLevel,
logFile: options.logFile,
sessionLogDirBase: options.logFile ? path.resolve(path.dirname(options.logFile), 'sessions') : undefined
};
const dependencies = createProductionDependencies(containerConfig);
this.logger = dependencies.logger;
this.logger.info('[DebugMcpServer Constructor] Main server logger instance assigned.');
this.server = new Server({ name: 'debug-mcp-server', version: '0.1.0' }, { capabilities: { tools: {} } });
const sessionManagerConfig = {
logDirBase: containerConfig.sessionLogDirBase
};
this.sessionManager = new SessionManager(sessionManagerConfig, dependencies);
this.registerTools();
this.server.onerror = (error) => {
this.logger.error('Server error', { error });
};
}
/**
* Sanitize request data for logging (remove sensitive information)
*/
sanitizeRequest(args) {
const sanitized = { ...args };
// Remove absolute paths from executablePath
if (sanitized.executablePath && typeof sanitized.executablePath === 'string' && path.isAbsolute(sanitized.executablePath)) {
sanitized.executablePath = '<absolute-path>';
}
// Truncate long arrays
if (sanitized.args && Array.isArray(sanitized.args) && sanitized.args.length > 5) {
sanitized.args = [...sanitized.args.slice(0, 5), `... +${sanitized.args.length - 5} more`];
}
return sanitized;
}
/**
* Get session name for logging
*/
getSessionName(sessionId) {
try {
const session = this.sessionManager.getSession(sessionId);
return session?.name || 'Unknown Session';
}
catch {
return 'Unknown Session';
}
}
getPathDescription(parameterName) {
// Hands-off approach: provide simple, generic path guidance
// Let OS/containers/debug adapters handle paths naturally
if (parameterName === 'script') {
return `Path to the script to debug. Use absolute paths or paths relative to your current working directory`;
}
return `Path to the ${parameterName}. Use absolute paths or paths relative to your current working directory`;
}
registerTools() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
this.logger.debug('Handling ListToolsRequest');
// Get supported languages dynamically - deferred until request time
let supportedLanguages;
try {
supportedLanguages = this.getSupportedLanguages();
}
catch (error) {
// Fallback if adapter registry isn't ready
supportedLanguages = ['python', 'mock'];
this.logger.warn('Adapter registry not ready, using default languages', { error });
}
// Generate dynamic descriptions for path parameters
const fileDescription = this.getPathDescription('source file');
const scriptPathDescription = this.getPathDescription('script');
return {
tools: [
{ name: 'create_debug_session', description: 'Create a new debugging session', inputSchema: { type: 'object', properties: { language: { type: 'string', enum: supportedLanguages, description: 'Programming language for debugging' }, name: { type: 'string', description: 'Optional session name' }, executablePath: { type: 'string', description: 'Path to language executable (optional, will auto-detect if not provided)' } }, required: ['language'] } },
{ name: 'list_supported_languages', description: 'List all supported debugging languages with metadata', inputSchema: { type: 'object', properties: {} } },
{ name: 'list_debug_sessions', description: 'List all active debugging sessions', inputSchema: { type: 'object', properties: {} } },
{ name: 'set_breakpoint', description: 'Set a breakpoint. Setting breakpoints on non-executable lines (structural, declarative) may lead to unexpected behavior', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, file: { type: 'string', description: fileDescription }, line: { type: 'number', description: 'Line number where to set breakpoint. Executable statements (assignments, function calls, conditionals, returns) work best. Structural lines (function/class definitions), declarative lines (imports), or non-executable lines (comments, blank lines) may cause unexpected stepping behavior' }, condition: { type: 'string' } }, required: ['sessionId', 'file', 'line'] } },
{ name: 'start_debugging', description: 'Start debugging a script', inputSchema: {
type: 'object',
properties: {
sessionId: { type: 'string' },
scriptPath: { type: 'string', description: scriptPathDescription },
args: { type: 'array', items: { type: 'string' } },
dapLaunchArgs: {
type: 'object',
properties: {
stopOnEntry: { type: 'boolean' },
justMyCode: { type: 'boolean' }
},
additionalProperties: true
},
dryRunSpawn: { type: 'boolean' }
},
required: ['sessionId', 'scriptPath']
}
},
{ name: 'close_debug_session', description: 'Close a debugging session', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } },
{ name: 'step_over', description: 'Step over', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } },
{ name: 'step_into', description: 'Step into', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } },
{ name: 'step_out', description: 'Step out', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } },
{ name: 'continue_execution', description: 'Continue execution', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } },
{ name: 'pause_execution', description: 'Pause execution (Not Implemented)', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } },
{ name: 'get_variables', description: 'Get variables (scope is variablesReference: number)', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, scope: { type: 'number', description: "The variablesReference number from a StackFrame or Variable" } }, required: ['sessionId', 'scope'] } },
{ name: 'get_stack_trace', description: 'Get stack trace', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' } }, required: ['sessionId'] } },
{ name: 'get_scopes', description: 'Get scopes for a stack frame', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, frameId: { type: 'number', description: "The ID of the stack frame from a stackTrace response" } }, required: ['sessionId', 'frameId'] } },
{ name: 'evaluate_expression', description: 'Evaluate expression (Not Implemented)', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, expression: { type: 'string' } }, required: ['sessionId', 'expression'] } },
{ name: 'get_source_context', description: 'Get source context (Not Implemented)', inputSchema: { type: 'object', properties: { sessionId: { type: 'string' }, file: { type: 'string', description: fileDescription }, line: { type: 'number' }, linesContext: { type: 'number' } }, required: ['sessionId', 'file', 'line'] } },
],
};
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const toolName = request.params.name;
const args = request.params.arguments;
// Log tool call with structured logging
this.logger.info('tool:call', {
tool: toolName,
sessionId: args.sessionId,
sessionName: args.sessionId ? this.getSessionName(args.sessionId) : undefined,
request: this.sanitizeRequest(args),
timestamp: Date.now()
});
try {
let result;
switch (toolName) {
case 'create_debug_session': {
const sessionInfo = await this.createDebugSession({
language: (args.language || 'python'),
name: args.name,
executablePath: args.executablePath
});
// Log session creation
this.logger.info('session:created', {
sessionId: sessionInfo.id,
sessionName: sessionInfo.name,
language: sessionInfo.language,
executablePath: args.executablePath,
timestamp: Date.now()
});
result = { content: [{ type: 'text', text: JSON.stringify({ success: true, sessionId: sessionInfo.id, message: `Created ${sessionInfo.language} debug session: ${sessionInfo.name}` }) }] };
break;
}
case 'list_debug_sessions': {
result = await this.handleListDebugSessions();
break;
}
case 'set_breakpoint': {
if (!args.sessionId || !args.file || args.line === undefined) {
throw new McpError(McpErrorCode.InvalidParams, 'Missing required parameters');
}
try {
const breakpoint = await this.setBreakpoint(args.sessionId, args.file, args.line, args.condition);
// Log breakpoint event
this.logger.info('debug:breakpoint', {
event: 'set',
sessionId: args.sessionId,
sessionName: this.getSessionName(args.sessionId),
breakpointId: breakpoint.id,
file: breakpoint.file,
line: breakpoint.line,
verified: breakpoint.verified,
timestamp: Date.now()
});
result = { content: [{ type: 'text', text: JSON.stringify({ success: true, breakpointId: breakpoint.id, file: breakpoint.file, line: breakpoint.line, verified: breakpoint.verified, message: `Breakpoint set at ${breakpoint.file}:${breakpoint.line}` }) }] };
}
catch (error) {
// Handle validation errors specifically
if (error instanceof McpError &&
(error.message.includes('terminated') ||
error.message.includes('closed') ||
error.message.includes('not found'))) {
result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message }) }] };
}
else {
// Re-throw unexpected errors
throw error;
}
}
break;
}
case 'start_debugging': {
if (!args.sessionId || !args.scriptPath) {
throw new McpError(McpErrorCode.InvalidParams, 'Missing required parameters');
}
try {
const debugResult = await this.startDebugging(args.sessionId, args.scriptPath, args.args, args.dapLaunchArgs, args.dryRunSpawn);
const responsePayload = {
success: debugResult.success,
state: debugResult.state,
message: debugResult.error ? debugResult.error : debugResult.data?.message || `Operation status for ${args.scriptPath}`,
};
if (debugResult.data) {
responsePayload.data = debugResult.data;
}
result = { content: [{ type: 'text', text: JSON.stringify(responsePayload) }] };
}
catch (error) {
// Handle validation errors specifically
if (error instanceof McpError &&
(error.message.includes('terminated') ||
error.message.includes('closed') ||
error.message.includes('not found'))) {
result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message, state: 'stopped' }) }] };
}
else {
// Re-throw unexpected errors
throw error;
}
}
break;
}
case 'close_debug_session': {
if (!args.sessionId) {
throw new McpError(McpErrorCode.InvalidParams, 'Missing required sessionId');
}
const sessionName = this.getSessionName(args.sessionId);
const sessionCreatedAt = Date.now(); // In real implementation, would track creation time
const closed = await this.closeDebugSession(args.sessionId);
if (closed) {
// Log session closure
this.logger.info('session:closed', {
sessionId: args.sessionId,
sessionName: sessionName,
duration: Date.now() - sessionCreatedAt,
timestamp: Date.now()
});
}
result = { content: [{ type: 'text', text: JSON.stringify({ success: closed, message: closed ? `Closed debug session: ${args.sessionId}` : `Failed to close debug session: ${args.sessionId}` }) }] };
break;
}
case 'step_over':
case 'step_into':
case 'step_out': {
if (!args.sessionId) {
throw new McpError(McpErrorCode.InvalidParams, 'Missing required sessionId');
}
try {
let stepResult;
if (toolName === 'step_over') {
stepResult = await this.stepOver(args.sessionId);
}
else if (toolName === 'step_into') {
stepResult = await this.stepInto(args.sessionId);
}
else {
stepResult = await this.stepOut(args.sessionId);
}
result = { content: [{ type: 'text', text: JSON.stringify({ success: stepResult, message: stepResult ? `Stepped ${toolName.replace('step_', '')}` : `Failed to ${toolName.replace('_', ' ')}` }) }] };
}
catch (error) {
// Handle validation errors specifically
if (error instanceof McpError &&
(error.message.includes('terminated') ||
error.message.includes('closed') ||
error.message.includes('not found'))) {
result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message }) }] };
}
else if (error instanceof Error) {
// Handle other expected errors (like "Failed to step over")
result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message }) }] };
}
else {
// Re-throw unexpected errors
throw error;
}
}
break;
}
case 'continue_execution': {
if (!args.sessionId) {
throw new McpError(McpErrorCode.InvalidParams, 'Missing required sessionId');
}
try {
const continueResult = await this.continueExecution(args.sessionId);
result = { content: [{ type: 'text', text: JSON.stringify({ success: continueResult, message: continueResult ? 'Continued execution' : 'Failed to continue execution' }) }] };
}
catch (error) {
// Handle validation errors specifically
if (error instanceof McpError &&
(error.message.includes('terminated') ||
error.message.includes('closed') ||
error.message.includes('not found'))) {
result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message }) }] };
}
else if (error instanceof Error) {
// Handle other expected errors
result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message }) }] };
}
else {
// Re-throw unexpected errors
throw error;
}
}
break;
}
case 'pause_execution': {
result = await this.handlePause(args);
break;
}
case 'get_variables': {
if (!args.sessionId || args.scope === undefined) {
throw new McpError(McpErrorCode.InvalidParams, 'Missing required parameters');
}
try {
const variables = await this.getVariables(args.sessionId, args.scope);
// Log variable inspection (truncate large values)
const truncatedVars = variables.map(v => ({
name: v.name,
type: v.type,
value: v.value.length > 200 ? v.value.substring(0, 200) + '... (truncated)' : v.value
}));
this.logger.info('debug:variables', {
sessionId: args.sessionId,
sessionName: this.getSessionName(args.sessionId),
variablesReference: args.scope,
variableCount: variables.length,
variables: truncatedVars.slice(0, 10), // Log first 10 variables
timestamp: Date.now()
});
result = { content: [{ type: 'text', text: JSON.stringify({ success: true, variables, count: variables.length, variablesReference: args.scope }) }] };
}
catch (error) {
// Handle validation errors specifically
if (error instanceof McpError &&
(error.message.includes('terminated') ||
error.message.includes('closed') ||
error.message.includes('not found'))) {
result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message }) }] };
}
else {
// Re-throw unexpected errors
throw error;
}
}
break;
}
case 'get_stack_trace': {
if (!args.sessionId) {
throw new McpError(McpErrorCode.InvalidParams, 'Missing required sessionId');
}
try {
const stackFrames = await this.getStackTrace(args.sessionId);
result = { content: [{ type: 'text', text: JSON.stringify({ success: true, stackFrames, count: stackFrames.length }) }] };
}
catch (error) {
// Handle validation errors specifically
if (error instanceof McpError &&
(error.message.includes('terminated') ||
error.message.includes('closed') ||
error.message.includes('not found') ||
error.message.includes('Cannot get stack trace'))) {
result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message }) }] };
}
else {
// Re-throw unexpected errors
throw error;
}
}
break;
}
case 'get_scopes': {
if (!args.sessionId || args.frameId === undefined) {
throw new McpError(McpErrorCode.InvalidParams, 'Missing required parameters');
}
try {
const scopes = await this.getScopes(args.sessionId, args.frameId);
result = { content: [{ type: 'text', text: JSON.stringify({ success: true, scopes }) }] };
}
catch (error) {
// Handle validation errors specifically
if (error instanceof McpError &&
(error.message.includes('terminated') ||
error.message.includes('closed') ||
error.message.includes('not found'))) {
result = { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error.message }) }] };
}
else {
// Re-throw unexpected errors
throw error;
}
}
break;
}
case 'evaluate_expression': {
result = await this.handleEvaluateExpression(args);
break;
}
case 'get_source_context': {
result = await this.handleGetSourceContext(args);
break;
}
case 'list_supported_languages': {
result = await this.handleListSupportedLanguages();
break;
}
default:
throw new McpError(McpErrorCode.MethodNotFound, `Unknown tool: ${toolName}`);
}
// Log successful tool response
this.logger.info('tool:response', {
tool: toolName,
sessionId: args.sessionId,
sessionName: args.sessionId ? this.getSessionName(args.sessionId) : undefined,
success: true,
timestamp: Date.now()
});
return result;
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
// Log tool error
this.logger.error('tool:error', {
tool: toolName,
sessionId: args.sessionId,
sessionName: args.sessionId ? this.getSessionName(args.sessionId) : undefined,
error: errorMessage,
timestamp: Date.now()
});
if (error instanceof McpError)
throw error;
throw new McpError(McpErrorCode.InternalError, `Failed to execute tool ${toolName}: ${errorMessage}`);
}
});
}
async handleListDebugSessions() {
try {
const sessionsInfo = this.sessionManager.getAllSessions();
const sessionData = sessionsInfo.map((session) => {
const mappedSession = {
id: session.id,
name: session.name,
language: session.language,
state: session.state,
createdAt: session.createdAt.toISOString(),
};
if (session.updatedAt) {
mappedSession.updatedAt = session.updatedAt.toISOString();
}
return mappedSession;
});
return { content: [{ type: 'text', text: JSON.stringify({ success: true, sessions: sessionData, count: sessionData.length }) }] };
}
catch (error) {
this.logger.error('Failed to list debug sessions', { error });
throw new McpError(McpErrorCode.InternalError, `Failed to list debug sessions: ${error.message}`);
}
}
async handlePause(args) {
try {
this.logger.info(`Pause requested for session: ${args.sessionId}`);
throw new McpError(McpErrorCode.InternalError, "Pause execution not yet implemented with proxy.");
}
catch (error) {
this.logger.error('Failed to pause execution', { error });
if (error instanceof McpError)
throw error;
throw new McpError(McpErrorCode.InternalError, `Failed to pause execution: ${error.message}`);
}
}
async handleEvaluateExpression(args) {
try {
this.logger.info(`Evaluate requested for session: ${args.sessionId}, expression: ${args.expression}`);
throw new McpError(McpErrorCode.InternalError, "Evaluate expression not yet implemented with proxy.");
}
catch (error) {
this.logger.error('Failed to evaluate expression', { error });
if (error instanceof McpError)
throw error;
throw new McpError(McpErrorCode.InternalError, `Failed to evaluate expression: ${error.message}`);
}
}
async handleGetSourceContext(args) {
try {
// In container mode, prepend /workspace/ to the path
let file = args.file;
if (process.env.MCP_CONTAINER === 'true') {
file = `/workspace/${file}`;
}
this.logger.info(`Source context requested for session: ${args.sessionId}, file: ${file}, line: ${args.line}`);
throw new McpError(McpErrorCode.InternalError, "Get source context not yet implemented with proxy.");
}
catch (error) {
this.logger.error('Failed to get source context', { error });
if (error instanceof McpError)
throw error;
throw new McpError(McpErrorCode.InternalError, `Failed to get source context: ${error.message}`);
}
}
async handleListSupportedLanguages() {
try {
const languages = this.getLanguageMetadata();
return { content: [{ type: 'text', text: JSON.stringify({ success: true, languages, count: languages.length }) }] };
}
catch (error) {
this.logger.error('Failed to list supported languages', { error });
throw new McpError(McpErrorCode.InternalError, `Failed to list supported languages: ${error.message}`);
}
}
/**
* Public methods for server lifecycle management
*/
async start() {
// For MCP servers, start is handled by transport
this.logger.info('Debug MCP Server started');
}
async stop() {
await this.sessionManager.closeAllSessions();
this.logger.info('Debug MCP Server stopped');
}
/**
* Get adapter registry from session manager
*/
getAdapterRegistry() {
return this.sessionManager.adapterRegistry;
}
}
//# sourceMappingURL=server.js.map