@prmichaelsen/acp-mcp 0.7.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/server-factory.ts", "../src/tools/acp-remote-list-files.ts", "../src/utils/logger.ts", "../src/tools/acp-remote-execute-command.ts", "../src/tools/acp-remote-read-file.ts", "../src/tools/acp-remote-write-file.ts", "../src/utils/ssh-connection.ts", "../src/types/file-entry.ts"],
4
- "sourcesContent": ["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { config } from './config.js';\nimport { acpRemoteListFilesTool, handleAcpRemoteListFiles } from './tools/acp-remote-list-files.js';\nimport { acpRemoteExecuteCommandTool, handleAcpRemoteExecuteCommand } from './tools/acp-remote-execute-command.js';\nimport { acpRemoteReadFileTool, handleAcpRemoteReadFile } from './tools/acp-remote-read-file.js';\nimport { acpRemoteWriteFileTool, handleAcpRemoteWriteFile } from './tools/acp-remote-write-file.js';\nimport { ServerConfig } from './types/ssh-config.js';\nimport { SSHConnectionManager } from './utils/ssh-connection.js';\nimport { logger } from './utils/logger.js';\n\n/**\n * Create an MCP server instance for a specific user with SSH configuration\n * This factory function is used by mcp-auth for multi-tenant support\n * \n * @param serverConfig - Configuration including userId and SSH credentials\n * @returns Configured MCP Server instance\n */\nexport async function createServer(serverConfig: ServerConfig): Promise<Server> {\n logger.info('Creating server instance', { userId: serverConfig.userId });\n logger.debug('SSH configuration', {\n host: serverConfig.ssh.host,\n port: serverConfig.ssh.port,\n username: serverConfig.ssh.username,\n });\n \n // Create SSH connection manager\n const sshConnection = new SSHConnectionManager(serverConfig.ssh);\n \n // Connect to remote server\n await sshConnection.connect();\n \n logger.info('Server created successfully', { userId: serverConfig.userId });\n\n const server = new Server(\n {\n name: 'acp-mcp',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // Register tools with SSH connection context\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n logger.debug('Tool discovery requested', { userId: serverConfig.userId });\n const tools = [acpRemoteListFilesTool, acpRemoteExecuteCommandTool, acpRemoteReadFileTool, acpRemoteWriteFileTool];\n logger.debug(`Returning ${tools.length} tools`, { tools: tools.map(t => t.name), userId: serverConfig.userId });\n return { tools };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {\n const startTime = Date.now();\n logger.toolInvoked(request.params.name, request.params.arguments, serverConfig.userId);\n \n try {\n let result;\n \n if (request.params.name === 'acp_remote_list_files') {\n // Pass SSH connection to handler for remote operations\n result = await handleAcpRemoteListFiles(request.params.arguments, sshConnection);\n } else if (request.params.name === 'acp_remote_execute_command') {\n // Pass extra and server for progress streaming support\n result = await handleAcpRemoteExecuteCommand(request.params.arguments, sshConnection, extra, server);\n } else if (request.params.name === 'acp_remote_read_file') {\n result = await handleAcpRemoteReadFile(request.params.arguments, sshConnection);\n } else if (request.params.name === 'acp_remote_write_file') {\n result = await handleAcpRemoteWriteFile(request.params.arguments, sshConnection);\n } else {\n throw new Error(`Unknown tool: ${request.params.name}`);\n }\n \n const duration = Date.now() - startTime;\n const resultSize = JSON.stringify(result).length;\n logger.toolCompleted(request.params.name, duration, resultSize);\n \n return result;\n } catch (error) {\n logger.toolFailed(request.params.name, error as Error, request.params.arguments);\n throw error;\n }\n });\n\n // Handle server shutdown to cleanup SSH connection\n process.on('SIGINT', () => {\n logger.info('Received SIGINT, shutting down', { userId: serverConfig.userId });\n sshConnection.disconnect();\n process.exit(0);\n });\n\n process.on('SIGTERM', () => {\n logger.info('Received SIGTERM, shutting down', { userId: serverConfig.userId });\n sshConnection.disconnect();\n process.exit(0);\n });\n\n return server;\n}\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\nimport { FileEntry } from '../types/file-entry.js';\n\nexport const acpRemoteListFilesTool: Tool = {\n name: 'acp_remote_list_files',\n description: 'List files and directories in a specified path on the remote machine via SSH. Returns comprehensive metadata including permissions, timestamps, size, and ownership. Includes hidden files by default.',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'The directory path to list files from',\n },\n recursive: {\n type: 'boolean',\n description: 'Whether to list files recursively',\n default: false,\n },\n includeHidden: {\n type: 'boolean',\n description: 'Whether to include hidden files (starting with .)',\n default: true,\n },\n },\n required: ['path'],\n },\n};\n\ninterface ListFilesArgs {\n path: string;\n recursive?: boolean;\n includeHidden?: boolean;\n}\n\n/**\n * Handle the acp_remote_list_files tool invocation\n * Lists files and directories at the specified path on the remote machine via SSH\n * \n * @param args - Tool arguments containing path and recursive flag\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteListFiles(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { path, recursive = false, includeHidden = true } = args as ListFilesArgs;\n\n try {\n const entries = await listRemoteFiles(sshConnection, path, recursive, includeHidden);\n \n // Format as JSON for structured output\n const output = JSON.stringify(entries, null, 2);\n \n return {\n content: [\n {\n type: 'text',\n text: output,\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return {\n content: [\n {\n type: 'text',\n text: `Error listing remote files: ${errorMessage}`,\n },\n ],\n };\n }\n}\n\n/**\n * Recursively list files in a remote directory via SSH\n * Returns FileEntry objects with comprehensive metadata\n */\nasync function listRemoteFiles(\n ssh: SSHConnectionManager,\n dirPath: string,\n recursive: boolean,\n includeHidden: boolean\n): Promise<FileEntry[]> {\n const entries = await ssh.listFiles(dirPath, includeHidden);\n const allEntries: FileEntry[] = [...entries];\n\n // Recursively list subdirectories if requested\n if (recursive) {\n for (const entry of entries) {\n if (entry.type === 'directory') {\n const subEntries = await listRemoteFiles(ssh, entry.path, recursive, includeHidden);\n allEntries.push(...subEntries);\n }\n }\n }\n\n return allEntries;\n}\n", "/**\n * Logger utility for ACP MCP Server\n * Provides structured logging with configurable log levels\n */\n\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n};\n\nclass Logger {\n private level: LogLevel;\n private enabled: boolean;\n\n constructor() {\n // Read configuration from environment variables\n this.level = (process.env.ACP_MCP_LOG_LEVEL as LogLevel) || 'info';\n this.enabled = process.env.ACP_MCP_DEBUG === 'true' || process.env.NODE_ENV === 'development';\n }\n\n private shouldLog(level: LogLevel): boolean {\n if (!this.enabled && level !== 'error' && level !== 'warn') {\n return false;\n }\n return LOG_LEVELS[level] <= LOG_LEVELS[this.level];\n }\n\n private formatMessage(level: LogLevel, message: string, data?: any): string {\n const timestamp = new Date().toISOString();\n const prefix = `[${timestamp}] [${level.toUpperCase()}]`;\n \n if (data !== undefined) {\n const dataStr = typeof data === 'object' ? JSON.stringify(data, null, 2) : String(data);\n return `${prefix} ${message}\\n${dataStr}`;\n }\n \n return `${prefix} ${message}`;\n }\n\n error(message: string, data?: any): void {\n if (this.shouldLog('error')) {\n console.error(this.formatMessage('error', message, data));\n }\n }\n\n warn(message: string, data?: any): void {\n if (this.shouldLog('warn')) {\n console.error(this.formatMessage('warn', message, data));\n }\n }\n\n info(message: string, data?: any): void {\n if (this.shouldLog('info')) {\n console.error(this.formatMessage('info', message, data));\n }\n }\n\n debug(message: string, data?: any): void {\n if (this.shouldLog('debug')) {\n console.error(this.formatMessage('debug', message, data));\n }\n }\n\n trace(message: string, data?: any): void {\n if (this.shouldLog('trace')) {\n console.error(this.formatMessage('trace', message, data));\n }\n }\n\n /**\n * Log tool invocation with parameters\n */\n toolInvoked(toolName: string, params: any, userId?: string): void {\n this.info(`Tool invoked: ${toolName}`);\n this.debug('Tool parameters', { tool: toolName, params, userId });\n }\n\n /**\n * Log tool completion with result summary\n */\n toolCompleted(toolName: string, duration: number, resultSize?: number): void {\n this.info(`Tool completed: ${toolName}`);\n this.debug('Tool performance', { tool: toolName, duration: `${duration}ms`, resultSize });\n }\n\n /**\n * Log tool failure with error details\n */\n toolFailed(toolName: string, error: Error, params?: any): void {\n this.error(`Tool execution failed: ${toolName}`, {\n tool: toolName,\n error: error.message,\n stack: error.stack,\n params,\n });\n }\n\n /**\n * Log SSH command execution\n */\n sshCommand(command: string, cwd?: string, timeout?: number): void {\n this.debug('Executing SSH command', { command, cwd, timeout });\n }\n\n /**\n * Log SSH command result\n */\n sshCommandResult(exitCode: number, duration: number, stdoutSize: number, stderrSize: number): void {\n this.debug('SSH command completed', {\n exitCode,\n duration: `${duration}ms`,\n stdout: `${stdoutSize} bytes`,\n stderr: `${stderrSize} bytes`,\n });\n }\n\n /**\n * Log file operation\n */\n fileOperation(operation: string, path: string, details?: any): void {\n this.info(`File operation: ${operation}`, { path, ...details });\n }\n}\n\n// Export singleton instance\nexport const logger = new Logger();\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\nimport { logger } from '../utils/logger.js';\n\nexport const acpRemoteExecuteCommandTool: Tool = {\n name: 'acp_remote_execute_command',\n description: 'Execute a shell command on the remote machine via SSH. Supports real-time progress streaming if client provides progressToken.',\n inputSchema: {\n type: 'object',\n properties: {\n command: {\n type: 'string',\n description: 'Shell command to execute',\n },\n cwd: {\n type: 'string',\n description: 'Working directory for command execution (optional)',\n },\n timeout: {\n type: 'number',\n description: 'Timeout in seconds (default: 30). Ignored if progress streaming is used.',\n default: 30,\n },\n },\n required: ['command'],\n },\n};\n\ninterface ExecuteCommandArgs {\n command: string;\n cwd?: string;\n timeout?: number;\n}\n\ninterface ExecuteCommandResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n timedOut: boolean;\n streamed?: boolean;\n}\n\n/**\n * Handle the acp_remote_execute_command tool invocation\n * Executes a shell command on the remote machine via SSH\n * Supports progress streaming when progressToken is provided\n * \n * @param args - Tool arguments containing command, cwd, and timeout\n * @param sshConnection - SSH connection manager for remote operations\n * @param extra - Optional extra parameters including progressToken\n * @param server - Server instance for sending progress notifications (optional)\n */\nexport async function handleAcpRemoteExecuteCommand(\n args: any,\n sshConnection: SSHConnectionManager,\n extra?: any,\n server?: any\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { command, cwd, timeout = 30 } = args as ExecuteCommandArgs;\n const progressToken = extra?._meta?.progressToken;\n\n logger.debug('Executing remote command', { command, cwd, timeout, hasProgressToken: !!progressToken });\n\n try {\n // If progress token provided and server available, use streaming\n if (progressToken && server) {\n return await executeWithProgress(command, cwd, sshConnection, progressToken, server);\n }\n \n // Otherwise, use existing timeout-based execution (fallback)\n const fullCommand = cwd ? `cd ${cwd} && ${command}` : command;\n const result = await sshConnection.execWithTimeout(fullCommand, timeout);\n \n logger.debug('Command execution result', {\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n stdoutLength: result.stdout.length,\n stderrLength: result.stderr.length,\n });\n \n const output: ExecuteCommandResult = {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n };\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(output, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error('Command execution error', { command, error: errorMessage });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n stdout: '',\n stderr: errorMessage,\n exitCode: 1,\n timedOut: false,\n }, null, 2),\n },\n ],\n };\n }\n}\n\n/**\n * Execute command with progress streaming\n * Sends real-time progress notifications as output is received\n * \n * @param command - Command to execute\n * @param cwd - Working directory\n * @param sshConnection - SSH connection\n * @param progressToken - Token for progress notifications\n * @param server - Server instance for sending notifications\n */\nasync function executeWithProgress(\n command: string,\n cwd: string | undefined,\n sshConnection: SSHConnectionManager,\n progressToken: string | number,\n server: any\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n logger.debug('Starting streaming execution', { command, cwd, progressToken });\n \n const { stream, stderr: stderrStream, exitCode } = await sshConnection.execStream(command, cwd);\n \n let stdout = '';\n let stderr = '';\n let bytesReceived = 0;\n let lastProgressTime = 0;\n const MIN_PROGRESS_INTERVAL = 100; // 100ms rate limiting\n\n // Stream stdout with progress notifications\n stream.on('data', (chunk: Buffer) => {\n const text = chunk.toString();\n stdout += text;\n bytesReceived += chunk.length;\n \n // Rate limiting: only send progress if enough time elapsed\n const now = Date.now();\n if (now - lastProgressTime >= MIN_PROGRESS_INTERVAL) {\n try {\n server.notification({\n method: 'notifications/progress',\n params: {\n progressToken,\n progress: bytesReceived,\n total: undefined, // Unknown total for streaming\n message: text,\n },\n });\n lastProgressTime = now;\n logger.debug('Progress notification sent', { \n progressToken, \n bytes: bytesReceived,\n chunkSize: chunk.length \n });\n } catch (error) {\n logger.warn('Failed to send progress notification', {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n }\n });\n\n // Collect stderr (no progress for errors)\n stderrStream.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n\n // Handle stream errors\n stream.on('error', (error: Error) => {\n logger.error('Stream error during execution', {\n command,\n error: error.message\n });\n });\n\n // Wait for completion\n const finalExitCode = await exitCode;\n \n logger.debug('Streaming execution completed', { \n command, \n exitCode: finalExitCode,\n stdoutBytes: stdout.length,\n stderrBytes: stderr.length,\n });\n\n const output: ExecuteCommandResult = {\n stdout,\n stderr,\n exitCode: finalExitCode,\n timedOut: false,\n streamed: true, // Indicate this was streamed\n };\n\n return {\n content: [{\n type: 'text',\n text: JSON.stringify(output, null, 2),\n }],\n };\n}\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\nimport { logger } from '../utils/logger.js';\n\nexport const acpRemoteReadFileTool: Tool = {\n name: 'acp_remote_read_file',\n description: 'Read file contents from the remote machine via SSH',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Absolute path to file',\n },\n encoding: {\n type: 'string',\n description: 'File encoding (default: utf-8)',\n default: 'utf-8',\n enum: ['utf-8', 'ascii', 'base64'],\n },\n maxSize: {\n type: 'number',\n description: 'Max file size in bytes (default: 1MB)',\n default: 1048576,\n },\n },\n required: ['path'],\n },\n};\n\ninterface ReadFileArgs {\n path: string;\n encoding?: string;\n maxSize?: number;\n}\n\ninterface ReadFileResult {\n content: string;\n size: number;\n encoding: string;\n}\n\n/**\n * Handle the acp_remote_read_file tool invocation\n * Reads file contents from the remote machine via SSH\n * \n * @param args - Tool arguments containing path, encoding, and maxSize\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteReadFile(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { path, encoding = 'utf-8', maxSize = 1048576 } = args as ReadFileArgs;\n\n logger.debug('Reading remote file', { path, encoding, maxSize });\n\n try {\n const result = await sshConnection.readFile(path, encoding, maxSize);\n \n logger.debug('File read successful', { path, size: result.size });\n \n const output: ReadFileResult = {\n content: result.content,\n size: result.size,\n encoding: result.encoding,\n };\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(output, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error('File read error', { path, error: errorMessage });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n error: errorMessage,\n content: '',\n size: 0,\n encoding,\n }, null, 2),\n },\n ],\n };\n }\n}\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\nimport { logger } from '../utils/logger.js';\n\nexport const acpRemoteWriteFileTool: Tool = {\n name: 'acp_remote_write_file',\n description: 'Write file contents to the remote machine via SSH',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Absolute path to file',\n },\n content: {\n type: 'string',\n description: 'File contents to write',\n },\n encoding: {\n type: 'string',\n description: 'File encoding (default: utf-8)',\n default: 'utf-8',\n },\n createDirs: {\n type: 'boolean',\n description: 'Create parent directories if they don\\'t exist (default: false)',\n default: false,\n },\n backup: {\n type: 'boolean',\n description: 'Backup existing file before overwriting (default: false)',\n default: false,\n },\n },\n required: ['path', 'content'],\n },\n};\n\ninterface WriteFileArgs {\n path: string;\n content: string;\n encoding?: string;\n createDirs?: boolean;\n backup?: boolean;\n}\n\ninterface WriteFileResult {\n success: boolean;\n bytesWritten: number;\n backupPath?: string;\n}\n\n/**\n * Handle the acp_remote_write_file tool invocation\n * Writes file contents to the remote machine via SSH\n * \n * @param args - Tool arguments containing path, content, and options\n * @param sshConnection - SSH connection manager for remote operations\n */\nexport async function handleAcpRemoteWriteFile(\n args: any,\n sshConnection: SSHConnectionManager\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { path, content, encoding = 'utf-8', createDirs = false, backup = false } = args as WriteFileArgs;\n\n logger.debug('Writing remote file', { path, contentSize: content.length, encoding, createDirs, backup });\n\n try {\n const result = await sshConnection.writeFile(path, content, {\n encoding,\n createDirs,\n backup,\n });\n \n logger.debug('File write successful', { path, bytesWritten: result.bytesWritten, backupPath: result.backupPath });\n \n const output: WriteFileResult = {\n success: result.success,\n bytesWritten: result.bytesWritten,\n backupPath: result.backupPath,\n };\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(output, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error('File write error', { path, error: errorMessage });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n success: false,\n bytesWritten: 0,\n error: errorMessage,\n }, null, 2),\n },\n ],\n };\n }\n}\n", "import { Client, SFTPWrapper } from 'ssh2';\nimport { SSHConfig } from '../types/ssh-config.js';\nimport { FileEntry, parsePermissions, getFileType } from '../types/file-entry.js';\nimport { logger } from './logger.js';\n\n/**\n * SSH Connection Manager\n * Manages SSH connections and provides SFTP access for remote file operations\n */\nexport class SSHConnectionManager {\n private client: Client;\n private config: SSHConfig;\n private connected: boolean = false;\n\n constructor(config: SSHConfig) {\n this.config = config;\n this.client = new Client();\n }\n\n /**\n * Connect to the remote SSH server\n */\n async connect(): Promise<void> {\n if (this.connected) {\n logger.debug('SSH connection already established');\n return;\n }\n\n logger.info('Connecting to SSH server', {\n host: this.config.host,\n port: this.config.port || 22,\n username: this.config.username,\n });\n\n return new Promise((resolve, reject) => {\n this.client\n .on('ready', () => {\n this.connected = true;\n logger.info('SSH connection established', {\n host: this.config.host,\n username: this.config.username,\n });\n resolve();\n })\n .on('error', (err) => {\n logger.error('SSH connection failed', {\n host: this.config.host,\n error: err.message,\n });\n reject(err);\n })\n .connect({\n host: this.config.host,\n port: this.config.port || 22,\n username: this.config.username,\n privateKey: this.config.privateKey,\n });\n });\n }\n\n /**\n * Execute a command on the remote server\n */\n async exec(command: string): Promise<string> {\n if (!this.connected) {\n await this.connect();\n }\n\n return new Promise((resolve, reject) => {\n this.client.exec(command, (err, stream) => {\n if (err) {\n reject(err);\n return;\n }\n\n let stdout = '';\n let stderr = '';\n\n stream\n .on('close', (code: number) => {\n if (code !== 0) {\n reject(new Error(`Command failed with code ${code}: ${stderr}`));\n } else {\n resolve(stdout);\n }\n })\n .on('data', (data: Buffer) => {\n stdout += data.toString();\n })\n .stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n });\n });\n }\n\n /**\n * Execute a command on the remote server with timeout support\n */\n async execWithTimeout(\n command: string,\n timeoutSeconds: number = 30\n ): Promise<{ stdout: string; stderr: string; exitCode: number; timedOut: boolean }> {\n if (!this.connected) {\n await this.connect();\n }\n\n const startTime = Date.now();\n // Wrap command to source shell config for proper PATH and environment\n const wrappedCommand = this.wrapCommandWithShellInit(command);\n logger.sshCommand(wrappedCommand, undefined, timeoutSeconds);\n\n const execPromise = new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve, reject) => {\n this.client.exec(wrappedCommand, (err, stream) => {\n if (err) {\n reject(err);\n return;\n }\n\n let stdout = '';\n let stderr = '';\n\n stream\n .on('close', (code: number) => {\n const duration = Date.now() - startTime;\n logger.sshCommandResult(code, duration, stdout.length, stderr.length);\n resolve({ stdout, stderr, exitCode: code });\n })\n .on('data', (data: Buffer) => {\n stdout += data.toString();\n })\n .stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n });\n });\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error('Command execution timed out'));\n }, timeoutSeconds * 1000);\n });\n\n try {\n const result = await Promise.race([execPromise, timeoutPromise]);\n return { ...result, timedOut: false };\n } catch (error) {\n if (error instanceof Error && error.message === 'Command execution timed out') {\n logger.warn('SSH command timed out', { command, timeout: timeoutSeconds });\n return {\n stdout: '',\n stderr: 'Command execution timed out',\n exitCode: 124,\n timedOut: true,\n };\n }\n logger.error('SSH command execution failed', {\n command,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Execute a command on the remote server with streaming output\n * Returns streams instead of buffered output for real-time progress\n *\n * @param command - Shell command to execute\n * @param cwd - Optional working directory\n * @returns Object with stdout stream, stderr stream, and exit code promise\n */\n async execStream(\n command: string,\n cwd?: string\n ): Promise<{\n stream: NodeJS.ReadableStream;\n stderr: NodeJS.ReadableStream;\n exitCode: Promise<number>;\n }> {\n if (!this.connected) {\n await this.connect();\n }\n\n const fullCommand = cwd ? `cd \"${cwd}\" && ${command}` : command;\n // Wrap command to source shell config for proper PATH and environment\n const wrappedCommand = this.wrapCommandWithShellInit(fullCommand);\n const startTime = Date.now();\n logger.sshCommand(wrappedCommand, cwd);\n\n return new Promise((resolve, reject) => {\n this.client.exec(wrappedCommand, (err, stream) => {\n if (err) {\n logger.error('SSH exec failed', {\n command: fullCommand,\n error: err.message\n });\n reject(err);\n return;\n }\n\n logger.debug('SSH stream started', { command: fullCommand });\n\n const exitCodePromise = new Promise<number>((resolveExit) => {\n stream.on('close', (code: number) => {\n const duration = Date.now() - startTime;\n logger.debug('SSH stream closed', {\n command: fullCommand,\n exitCode: code,\n duration: `${duration}ms`\n });\n resolveExit(code);\n });\n });\n\n // Handle stream errors\n stream.on('error', (error: Error) => {\n logger.error('SSH stream error', {\n command: fullCommand,\n error: error.message\n });\n });\n\n resolve({\n stream: stream,\n stderr: stream.stderr,\n exitCode: exitCodePromise,\n });\n });\n });\n }\n\n /**\n * Get SFTP wrapper for file operations\n */\n async getSFTP(): Promise<SFTPWrapper> {\n if (!this.connected) {\n await this.connect();\n }\n\n return new Promise((resolve, reject) => {\n this.client.sftp((err, sftp) => {\n if (err) {\n reject(err);\n } else {\n resolve(sftp);\n }\n });\n });\n }\n\n /**\n * List files in a directory with comprehensive metadata\n * Uses hybrid approach: shell ls for filenames (includes hidden), SFTP stat for metadata\n *\n * @param path - Directory path to list\n * @param includeHidden - Whether to include hidden files (default: true)\n * @returns Array of FileEntry objects with complete metadata\n */\n async listFiles(path: string, includeHidden: boolean = true): Promise<FileEntry[]> {\n const startTime = Date.now();\n logger.debug('Listing files', { path, includeHidden });\n\n try {\n // Step 1: Use shell command to get ALL filenames (including hidden)\n const lsFlag = includeHidden ? '-A' : '';\n const command = `ls ${lsFlag} -1 \"${path}\" 2>/dev/null`;\n const result = await this.execWithTimeout(command, 10);\n\n if (result.exitCode !== 0) {\n throw new Error(`ls command failed: ${result.stderr}`);\n }\n\n const filenames = result.stdout\n .split('\\n')\n .map(f => f.trim())\n .filter(f => f !== '' && f !== '.' && f !== '..');\n\n logger.debug('Filenames retrieved via shell', {\n path,\n count: filenames.length,\n method: 'shell',\n });\n\n // Step 2: Get rich metadata for each file using SFTP stat()\n const sftp = await this.getSFTP();\n const entries: FileEntry[] = [];\n\n for (const filename of filenames) {\n const fullPath = `${path}/${filename}`.replace(/\\/+/g, '/');\n\n try {\n const stats = await new Promise<any>((resolve, reject) => {\n sftp.stat(fullPath, (err, stats) => {\n if (err) reject(err);\n else resolve(stats);\n });\n });\n\n entries.push({\n name: filename,\n path: fullPath,\n type: getFileType(stats),\n size: stats.size,\n permissions: parsePermissions(stats.mode),\n owner: {\n uid: stats.uid,\n gid: stats.gid,\n },\n timestamps: {\n accessed: new Date(stats.atime * 1000).toISOString(),\n modified: new Date(stats.mtime * 1000).toISOString(),\n },\n });\n } catch (error) {\n // Skip files we can't stat (permissions, race conditions, etc.)\n logger.warn('Failed to stat file, skipping', {\n path: fullPath,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n const duration = Date.now() - startTime;\n logger.debug('Files listed successfully', {\n path,\n count: entries.length,\n duration: `${duration}ms`,\n method: 'hybrid',\n });\n\n return entries;\n } catch (error) {\n // Fallback to SFTP readdir if shell command fails\n logger.warn('Shell ls command failed, falling back to SFTP readdir', {\n path,\n error: error instanceof Error ? error.message : String(error),\n });\n\n return this.listFilesViaSFTP(path, includeHidden);\n }\n }\n\n /**\n * Fallback method: List files using SFTP readdir (may miss hidden files)\n * @private\n */\n private async listFilesViaSFTP(path: string, includeHidden: boolean): Promise<FileEntry[]> {\n const sftp = await this.getSFTP();\n\n return new Promise((resolve, reject) => {\n sftp.readdir(path, (err, list) => {\n if (err) {\n logger.error('SFTP readdir failed', { path, error: err.message });\n reject(err);\n return;\n }\n\n let entries = list.map((item) => ({\n name: item.filename,\n path: `${path}/${item.filename}`.replace(/\\/+/g, '/'),\n type: getFileType(item.attrs),\n size: item.attrs.size,\n permissions: parsePermissions(item.attrs.mode),\n owner: {\n uid: item.attrs.uid,\n gid: item.attrs.gid,\n },\n timestamps: {\n accessed: new Date(item.attrs.atime * 1000).toISOString(),\n modified: new Date(item.attrs.mtime * 1000).toISOString(),\n },\n }));\n\n // SFTP readdir doesn't return hidden files, so filter if requested\n if (!includeHidden) {\n entries = entries.filter(e => !e.name.startsWith('.'));\n }\n\n logger.debug('Files listed via SFTP fallback', {\n path,\n count: entries.length,\n method: 'sftp',\n note: 'Hidden files may be missing (SFTP limitation)',\n });\n\n resolve(entries);\n });\n });\n }\n\n /**\n * Read file contents from remote machine\n */\n async readFile(\n path: string,\n encoding: string = 'utf-8',\n maxSize: number = 1048576\n ): Promise<{ content: string; size: number; encoding: string }> {\n const startTime = Date.now();\n logger.fileOperation('read', path, { encoding, maxSize });\n \n const sftp = await this.getSFTP();\n\n return new Promise((resolve, reject) => {\n // First, get file stats to check size\n sftp.stat(path, (err, stats) => {\n if (err) {\n logger.error('File stat failed', { path, error: err.message });\n reject(new Error(`File not found or inaccessible: ${path}`));\n return;\n }\n\n logger.debug('File stat retrieved', { path, size: stats.size });\n\n if (stats.size > maxSize) {\n logger.warn('File too large', { path, size: stats.size, maxSize });\n reject(new Error(`File too large: ${stats.size} bytes (max: ${maxSize} bytes)`));\n return;\n }\n\n // Read file contents\n sftp.readFile(path, { encoding: encoding as BufferEncoding }, (err, data) => {\n if (err) {\n logger.error('File read failed', { path, error: err.message });\n reject(new Error(`Failed to read file: ${err.message}`));\n return;\n }\n\n const duration = Date.now() - startTime;\n logger.debug('File read completed', { path, size: stats.size, duration: `${duration}ms` });\n\n resolve({\n content: data.toString(),\n size: stats.size,\n encoding,\n });\n });\n });\n });\n }\n\n /**\n * Write file contents to remote machine\n */\n async writeFile(\n path: string,\n content: string,\n options: {\n encoding?: string;\n createDirs?: boolean;\n backup?: boolean;\n } = {}\n ): Promise<{ success: boolean; bytesWritten: number; backupPath?: string }> {\n const { encoding = 'utf-8', createDirs = false, backup = false } = options;\n const startTime = Date.now();\n \n logger.fileOperation('write', path, {\n contentSize: content.length,\n encoding,\n createDirs,\n backup,\n });\n \n const sftp = await this.getSFTP();\n\n return new Promise((resolve, reject) => {\n const writeOperation = () => {\n // Create backup if requested\n if (backup) {\n const backupPath = `${path}.backup`;\n sftp.rename(path, backupPath, (err) => {\n if (err && err.message !== 'No such file') {\n // Ignore \"no such file\" error (file doesn't exist yet)\n reject(new Error(`Failed to create backup: ${err.message}`));\n return;\n }\n \n // Write file\n performWrite(backupPath);\n });\n } else {\n performWrite();\n }\n };\n\n const performWrite = (backupPath?: string) => {\n const buffer = Buffer.from(content, encoding as BufferEncoding);\n const tempPath = `${path}.tmp`;\n\n // Write to temp file first (atomic write)\n sftp.writeFile(tempPath, buffer, (err) => {\n if (err) {\n reject(new Error(`Failed to write file: ${err.message}`));\n return;\n }\n\n // Rename temp file to target (atomic operation)\n sftp.rename(tempPath, path, (err) => {\n if (err) {\n logger.error('File rename failed', { tempPath, path, error: err.message });\n reject(new Error(`Failed to rename temp file: ${err.message}`));\n return;\n }\n\n const duration = Date.now() - startTime;\n logger.debug('File write completed', {\n path,\n bytesWritten: buffer.length,\n duration: `${duration}ms`,\n backupPath,\n });\n\n resolve({\n success: true,\n bytesWritten: buffer.length,\n backupPath,\n });\n });\n });\n };\n\n // Create parent directories if requested\n if (createDirs) {\n const dirPath = path.substring(0, path.lastIndexOf('/'));\n this.exec(`mkdir -p ${dirPath}`).then(() => {\n writeOperation();\n }).catch(reject);\n } else {\n writeOperation();\n }\n });\n }\n\n /**\n * Wrap command to source shell configuration files\n * This ensures PATH and other environment variables are properly set\n * SSH non-interactive shells don't source ~/.bashrc or ~/.zshrc by default\n *\n * @param command - The command to wrap\n * @returns Wrapped command that sources shell config first\n */\n private wrapCommandWithShellInit(command: string): string {\n // Try to source common shell config files\n // Use || true to ignore errors if files don't exist\n return `(source ~/.zshrc 2>/dev/null || source ~/.bashrc 2>/dev/null || source ~/.profile 2>/dev/null || true) && ${command}`;\n }\n\n /**\n * Disconnect from the SSH server\n */\n disconnect(): void {\n if (this.connected) {\n logger.info('Disconnecting from SSH server', {\n host: this.config.host,\n username: this.config.username,\n });\n this.client.end();\n this.connected = false;\n }\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.connected;\n }\n}\n", "/**\n * Comprehensive file entry with metadata\n */\nexport interface FileEntry {\n /** Filename (without path) */\n name: string;\n \n /** Absolute path to file */\n path: string;\n \n /** File type */\n type: 'file' | 'directory' | 'symlink' | 'other';\n \n /** File size in bytes */\n size: number;\n \n /** File permissions */\n permissions: {\n /** Octal mode (e.g., 0o644) */\n mode: number;\n \n /** Human-readable string (e.g., \"rw-r--r--\") */\n string: string;\n \n /** Owner permissions */\n owner: {\n read: boolean;\n write: boolean;\n execute: boolean;\n };\n \n /** Group permissions */\n group: {\n read: boolean;\n write: boolean;\n execute: boolean;\n };\n \n /** Others permissions */\n others: {\n read: boolean;\n write: boolean;\n execute: boolean;\n };\n };\n \n /** File ownership */\n owner: {\n /** User ID */\n uid: number;\n \n /** Group ID */\n gid: number;\n };\n \n /** File timestamps */\n timestamps: {\n /** Last access time (ISO 8601) */\n accessed: string;\n \n /** Last modification time (ISO 8601) */\n modified: string;\n };\n}\n\n/**\n * Convert Unix mode to human-readable permission string\n * @param mode - Unix file mode (e.g., 33188 for -rw-r--r--)\n * @returns Permission string (e.g., \"rw-r--r--\")\n */\nexport function modeToPermissionString(mode: number): string {\n const perms = [\n (mode & 0o400) ? 'r' : '-',\n (mode & 0o200) ? 'w' : '-',\n (mode & 0o100) ? 'x' : '-',\n (mode & 0o040) ? 'r' : '-',\n (mode & 0o020) ? 'w' : '-',\n (mode & 0o010) ? 'x' : '-',\n (mode & 0o004) ? 'r' : '-',\n (mode & 0o002) ? 'w' : '-',\n (mode & 0o001) ? 'x' : '-',\n ];\n return perms.join('');\n}\n\n/**\n * Parse Unix mode into structured permissions object\n * @param mode - Unix file mode\n * @returns Structured permissions object\n */\nexport function parsePermissions(mode: number) {\n return {\n mode,\n string: modeToPermissionString(mode),\n owner: {\n read: (mode & 0o400) !== 0,\n write: (mode & 0o200) !== 0,\n execute: (mode & 0o100) !== 0,\n },\n group: {\n read: (mode & 0o040) !== 0,\n write: (mode & 0o020) !== 0,\n execute: (mode & 0o010) !== 0,\n },\n others: {\n read: (mode & 0o004) !== 0,\n write: (mode & 0o002) !== 0,\n execute: (mode & 0o001) !== 0,\n },\n };\n}\n\n/**\n * Determine file type from SFTP stats\n * @param stats - SFTP file stats\n * @returns File type string\n */\nexport function getFileType(stats: any): 'file' | 'directory' | 'symlink' | 'other' {\n if (stats.isDirectory()) return 'directory';\n if (stats.isFile()) return 'file';\n if (stats.isSymbolicLink()) return 'symlink';\n return 'other';\n}\n"],
5
- "mappings": "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",
6
- "names": ["stats", "err"]
3
+ "sources": ["../src/server-factory.ts", "../src/utils/logger.ts", "../src/tools/acp-remote-execute-command.ts", "../src/utils/ssh-connection.ts"],
4
+ "sourcesContent": ["import { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { config } from './config.js';\nimport { acpRemoteExecuteCommandTool, handleAcpRemoteExecuteCommand } from './tools/acp-remote-execute-command.js';\nimport { ServerConfig } from './types/ssh-config.js';\nimport { SSHConnectionManager } from './utils/ssh-connection.js';\nimport { logger } from './utils/logger.js';\n\n/**\n * Create an MCP server instance for a specific user with SSH configuration\n * This factory function is used by mcp-auth for multi-tenant support\n * \n * @param serverConfig - Configuration including userId and SSH credentials\n * @returns Configured MCP Server instance\n */\nexport async function createServer(serverConfig: ServerConfig): Promise<Server> {\n logger.info('Creating server instance', { userId: serverConfig.userId });\n logger.debug('SSH configuration', {\n host: serverConfig.ssh.host,\n port: serverConfig.ssh.port,\n username: serverConfig.ssh.username,\n });\n \n // Create SSH connection manager\n const sshConnection = new SSHConnectionManager(serverConfig.ssh);\n \n // Connect to remote server\n await sshConnection.connect();\n \n logger.info('Server created successfully', { userId: serverConfig.userId });\n\n const server = new Server(\n {\n name: 'acp-mcp',\n version: '0.1.0',\n },\n {\n capabilities: {\n tools: {},\n },\n }\n );\n\n // Register tools with SSH connection context\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n logger.debug('Tool discovery requested', { userId: serverConfig.userId });\n const tools = [acpRemoteExecuteCommandTool];\n logger.debug(`Returning ${tools.length} tools`, { tools: tools.map(t => t.name), userId: serverConfig.userId });\n return { tools };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {\n const startTime = Date.now();\n logger.toolInvoked(request.params.name, request.params.arguments, serverConfig.userId);\n \n try {\n let result;\n \n if (request.params.name === 'acp_remote_execute_command') {\n // Pass extra and server for progress streaming support\n result = await handleAcpRemoteExecuteCommand(request.params.arguments, sshConnection, extra, server);\n } else {\n throw new Error(`Unknown tool: ${request.params.name}`);\n }\n \n const duration = Date.now() - startTime;\n const resultSize = JSON.stringify(result).length;\n logger.toolCompleted(request.params.name, duration, resultSize);\n \n return result;\n } catch (error) {\n logger.toolFailed(request.params.name, error as Error, request.params.arguments);\n throw error;\n }\n });\n\n // Handle server shutdown to cleanup SSH connection\n process.on('SIGINT', () => {\n logger.info('Received SIGINT, shutting down', { userId: serverConfig.userId });\n sshConnection.disconnect();\n process.exit(0);\n });\n\n process.on('SIGTERM', () => {\n logger.info('Received SIGTERM, shutting down', { userId: serverConfig.userId });\n sshConnection.disconnect();\n process.exit(0);\n });\n\n return server;\n}\n", "/**\n * Logger utility for ACP MCP Server\n * Provides structured logging with configurable log levels\n */\n\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug' | 'trace';\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n error: 0,\n warn: 1,\n info: 2,\n debug: 3,\n trace: 4,\n};\n\nclass Logger {\n private level: LogLevel;\n private enabled: boolean;\n\n constructor() {\n // Read configuration from environment variables\n this.level = (process.env.ACP_MCP_LOG_LEVEL as LogLevel) || 'info';\n this.enabled = process.env.ACP_MCP_DEBUG === 'true' || process.env.NODE_ENV === 'development';\n }\n\n private shouldLog(level: LogLevel): boolean {\n if (!this.enabled && level !== 'error' && level !== 'warn') {\n return false;\n }\n return LOG_LEVELS[level] <= LOG_LEVELS[this.level];\n }\n\n private formatMessage(level: LogLevel, message: string, data?: any): string {\n const timestamp = new Date().toISOString();\n const prefix = `[${timestamp}] [${level.toUpperCase()}]`;\n \n if (data !== undefined) {\n const dataStr = typeof data === 'object' ? JSON.stringify(data, null, 2) : String(data);\n return `${prefix} ${message}\\n${dataStr}`;\n }\n \n return `${prefix} ${message}`;\n }\n\n error(message: string, data?: any): void {\n if (this.shouldLog('error')) {\n console.error(this.formatMessage('error', message, data));\n }\n }\n\n warn(message: string, data?: any): void {\n if (this.shouldLog('warn')) {\n console.error(this.formatMessage('warn', message, data));\n }\n }\n\n info(message: string, data?: any): void {\n if (this.shouldLog('info')) {\n console.error(this.formatMessage('info', message, data));\n }\n }\n\n debug(message: string, data?: any): void {\n if (this.shouldLog('debug')) {\n console.error(this.formatMessage('debug', message, data));\n }\n }\n\n trace(message: string, data?: any): void {\n if (this.shouldLog('trace')) {\n console.error(this.formatMessage('trace', message, data));\n }\n }\n\n /**\n * Log tool invocation with parameters\n */\n toolInvoked(toolName: string, params: any, userId?: string): void {\n this.info(`Tool invoked: ${toolName}`);\n this.debug('Tool parameters', { tool: toolName, params, userId });\n }\n\n /**\n * Log tool completion with result summary\n */\n toolCompleted(toolName: string, duration: number, resultSize?: number): void {\n this.info(`Tool completed: ${toolName}`);\n this.debug('Tool performance', { tool: toolName, duration: `${duration}ms`, resultSize });\n }\n\n /**\n * Log tool failure with error details\n */\n toolFailed(toolName: string, error: Error, params?: any): void {\n this.error(`Tool execution failed: ${toolName}`, {\n tool: toolName,\n error: error.message,\n stack: error.stack,\n params,\n });\n }\n\n /**\n * Log SSH command execution\n */\n sshCommand(command: string, cwd?: string, timeout?: number): void {\n this.debug('Executing SSH command', { command, cwd, timeout });\n }\n\n /**\n * Log SSH command result\n */\n sshCommandResult(exitCode: number, duration: number, stdoutSize: number, stderrSize: number): void {\n this.debug('SSH command completed', {\n exitCode,\n duration: `${duration}ms`,\n stdout: `${stdoutSize} bytes`,\n stderr: `${stderrSize} bytes`,\n });\n }\n\n /**\n * Log file operation\n */\n fileOperation(operation: string, path: string, details?: any): void {\n this.info(`File operation: ${operation}`, { path, ...details });\n }\n}\n\n// Export singleton instance\nexport const logger = new Logger();\n", "import { Tool } from '@modelcontextprotocol/sdk/types.js';\nimport { SSHConnectionManager } from '../utils/ssh-connection.js';\nimport { logger } from '../utils/logger.js';\n\nexport const acpRemoteExecuteCommandTool: Tool = {\n name: 'acp_remote_execute_command',\n description: 'Execute a shell command on the remote machine via SSH. Supports real-time progress streaming if client provides progressToken.',\n inputSchema: {\n type: 'object',\n properties: {\n command: {\n type: 'string',\n description: 'Shell command to execute',\n },\n cwd: {\n type: 'string',\n description: 'Working directory for command execution (optional)',\n },\n timeout: {\n type: 'number',\n description: 'Timeout in seconds (default: 30). Ignored if progress streaming is used.',\n default: 30,\n },\n },\n required: ['command'],\n },\n};\n\ninterface ExecuteCommandArgs {\n command: string;\n cwd?: string;\n timeout?: number;\n}\n\ninterface ExecuteCommandResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n timedOut: boolean;\n streamed?: boolean;\n}\n\n/**\n * Handle the acp_remote_execute_command tool invocation\n * Executes a shell command on the remote machine via SSH\n * Supports progress streaming when progressToken is provided\n * \n * @param args - Tool arguments containing command, cwd, and timeout\n * @param sshConnection - SSH connection manager for remote operations\n * @param extra - Optional extra parameters including progressToken\n * @param server - Server instance for sending progress notifications (optional)\n */\nexport async function handleAcpRemoteExecuteCommand(\n args: any,\n sshConnection: SSHConnectionManager,\n extra?: any,\n server?: any\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n const { command, cwd, timeout = 30 } = args as ExecuteCommandArgs;\n const progressToken = extra?._meta?.progressToken;\n\n logger.debug('Executing remote command', { command, cwd, timeout, hasProgressToken: !!progressToken });\n\n try {\n // If progress token provided and server available, use streaming\n if (progressToken && server) {\n return await executeWithProgress(command, cwd, sshConnection, progressToken, server);\n }\n \n // Otherwise, use existing timeout-based execution (fallback)\n const fullCommand = cwd ? `cd ${cwd} && ${command}` : command;\n const result = await sshConnection.execWithTimeout(fullCommand, timeout);\n \n logger.debug('Command execution result', {\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n stdoutLength: result.stdout.length,\n stderrLength: result.stderr.length,\n });\n \n const output: ExecuteCommandResult = {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n };\n \n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(output, null, 2),\n },\n ],\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error('Command execution error', { command, error: errorMessage });\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n stdout: '',\n stderr: errorMessage,\n exitCode: 1,\n timedOut: false,\n }, null, 2),\n },\n ],\n };\n }\n}\n\n/**\n * Execute command with progress streaming\n * Sends real-time progress notifications as output is received\n * \n * @param command - Command to execute\n * @param cwd - Working directory\n * @param sshConnection - SSH connection\n * @param progressToken - Token for progress notifications\n * @param server - Server instance for sending notifications\n */\nasync function executeWithProgress(\n command: string,\n cwd: string | undefined,\n sshConnection: SSHConnectionManager,\n progressToken: string | number,\n server: any\n): Promise<{ content: Array<{ type: string; text: string }> }> {\n logger.debug('Starting streaming execution', { command, cwd, progressToken });\n \n const { stream, stderr: stderrStream, exitCode } = await sshConnection.execStream(command, cwd);\n \n let stdout = '';\n let stderr = '';\n let bytesReceived = 0;\n let lastProgressTime = 0;\n const MIN_PROGRESS_INTERVAL = 100; // 100ms rate limiting\n\n // Stream stdout with progress notifications\n stream.on('data', (chunk: Buffer) => {\n const text = chunk.toString();\n stdout += text;\n bytesReceived += chunk.length;\n \n // Rate limiting: only send progress if enough time elapsed\n const now = Date.now();\n if (now - lastProgressTime >= MIN_PROGRESS_INTERVAL) {\n try {\n server.notification({\n method: 'notifications/progress',\n params: {\n progressToken,\n progress: bytesReceived,\n total: undefined, // Unknown total for streaming\n message: text,\n },\n });\n lastProgressTime = now;\n logger.debug('Progress notification sent', { \n progressToken, \n bytes: bytesReceived,\n chunkSize: chunk.length \n });\n } catch (error) {\n logger.warn('Failed to send progress notification', {\n error: error instanceof Error ? error.message : String(error)\n });\n }\n }\n });\n\n // Collect stderr (no progress for errors)\n stderrStream.on('data', (chunk: Buffer) => {\n stderr += chunk.toString();\n });\n\n // Handle stream errors\n stream.on('error', (error: Error) => {\n logger.error('Stream error during execution', {\n command,\n error: error.message\n });\n });\n\n // Wait for completion\n const finalExitCode = await exitCode;\n \n logger.debug('Streaming execution completed', { \n command, \n exitCode: finalExitCode,\n stdoutBytes: stdout.length,\n stderrBytes: stderr.length,\n });\n\n const output: ExecuteCommandResult = {\n stdout,\n stderr,\n exitCode: finalExitCode,\n timedOut: false,\n streamed: true, // Indicate this was streamed\n };\n\n return {\n content: [{\n type: 'text',\n text: JSON.stringify(output, null, 2),\n }],\n };\n}\n", "import { Client } from 'ssh2';\nimport { SSHConfig } from '../types/ssh-config.js';\nimport { logger } from './logger.js';\n\n/**\n * SSH Connection Manager\n * Manages SSH connections and provides SFTP access for remote file operations\n */\nexport class SSHConnectionManager {\n private client: Client;\n private config: SSHConfig;\n private connected: boolean = false;\n\n constructor(config: SSHConfig) {\n this.config = config;\n this.client = new Client();\n }\n\n /**\n * Connect to the remote SSH server\n */\n async connect(): Promise<void> {\n if (this.connected) {\n logger.debug('SSH connection already established');\n return;\n }\n\n logger.info('Connecting to SSH server', {\n host: this.config.host,\n port: this.config.port || 22,\n username: this.config.username,\n });\n\n return new Promise((resolve, reject) => {\n this.client\n .on('ready', () => {\n this.connected = true;\n logger.info('SSH connection established', {\n host: this.config.host,\n username: this.config.username,\n });\n resolve();\n })\n .on('error', (err) => {\n logger.error('SSH connection failed', {\n host: this.config.host,\n error: err.message,\n });\n reject(err);\n })\n .connect({\n host: this.config.host,\n port: this.config.port || 22,\n username: this.config.username,\n privateKey: this.config.privateKey,\n });\n });\n }\n\n /**\n * Execute a command on the remote server\n */\n async exec(command: string): Promise<string> {\n if (!this.connected) {\n await this.connect();\n }\n\n return new Promise((resolve, reject) => {\n this.client.exec(command, (err, stream) => {\n if (err) {\n reject(err);\n return;\n }\n\n let stdout = '';\n let stderr = '';\n\n stream\n .on('close', (code: number) => {\n if (code !== 0) {\n reject(new Error(`Command failed with code ${code}: ${stderr}`));\n } else {\n resolve(stdout);\n }\n })\n .on('data', (data: Buffer) => {\n stdout += data.toString();\n })\n .stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n });\n });\n }\n\n /**\n * Execute a command on the remote server with timeout support\n */\n async execWithTimeout(\n command: string,\n timeoutSeconds: number = 30\n ): Promise<{ stdout: string; stderr: string; exitCode: number; timedOut: boolean }> {\n if (!this.connected) {\n await this.connect();\n }\n\n const startTime = Date.now();\n // Wrap command to source shell config for proper PATH and environment\n const wrappedCommand = this.wrapCommandWithShellInit(command);\n logger.sshCommand(wrappedCommand, undefined, timeoutSeconds);\n\n const execPromise = new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve, reject) => {\n this.client.exec(wrappedCommand, (err, stream) => {\n if (err) {\n reject(err);\n return;\n }\n\n let stdout = '';\n let stderr = '';\n\n stream\n .on('close', (code: number) => {\n const duration = Date.now() - startTime;\n logger.sshCommandResult(code, duration, stdout.length, stderr.length);\n resolve({ stdout, stderr, exitCode: code });\n })\n .on('data', (data: Buffer) => {\n stdout += data.toString();\n })\n .stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n });\n });\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n setTimeout(() => {\n reject(new Error('Command execution timed out'));\n }, timeoutSeconds * 1000);\n });\n\n try {\n const result = await Promise.race([execPromise, timeoutPromise]);\n return { ...result, timedOut: false };\n } catch (error) {\n if (error instanceof Error && error.message === 'Command execution timed out') {\n logger.warn('SSH command timed out', { command, timeout: timeoutSeconds });\n return {\n stdout: '',\n stderr: 'Command execution timed out',\n exitCode: 124,\n timedOut: true,\n };\n }\n logger.error('SSH command execution failed', {\n command,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n }\n\n /**\n * Execute a command on the remote server with streaming output\n * Returns streams instead of buffered output for real-time progress\n *\n * @param command - Shell command to execute\n * @param cwd - Optional working directory\n * @returns Object with stdout stream, stderr stream, and exit code promise\n */\n async execStream(\n command: string,\n cwd?: string\n ): Promise<{\n stream: NodeJS.ReadableStream;\n stderr: NodeJS.ReadableStream;\n exitCode: Promise<number>;\n }> {\n if (!this.connected) {\n await this.connect();\n }\n\n const fullCommand = cwd ? `cd \"${cwd}\" && ${command}` : command;\n // Wrap command to source shell config for proper PATH and environment\n const wrappedCommand = this.wrapCommandWithShellInit(fullCommand);\n const startTime = Date.now();\n logger.sshCommand(wrappedCommand, cwd);\n\n return new Promise((resolve, reject) => {\n this.client.exec(wrappedCommand, (err, stream) => {\n if (err) {\n logger.error('SSH exec failed', {\n command: fullCommand,\n error: err.message\n });\n reject(err);\n return;\n }\n\n logger.debug('SSH stream started', { command: fullCommand });\n\n const exitCodePromise = new Promise<number>((resolveExit) => {\n stream.on('close', (code: number) => {\n const duration = Date.now() - startTime;\n logger.debug('SSH stream closed', {\n command: fullCommand,\n exitCode: code,\n duration: `${duration}ms`\n });\n resolveExit(code);\n });\n });\n\n // Handle stream errors\n stream.on('error', (error: Error) => {\n logger.error('SSH stream error', {\n command: fullCommand,\n error: error.message\n });\n });\n\n resolve({\n stream: stream,\n stderr: stream.stderr,\n exitCode: exitCodePromise,\n });\n });\n });\n }\n\n /**\n * Wrap command to source shell configuration files\n * This ensures PATH and other environment variables are properly set\n * SSH non-interactive shells don't source ~/.bashrc or ~/.zshrc by default\n *\n * @param command - The command to wrap\n * @returns Wrapped command that sources shell config first\n */\n private wrapCommandWithShellInit(command: string): string {\n // Try to source common shell config files\n // Use || true to ignore errors if files don't exist\n return `(source ~/.zshrc 2>/dev/null || source ~/.bashrc 2>/dev/null || source ~/.profile 2>/dev/null || true) && ${command}`;\n }\n\n /**\n * Disconnect from the SSH server\n */\n disconnect(): void {\n if (this.connected) {\n logger.info('Disconnecting from SSH server', {\n host: this.config.host,\n username: this.config.username,\n });\n this.client.end();\n this.connected = false;\n }\n }\n\n /**\n * Check if connected\n */\n isConnected(): boolean {\n return this.connected;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
7
  }