Skip to main content
Glama

VPS Initialize

by oxy-Op
ssh-service.ts4.92 kB
import { NodeSSH } from 'node-ssh'; import { readFileSync } from 'fs'; import { SSHConfig, CommandResult } from '../types/index.js'; import { logger } from '../utils/logger.js'; export class SSHService { private ssh: NodeSSH; private isConnected = false; private config: SSHConfig; constructor(config: SSHConfig) { this.ssh = new NodeSSH(); this.config = config; } async connect(): Promise<boolean> { try { const connectionConfig: Parameters<NodeSSH['connect']>[0] = { host: this.config.host, port: this.config.port || 22, username: this.config.username, }; // Handle authentication methods if (this.config.privateKeyPath) { logger.info('Authenticating with private key', { keyPath: this.config.privateKeyPath, }); connectionConfig.privateKey = readFileSync(this.config.privateKeyPath, 'utf8'); if (this.config.passphrase) { connectionConfig.passphrase = this.config.passphrase; } } else if (this.config.password) { logger.info('Authenticating with password'); connectionConfig.password = this.config.password; } else { throw new Error('Either password or privateKeyPath must be provided'); } await this.ssh.connect(connectionConfig); this.isConnected = true; logger.info('Successfully connected to SSH server', { host: this.config.host, username: this.config.username, }); return true; } catch (error) { logger.error('Failed to connect to SSH server', { error: error instanceof Error ? error.message : 'Unknown error', host: this.config.host, }); this.isConnected = false; return false; } } async executeCommand(command: string): Promise<CommandResult> { if (!this.isConnected) { throw new Error('SSH connection not established'); } try { logger.debug('Executing command', { command }); const result = await this.ssh.execCommand(command); const commandResult: CommandResult = { success: result.code === 0, stdout: result.stdout, stderr: result.stderr, exitCode: result.code || 0, }; if (commandResult.success) { logger.debug('Command executed successfully', { command, exitCode: commandResult.exitCode, }); } else { logger.warn('Command execution failed', { command, exitCode: commandResult.exitCode, stderr: commandResult.stderr, }); } return commandResult; } catch (error) { logger.error('Error executing command', { command, error: error instanceof Error ? error.message : 'Unknown error', }); return { success: false, stdout: '', stderr: error instanceof Error ? error.message : 'Unknown error', exitCode: -1, }; } } async uploadFile(localPath: string, remotePath: string): Promise<boolean> { if (!this.isConnected) { throw new Error('SSH connection not established'); } try { logger.info('Uploading file', { localPath, remotePath }); await this.ssh.putFile(localPath, remotePath); logger.info('File uploaded successfully', { localPath, remotePath }); return true; } catch (error) { logger.error('Failed to upload file', { localPath, remotePath, error: error instanceof Error ? error.message : 'Unknown error', }); return false; } } async downloadFile(remotePath: string, localPath: string): Promise<boolean> { if (!this.isConnected) { throw new Error('SSH connection not established'); } try { logger.info('Downloading file', { remotePath, localPath }); await this.ssh.getFile(localPath, remotePath); logger.info('File downloaded successfully', { remotePath, localPath }); return true; } catch (error) { logger.error('Failed to download file', { remotePath, localPath, error: error instanceof Error ? error.message : 'Unknown error', }); return false; } } async ensureDirectory(path: string): Promise<boolean> { const result = await this.executeCommand(`mkdir -p "${path}"`); return result.success; } async fileExists(path: string): Promise<boolean> { const result = await this.executeCommand(`test -f "${path}"`); return result.success; } async directoryExists(path: string): Promise<boolean> { const result = await this.executeCommand(`test -d "${path}"`); return result.success; } async disconnect(): Promise<void> { if (this.isConnected) { this.ssh.dispose(); this.isConnected = false; logger.info('SSH connection closed'); } } isConnectionActive(): boolean { return this.isConnected; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/oxy-Op/DevPilot'

If you have feedback or need assistance with the MCP directory API, please join our Discord server