From aa7822fd2bee26239735bc1efc59dd30366d7ba4 Mon Sep 17 00:00:00 2001 From: majordave Date: Sat, 18 Apr 2026 00:05:25 -0600 Subject: [PATCH 1/2] feat: add ProxyCommand support for SOCKS5 and custom proxy connections Adds SSH ProxyCommand support to MCP SSH Manager alongside existing ProxyJump functionality. Supports SOCKS5 proxies, custom proxy commands, and Windows SSH proxy commands with proper error handling and cleanup. Configuration formats: - .env: SSH_SERVER_*_PROXYCOMMAND - TOML: proxy_command field Examples use generic placeholders (user@jump-host) for documentation. Co-Authored-By: Claude Opus 4.7 --- CLAUDE.md | 428 ++++++++++++++++++++++--------------------- README.md | 33 ++++ package.json | 2 +- src/config-loader.js | 4 + src/index.js | 56 +++++- 5 files changed, 309 insertions(+), 214 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 7ff44bf..e6be724 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,212 +1,216 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -MCP SSH Manager is a Model Context Protocol server that enables Claude Code to manage multiple SSH connections. It provides tools for executing commands, transferring files, and managing deployments across remote servers. - -## Architecture - -The system consists of three main components: - -1. **MCP Server** (`src/index.js`): Node.js-based MCP server using the Model Context Protocol SDK - - Handles SSH connections via node-ssh library - - Manages connection pooling to avoid reconnecting - - Provides MCP tools for Claude Code integration - -2. **Server Management** (`tools/server_manager.py`): Python CLI for configuration - - Manages `.env` file with server configurations - - Tests connections using Paramiko - - Configures Claude Code integration - -3. **Deployment Helpers** (`src/deploy-helper.js`, `src/server-aliases.js`): Advanced features - - Automated deployment strategies with permission handling - - Server alias management for simplified access - - Batch deployment scripts generation - -## Commands - -### Setup and Installation -```bash -npm install # Install Node.js dependencies -./scripts/setup-hooks.sh # Setup pre-commit hooks for development -``` - -### Server Management (Bash CLI) -```bash -ssh-manager server add # Add a new server -ssh-manager server list # List configured servers -ssh-manager server test SERVER # Test connection to specific server -ssh-manager server remove SERVER # Remove a server -ssh-manager server show SERVER # Show server details -``` - -### OpenAI Codex Integration -```bash -ssh-manager codex setup # Configure for Codex -ssh-manager codex migrate # Convert servers to TOML -ssh-manager codex test # Test Codex integration -ssh-manager codex convert to-toml # Convert .env to TOML -ssh-manager codex convert to-env # Convert TOML to .env -``` - -### Tool Management (NEW in v3.1) -```bash -ssh-manager tools list # Show all tools and status -ssh-manager tools configure # Interactive configuration wizard -ssh-manager tools enable # Enable a tool group -ssh-manager tools disable # Disable a tool group -ssh-manager tools reset # Reset to defaults (all tools) -ssh-manager tools export-claude # Export auto-approval config -``` - -**Tool Groups**: core (5), sessions (4), monitoring (6), backup (4), database (4), advanced (14) - -**Modes**: all (37 tools, ~43.5k tokens), minimal (5 tools, ~3.5k tokens), custom (variable) - -See [docs/TOOL_MANAGEMENT.md](docs/TOOL_MANAGEMENT.md) for complete guide. - -### Development and Testing -```bash -npm start # Start MCP server (requires stdin) -./scripts/validate.sh # Run all validation checks -node --check src/index.js # Check JavaScript syntax -python -m py_compile tools/*.py # Check Python syntax -``` - -### Debug Tools (in `debug/` directory) -```bash -./debug/test-claude-code.sh # Test Claude Code integration -node debug/test-mcp.js # Test MCP connection -node debug/test-ssh-command.js # Test SSH command execution -python debug/test_basic.py # Basic Python tests -python debug/test_fastmcp.py # FastMCP integration test -``` - -## MCP Tools Available - -The server exposes these tools to Claude Code and OpenAI Codex: - -### Core Tools -- `ssh_list_servers`: List all configured SSH servers -- `ssh_execute`: Execute commands on remote servers (supports default directories) -- `ssh_upload`: Upload files to remote servers -- `ssh_download`: Download files from remote servers - -### Backup & Restore (v2.1+) -- `ssh_backup_create`: Create database or file backups (MySQL, PostgreSQL, MongoDB, Files) -- `ssh_backup_list`: List all available backups with metadata -- `ssh_backup_restore`: Restore from previous backups -- `ssh_backup_schedule`: Schedule automatic backups using cron - -### Health & Monitoring (v2.2+) -- `ssh_health_check`: Comprehensive server health check (CPU, RAM, Disk, Network) -- `ssh_service_status`: Check status of services (nginx, mysql, docker, etc.) -- `ssh_process_manager`: List, monitor, or kill processes -- `ssh_alert_setup`: Configure health monitoring alerts and thresholds - -### Database Management (v2.3+) -- `ssh_db_dump`: Create database dumps (MySQL, PostgreSQL, MongoDB) -- `ssh_db_import`: Import SQL dumps or restore databases -- `ssh_db_list`: List databases or tables/collections -- `ssh_db_query`: Execute read-only SELECT queries (security validated) - -### Deployment & Management -- `ssh_deploy`: Deploy files with automatic permission/backup handling -- `ssh_execute_sudo`: Execute commands with sudo privileges -- `ssh_alias`: Manage server aliases (add/remove/list) -- `ssh_sync`: Bidirectional file synchronization with rsync -- `ssh_monitor`: System resource monitoring -- `ssh_tail`: Real-time log monitoring - -### Advanced Features -- `ssh_session_*`: Persistent SSH sessions -- `ssh_tunnel_*`: SSH tunnel management (local/remote/SOCKS) -- `ssh_group_*`: Server group operations -- `ssh_command_alias`: Command alias management -- `ssh_hooks`: Automation hooks -- `ssh_profile`: Profile management - -## Server Configuration - -### Configuration Formats - -MCP SSH Manager supports two configuration formats: - -1. **Environment Variables (.env)** - Traditional format for Claude Code -2. **TOML** - Modern format for OpenAI Codex - -### Configuration Loading Priority - -The system loads configurations in this order (highest to lowest priority): -1. Environment variables (process.env) -2. `.env` file in project root -3. TOML file (specified by SSH_CONFIG_PATH or ~/.codex/ssh-config.toml) - -### .env Format -``` -SSH_SERVER_[NAME]_HOST=hostname -SSH_SERVER_[NAME]_USER=username -SSH_SERVER_[NAME]_PASSWORD=password # For password auth -SSH_SERVER_[NAME]_KEYPATH=~/.ssh/key # For SSH key auth -SSH_SERVER_[NAME]_PASSPHRASE=passphrase # Optional, for passphrase-protected keys -SSH_SERVER_[NAME]_PORT=22 # Optional -SSH_SERVER_[NAME]_DEFAULT_DIR=/path # Optional default working directory -SSH_SERVER_[NAME]_SUDO_PASSWORD=pass # Optional for automated sudo -SSH_SERVER_[NAME]_PLATFORM=windows # Optional: "linux" (default) or "windows" -SSH_SERVER_[NAME]_PROXYJUMP=bastion # Optional: name of another server to use as jump host -``` - -### TOML Format -```toml -[ssh_servers.name] -host = "hostname" -user = "username" -password = "password" # For password auth -key_path = "~/.ssh/key" # For SSH key auth -passphrase = "key_passphrase" # Optional, for passphrase-protected keys -port = 22 # Optional -default_dir = "/path" # Optional default working directory -sudo_password = "pass" # Optional for automated sudo -platform = "windows" # Optional: "linux" (default) or "windows" -proxy_jump = "bastion" # Optional: name of another server to use as jump host -``` - -## Key Implementation Details - -1. **Connection Pooling**: The server maintains persistent SSH connections in a Map to avoid reconnection overhead (src/index.js:31) - -2. **Server Resolution**: Server names are resolved through aliases first, then direct lookup. Names are normalized to lowercase (src/index.js:54-68) - -3. **Default Directories**: If a server has a DEFAULT_DIR configured and no cwd is provided to ssh_execute, commands run in that directory - -4. **Deployment Strategy**: The deploy helper detects permission issues and automatically creates scripts for sudo execution when needed - -5. **Environment Loading**: Uses dotenv to load configuration from `.env` file in project root - -## Security Considerations - -- Never commit `.env` files (included in .gitignore) -- SSH keys preferred over passwords -- Sudo passwords stored separately from regular passwords -- Connection errors logged to stderr for debugging -- Pre-commit hooks check for sensitive data leaks - -## Validation and Quality - -Run `./scripts/validate.sh` before commits to check: -- JavaScript syntax validity -- Python syntax validity -- No `.env` file in git -- MCP server startup -- Dependencies installed - -## Claude Code Integration - -To install in Claude Code: -```bash -claude mcp add ssh-manager node /absolute/path/to/mcp-ssh-manager/src/index.js -``` - -Configuration is stored in `~/.config/claude-code/claude_code_config.json` \ No newline at end of file +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +MCP SSH Manager is a Model Context Protocol server that enables Claude Code to manage multiple SSH connections. It provides tools for executing commands, transferring files, and managing deployments across remote servers. + +## Architecture + +The system consists of three main components: + +1. **MCP Server** (`src/index.js`): Node.js-based MCP server using the Model Context Protocol SDK + - Handles SSH connections via node-ssh library + - Manages connection pooling to avoid reconnecting + - Provides MCP tools for Claude Code integration + +2. **Server Management** (`tools/server_manager.py`): Python CLI for configuration + - Manages `.env` file with server configurations + - Tests connections using Paramiko + - Configures Claude Code integration + +3. **Deployment Helpers** (`src/deploy-helper.js`, `src/server-aliases.js`): Advanced features + - Automated deployment strategies with permission handling + - Server alias management for simplified access + - Batch deployment scripts generation + +## Commands + +### Setup and Installation +```bash +npm install # Install Node.js dependencies +./scripts/setup-hooks.sh # Setup pre-commit hooks for development +``` + +### Server Management (Bash CLI) +```bash +ssh-manager server add # Add a new server +ssh-manager server list # List configured servers +ssh-manager server test SERVER # Test connection to specific server +ssh-manager server remove SERVER # Remove a server +ssh-manager server show SERVER # Show server details +``` + +### OpenAI Codex Integration +```bash +ssh-manager codex setup # Configure for Codex +ssh-manager codex migrate # Convert servers to TOML +ssh-manager codex test # Test Codex integration +ssh-manager codex convert to-toml # Convert .env to TOML +ssh-manager codex convert to-env # Convert TOML to .env +``` + +### Tool Management (NEW in v3.1) +```bash +ssh-manager tools list # Show all tools and status +ssh-manager tools configure # Interactive configuration wizard +ssh-manager tools enable # Enable a tool group +ssh-manager tools disable # Disable a tool group +ssh-manager tools reset # Reset to defaults (all tools) +ssh-manager tools export-claude # Export auto-approval config +``` + +**Tool Groups**: core (5), sessions (4), monitoring (6), backup (4), database (4), advanced (14) + +**Modes**: all (37 tools, ~43.5k tokens), minimal (5 tools, ~3.5k tokens), custom (variable) + +See [docs/TOOL_MANAGEMENT.md](docs/TOOL_MANAGEMENT.md) for complete guide. + +### Development and Testing +```bash +npm start # Start MCP server (requires stdin) +./scripts/validate.sh # Run all validation checks +node --check src/index.js # Check JavaScript syntax +python -m py_compile tools/*.py # Check Python syntax +``` + +### Debug Tools (in `debug/` directory) +```bash +./debug/test-claude-code.sh # Test Claude Code integration +node debug/test-mcp.js # Test MCP connection +node debug/test-ssh-command.js # Test SSH command execution +python debug/test_basic.py # Basic Python tests +python debug/test_fastmcp.py # FastMCP integration test +``` + +## MCP Tools Available + +The server exposes these tools to Claude Code and OpenAI Codex: + +### Core Tools +- `ssh_list_servers`: List all configured SSH servers +- `ssh_execute`: Execute commands on remote servers (supports default directories) +- `ssh_upload`: Upload files to remote servers +- `ssh_download`: Download files from remote servers + +### Backup & Restore (v2.1+) +- `ssh_backup_create`: Create database or file backups (MySQL, PostgreSQL, MongoDB, Files) +- `ssh_backup_list`: List all available backups with metadata +- `ssh_backup_restore`: Restore from previous backups +- `ssh_backup_schedule`: Schedule automatic backups using cron + +### Health & Monitoring (v2.2+) +- `ssh_health_check`: Comprehensive server health check (CPU, RAM, Disk, Network) +- `ssh_service_status`: Check status of services (nginx, mysql, docker, etc.) +- `ssh_process_manager`: List, monitor, or kill processes +- `ssh_alert_setup`: Configure health monitoring alerts and thresholds + +### Database Management (v2.3+) +- `ssh_db_dump`: Create database dumps (MySQL, PostgreSQL, MongoDB) +- `ssh_db_import`: Import SQL dumps or restore databases +- `ssh_db_list`: List databases or tables/collections +- `ssh_db_query`: Execute read-only SELECT queries (security validated) + +### Deployment & Management +- `ssh_deploy`: Deploy files with automatic permission/backup handling +- `ssh_execute_sudo`: Execute commands with sudo privileges +- `ssh_alias`: Manage server aliases (add/remove/list) +- `ssh_sync`: Bidirectional file synchronization with rsync +- `ssh_monitor`: System resource monitoring +- `ssh_tail`: Real-time log monitoring + +### Advanced Features +- `ssh_session_*`: Persistent SSH sessions +- `ssh_tunnel_*`: SSH tunnel management (local/remote/SOCKS) +- `ssh_group_*`: Server group operations +- `ssh_command_alias`: Command alias management +- `ssh_hooks`: Automation hooks +- `ssh_profile`: Profile management + +## Server Configuration + +### Configuration Formats + +MCP SSH Manager supports two configuration formats: + +1. **Environment Variables (.env)** - Traditional format for Claude Code +2. **TOML** - Modern format for OpenAI Codex + +### Configuration Loading Priority + +The system loads configurations in this order (highest to lowest priority): +1. Environment variables (process.env) +2. `.env` file in project root +3. TOML file (specified by SSH_CONFIG_PATH or ~/.codex/ssh-config.toml) + +### .env Format +``` +SSH_SERVER_[NAME]_HOST=hostname +SSH_SERVER_[NAME]_USER=username +SSH_SERVER_[NAME]_PASSWORD=password # For password auth +SSH_SERVER_[NAME]_KEYPATH=~/.ssh/key # For SSH key auth +SSH_SERVER_[NAME]_PASSPHRASE=passphrase # Optional, for passphrase-protected keys +SSH_SERVER_[NAME]_PORT=22 # Optional +SSH_SERVER_[NAME]_DEFAULT_DIR=/path # Optional default working directory +SSH_SERVER_[NAME]_SUDO_PASSWORD=pass # Optional for automated sudo +SSH_SERVER_[NAME]_PLATFORM=windows # Optional: "linux" (default) or "windows" +SSH_SERVER_[NAME]_PROXYJUMP=bastion # Optional: name of another server to use as jump host +SSH_SERVER_[NAME]_PROXYCOMMAND=command # Optional: custom proxy command (ncat, ssh -W, etc.) +``` + +### TOML Format +```toml +[ssh_servers.name] +host = "hostname" +user = "username" +password = "password" # For password auth +key_path = "~/.ssh/key" # For SSH key auth +passphrase = "key_passphrase" # Optional, for passphrase-protected keys +port = 22 # Optional +default_dir = "/path" # Optional default working directory +sudo_password = "pass" # Optional for automated sudo +platform = "windows" # Optional: "linux" (default) or "windows" +proxy_jump = "bastion" # Optional: name of another server to use as jump host +proxy_command = "command" # Optional: custom proxy command (ncat, ssh -W, etc.) +``` + +## Key Implementation Details + +1. **Connection Pooling**: The server maintains persistent SSH connections in a Map to avoid reconnection overhead (src/index.js:31) + +2. **Server Resolution**: Server names are resolved through aliases first, then direct lookup. Names are normalized to lowercase (src/index.js:54-68) + +3. **Default Directories**: If a server has a DEFAULT_DIR configured and no cwd is provided to ssh_execute, commands run in that directory + +4. **Deployment Strategy**: The deploy helper detects permission issues and automatically creates scripts for sudo execution when needed + +5. **Environment Loading**: Uses dotenv to load configuration from `.env` file in project root + +6. **Proxy Command Support**: Custom proxy commands (SOCKS5, ssh -W, etc.) are executed locally to establish connections, with proper error handling and timeout management (src/index.js:389-432) + +## Security Considerations + +- Never commit `.env` files (included in .gitignore) +- SSH keys preferred over passwords +- Sudo passwords stored separately from regular passwords +- Connection errors logged to stderr for debugging +- Pre-commit hooks check for sensitive data leaks + +## Validation and Quality + +Run `./scripts/validate.sh` before commits to check: +- JavaScript syntax validity +- Python syntax validity +- No `.env` file in git +- MCP server startup +- Dependencies installed + +## Claude Code Integration + +To install in Claude Code: +```bash +claude mcp add ssh-manager node /absolute/path/to/mcp-ssh-manager/src/index.js +``` + +Configuration is stored in `~/.config/claude-code/claude_code_config.json` \ No newline at end of file diff --git a/README.md b/README.md index ed0b929..b525dbf 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ This release adds **12 new MCP tools** transforming SSH Manager into a comprehen - **🔗 Multiple SSH Connections** - Manage unlimited SSH servers from a single interface - **🔐 Secure Authentication** - Support for password, SSH key, and ssh-agent authentication (including passphrase-protected keys) - **🔀 ProxyJump / Bastion Host** - Connect to servers behind jump hosts with chained multi-hop support +- **🔌 ProxyCommand / Custom Proxy** - Connect through SOCKS5 proxies or custom proxy commands (ncat, ssh -W, etc.) - **📁 File Operations** - Upload and download files between local and remote systems - **⚡ Command Execution** - Run commands on remote servers with working directory support - **📂 Default Directories** - Set default working directories per server for convenience @@ -568,6 +569,7 @@ SSH_SERVER_[NAME]_DEFAULT_DIR=/path/to/dir # Optional, default working director SSH_SERVER_[NAME]_DESCRIPTION=Description # Optional SSH_SERVER_[NAME]_PLATFORM=windows # Optional: "linux" (default) or "windows" SSH_SERVER_[NAME]_PROXYJUMP=bastion # Optional: name of another server to use as jump host +SSH_SERVER_[NAME]_PROXYCOMMAND=command # Optional: custom proxy command (ncat, ssh -W, etc.) # Example: Linux server SSH_SERVER_PRODUCTION_HOST=prod.example.com @@ -731,6 +733,37 @@ proxy_jump = "bastion" **Chained jumps** are supported: if `bastion` itself has a `proxy_jump`, the chain is followed recursively. Circular references are detected and rejected. +### ProxyCommand / Custom Proxy + +Connect through SOCKS5 proxies or custom proxy commands. The proxy command executes locally and forwards traffic to the remote host. + +```env +# SOCKS5 proxy via ncat +SSH_SERVER_SOCKS_HOST=target.example.com +SSH_SERVER_SOCKS_USER=admin +SSH_SERVER_SOCKS_PROXYCOMMAND="ncat --proxy 127.0.0.1:1080 --proxy-type socks5 %h %p" + +# Windows SSH proxy command +SSH_SERVER_WINPROXY_HOST=internal.example.com +SSH_SERVER_WINPROXY_USER=admin +SSH_SERVER_WINPROXY_PROXYCOMMAND="C:\Windows\System32\OpenSSH\ssh.exe -W %h:%p user@jump-host" +``` + +Or in TOML: +```toml +[ssh_servers.socks] +host = "target.example.com" +user = "admin" +proxy_command = "ncat --proxy 127.0.0.1:1080 --proxy-type socks5 %h %p" + +[ssh_servers.winproxy] +host = "internal.example.com" +user = "admin" +proxy_command = "C:\\Windows\\System32\\OpenSSH\\ssh.exe -W %h:%p user@jump-host" +``` + +The proxy command must be a valid command that reads from stdin and writes to stdout, accepting `%h` and `%p` placeholders for host and port. + ### Documentation - [DEPLOYMENT_GUIDE.md](docs/DEPLOYMENT_GUIDE.md) - Deployment strategies and permission handling - [ALIASES_AND_HOOKS.md](docs/ALIASES_AND_HOOKS.md) - Command aliases and automation hooks diff --git a/package.json b/package.json index 2b370de..2f99f50 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mcp-ssh-manager", - "version": "3.2.2", + "version": "3.3.0", "description": "MCP SSH Manager: Model Context Protocol server for SSH remote server management. Control SSH connections from Claude Code and OpenAI Codex - execute commands, transfer files, database operations, backups, health monitoring, and DevOps automation. NEW: Tool activation system reduces context usage by 92%", "main": "src/index.js", "bin": { diff --git a/src/config-loader.js b/src/config-loader.js index bbb6cb1..53e5223 100644 --- a/src/config-loader.js +++ b/src/config-loader.js @@ -94,6 +94,7 @@ export class ConfigLoader { description: serverConfig.description, platform: serverConfig.platform ? serverConfig.platform.toLowerCase() : undefined, proxyJump: serverConfig.proxy_jump, + proxyCommand: serverConfig.proxy_command || serverConfig.proxycommand, source: 'toml' }); } @@ -143,6 +144,7 @@ export class ConfigLoader { description: env[`SSH_SERVER_${match[1]}_DESCRIPTION`], platform: (env[`SSH_SERVER_${match[1]}_PLATFORM`] || '').toLowerCase() || undefined, proxyJump: env[`SSH_SERVER_${match[1]}_PROXYJUMP`], + proxyCommand: env[`SSH_SERVER_${match[1]}_PROXYCOMMAND`], source: 'env' }; @@ -196,6 +198,7 @@ export class ConfigLoader { if (server.description) serverConfig.description = server.description; if (server.platform) serverConfig.platform = server.platform; if (server.proxyJump) serverConfig.proxy_jump = server.proxyJump; + if (server.proxyCommand) serverConfig.proxy_command = server.proxyCommand; config.ssh_servers[name] = serverConfig; } @@ -225,6 +228,7 @@ export class ConfigLoader { if (server.description) lines.push(`SSH_SERVER_${upperName}_DESCRIPTION="${server.description}"`); if (server.platform) lines.push(`SSH_SERVER_${upperName}_PLATFORM=${server.platform}`); if (server.proxyJump) lines.push(`SSH_SERVER_${upperName}_PROXYJUMP=${server.proxyJump}`); + if (server.proxyCommand) lines.push(`SSH_SERVER_${upperName}_PROXYCOMMAND=${server.proxyCommand}`); lines.push(''); } diff --git a/src/index.js b/src/index.js index 959f0a0..65fcf07 100755 --- a/src/index.js +++ b/src/index.js @@ -385,6 +385,52 @@ function cleanupOldConnections() { } } +// Create a socket from a proxy command (e.g., "ncat --proxy 127.0.0.1:1080 --proxy-type socks5 %h %p") +async function createProxyCommandSocket(proxyCommand, host, port) { + const { spawn } = await import('child_process'); + const { Duplex } = await import('stream'); + + // Replace placeholders + let cmd = proxyCommand.replace(/%h/g, host).replace(/%p/g, port.toString()); + + // Parse command line (simple split, doesn't handle quotes) + const parts = cmd.split(/\s+/); + const program = parts[0]; + const args = parts.slice(1); + + return new Promise((resolve, reject) => { + const child = spawn(program, args, { + stdio: ['pipe', 'pipe', 'pipe'] // stdin, stdout, stderr + }); + + // Create duplex stream from child's stdout (readable) and stdin (writable) + const socket = Duplex.from({ + readable: child.stdout, + writable: child.stdin, + allowHalfOpen: false + }); + + // When socket ends, kill child process + socket.on('close', () => { + if (!child.killed) { + child.kill(); + } + }); + + child.on('error', reject); + child.on('spawn', () => { + resolve(socket); + }); + + // If child exits unexpectedly, destroy socket + child.on('exit', (code) => { + if (code !== 0) { + socket.destroy(new Error(`Proxy command exited with code ${code}`)); + } + }); + }); +} + // Get or create SSH connection with reconnection support async function getConnection(serverName) { const servers = loadServerConfig(); @@ -465,6 +511,14 @@ async function getConnection(serverName) { await ssh.connect({ sock: stream }); jumpDependencies.set(normalizedName, jumpServerName); ssh.jumpConnection = jumpSSH; + } else if (serverConfig.proxyCommand) { + // Create socket via proxy command (e.g., SOCKS5 proxy) + const socket = await createProxyCommandSocket( + serverConfig.proxyCommand, + serverConfig.host, + serverConfig.port || 22 + ); + await ssh.connect({ sock: socket }); } else { await ssh.connect(); } @@ -479,7 +533,7 @@ async function getConnection(serverName) { host: serverConfig.host, port: serverConfig.port, method: serverConfig.password ? 'password' : 'key', - proxyJump: serverConfig.proxyJump || null + proxyJump: serverConfig.proxyJump || null, }); // Execute post-connect hook From 7f91e58068341b22a2b21c9b0eaae02a3a719d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Christillin?= Date: Sat, 18 Apr 2026 21:05:22 +0200 Subject: [PATCH 2/2] fix(proxycommand): normalize CLAUDE.md EOL and harden proxy command parsing - Reconvert CLAUDE.md from CRLF to LF and restore trailing newline so the diff only shows the 4 intentional lines (not the full 212-line rewrite) - Replace naive whitespace split of the proxy command with spawn({ shell: true }), matching OpenSSH ProxyCommand semantics so quoted args, pipes and shell metacharacters work as users expect - Forward proxy stderr to the MCP server's stderr for debugging - Guard resolve/reject against double-settle on exit after successful spawn - Include proxyCommand presence in the connection log --- CLAUDE.md | 432 +++++++++++++++++++++++++-------------------------- src/index.js | 47 +++--- 2 files changed, 242 insertions(+), 237 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e6be724..4f5de9a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,216 +1,216 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -MCP SSH Manager is a Model Context Protocol server that enables Claude Code to manage multiple SSH connections. It provides tools for executing commands, transferring files, and managing deployments across remote servers. - -## Architecture - -The system consists of three main components: - -1. **MCP Server** (`src/index.js`): Node.js-based MCP server using the Model Context Protocol SDK - - Handles SSH connections via node-ssh library - - Manages connection pooling to avoid reconnecting - - Provides MCP tools for Claude Code integration - -2. **Server Management** (`tools/server_manager.py`): Python CLI for configuration - - Manages `.env` file with server configurations - - Tests connections using Paramiko - - Configures Claude Code integration - -3. **Deployment Helpers** (`src/deploy-helper.js`, `src/server-aliases.js`): Advanced features - - Automated deployment strategies with permission handling - - Server alias management for simplified access - - Batch deployment scripts generation - -## Commands - -### Setup and Installation -```bash -npm install # Install Node.js dependencies -./scripts/setup-hooks.sh # Setup pre-commit hooks for development -``` - -### Server Management (Bash CLI) -```bash -ssh-manager server add # Add a new server -ssh-manager server list # List configured servers -ssh-manager server test SERVER # Test connection to specific server -ssh-manager server remove SERVER # Remove a server -ssh-manager server show SERVER # Show server details -``` - -### OpenAI Codex Integration -```bash -ssh-manager codex setup # Configure for Codex -ssh-manager codex migrate # Convert servers to TOML -ssh-manager codex test # Test Codex integration -ssh-manager codex convert to-toml # Convert .env to TOML -ssh-manager codex convert to-env # Convert TOML to .env -``` - -### Tool Management (NEW in v3.1) -```bash -ssh-manager tools list # Show all tools and status -ssh-manager tools configure # Interactive configuration wizard -ssh-manager tools enable # Enable a tool group -ssh-manager tools disable # Disable a tool group -ssh-manager tools reset # Reset to defaults (all tools) -ssh-manager tools export-claude # Export auto-approval config -``` - -**Tool Groups**: core (5), sessions (4), monitoring (6), backup (4), database (4), advanced (14) - -**Modes**: all (37 tools, ~43.5k tokens), minimal (5 tools, ~3.5k tokens), custom (variable) - -See [docs/TOOL_MANAGEMENT.md](docs/TOOL_MANAGEMENT.md) for complete guide. - -### Development and Testing -```bash -npm start # Start MCP server (requires stdin) -./scripts/validate.sh # Run all validation checks -node --check src/index.js # Check JavaScript syntax -python -m py_compile tools/*.py # Check Python syntax -``` - -### Debug Tools (in `debug/` directory) -```bash -./debug/test-claude-code.sh # Test Claude Code integration -node debug/test-mcp.js # Test MCP connection -node debug/test-ssh-command.js # Test SSH command execution -python debug/test_basic.py # Basic Python tests -python debug/test_fastmcp.py # FastMCP integration test -``` - -## MCP Tools Available - -The server exposes these tools to Claude Code and OpenAI Codex: - -### Core Tools -- `ssh_list_servers`: List all configured SSH servers -- `ssh_execute`: Execute commands on remote servers (supports default directories) -- `ssh_upload`: Upload files to remote servers -- `ssh_download`: Download files from remote servers - -### Backup & Restore (v2.1+) -- `ssh_backup_create`: Create database or file backups (MySQL, PostgreSQL, MongoDB, Files) -- `ssh_backup_list`: List all available backups with metadata -- `ssh_backup_restore`: Restore from previous backups -- `ssh_backup_schedule`: Schedule automatic backups using cron - -### Health & Monitoring (v2.2+) -- `ssh_health_check`: Comprehensive server health check (CPU, RAM, Disk, Network) -- `ssh_service_status`: Check status of services (nginx, mysql, docker, etc.) -- `ssh_process_manager`: List, monitor, or kill processes -- `ssh_alert_setup`: Configure health monitoring alerts and thresholds - -### Database Management (v2.3+) -- `ssh_db_dump`: Create database dumps (MySQL, PostgreSQL, MongoDB) -- `ssh_db_import`: Import SQL dumps or restore databases -- `ssh_db_list`: List databases or tables/collections -- `ssh_db_query`: Execute read-only SELECT queries (security validated) - -### Deployment & Management -- `ssh_deploy`: Deploy files with automatic permission/backup handling -- `ssh_execute_sudo`: Execute commands with sudo privileges -- `ssh_alias`: Manage server aliases (add/remove/list) -- `ssh_sync`: Bidirectional file synchronization with rsync -- `ssh_monitor`: System resource monitoring -- `ssh_tail`: Real-time log monitoring - -### Advanced Features -- `ssh_session_*`: Persistent SSH sessions -- `ssh_tunnel_*`: SSH tunnel management (local/remote/SOCKS) -- `ssh_group_*`: Server group operations -- `ssh_command_alias`: Command alias management -- `ssh_hooks`: Automation hooks -- `ssh_profile`: Profile management - -## Server Configuration - -### Configuration Formats - -MCP SSH Manager supports two configuration formats: - -1. **Environment Variables (.env)** - Traditional format for Claude Code -2. **TOML** - Modern format for OpenAI Codex - -### Configuration Loading Priority - -The system loads configurations in this order (highest to lowest priority): -1. Environment variables (process.env) -2. `.env` file in project root -3. TOML file (specified by SSH_CONFIG_PATH or ~/.codex/ssh-config.toml) - -### .env Format -``` -SSH_SERVER_[NAME]_HOST=hostname -SSH_SERVER_[NAME]_USER=username -SSH_SERVER_[NAME]_PASSWORD=password # For password auth -SSH_SERVER_[NAME]_KEYPATH=~/.ssh/key # For SSH key auth -SSH_SERVER_[NAME]_PASSPHRASE=passphrase # Optional, for passphrase-protected keys -SSH_SERVER_[NAME]_PORT=22 # Optional -SSH_SERVER_[NAME]_DEFAULT_DIR=/path # Optional default working directory -SSH_SERVER_[NAME]_SUDO_PASSWORD=pass # Optional for automated sudo -SSH_SERVER_[NAME]_PLATFORM=windows # Optional: "linux" (default) or "windows" -SSH_SERVER_[NAME]_PROXYJUMP=bastion # Optional: name of another server to use as jump host -SSH_SERVER_[NAME]_PROXYCOMMAND=command # Optional: custom proxy command (ncat, ssh -W, etc.) -``` - -### TOML Format -```toml -[ssh_servers.name] -host = "hostname" -user = "username" -password = "password" # For password auth -key_path = "~/.ssh/key" # For SSH key auth -passphrase = "key_passphrase" # Optional, for passphrase-protected keys -port = 22 # Optional -default_dir = "/path" # Optional default working directory -sudo_password = "pass" # Optional for automated sudo -platform = "windows" # Optional: "linux" (default) or "windows" -proxy_jump = "bastion" # Optional: name of another server to use as jump host -proxy_command = "command" # Optional: custom proxy command (ncat, ssh -W, etc.) -``` - -## Key Implementation Details - -1. **Connection Pooling**: The server maintains persistent SSH connections in a Map to avoid reconnection overhead (src/index.js:31) - -2. **Server Resolution**: Server names are resolved through aliases first, then direct lookup. Names are normalized to lowercase (src/index.js:54-68) - -3. **Default Directories**: If a server has a DEFAULT_DIR configured and no cwd is provided to ssh_execute, commands run in that directory - -4. **Deployment Strategy**: The deploy helper detects permission issues and automatically creates scripts for sudo execution when needed - -5. **Environment Loading**: Uses dotenv to load configuration from `.env` file in project root - -6. **Proxy Command Support**: Custom proxy commands (SOCKS5, ssh -W, etc.) are executed locally to establish connections, with proper error handling and timeout management (src/index.js:389-432) - -## Security Considerations - -- Never commit `.env` files (included in .gitignore) -- SSH keys preferred over passwords -- Sudo passwords stored separately from regular passwords -- Connection errors logged to stderr for debugging -- Pre-commit hooks check for sensitive data leaks - -## Validation and Quality - -Run `./scripts/validate.sh` before commits to check: -- JavaScript syntax validity -- Python syntax validity -- No `.env` file in git -- MCP server startup -- Dependencies installed - -## Claude Code Integration - -To install in Claude Code: -```bash -claude mcp add ssh-manager node /absolute/path/to/mcp-ssh-manager/src/index.js -``` - -Configuration is stored in `~/.config/claude-code/claude_code_config.json` \ No newline at end of file +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +MCP SSH Manager is a Model Context Protocol server that enables Claude Code to manage multiple SSH connections. It provides tools for executing commands, transferring files, and managing deployments across remote servers. + +## Architecture + +The system consists of three main components: + +1. **MCP Server** (`src/index.js`): Node.js-based MCP server using the Model Context Protocol SDK + - Handles SSH connections via node-ssh library + - Manages connection pooling to avoid reconnecting + - Provides MCP tools for Claude Code integration + +2. **Server Management** (`tools/server_manager.py`): Python CLI for configuration + - Manages `.env` file with server configurations + - Tests connections using Paramiko + - Configures Claude Code integration + +3. **Deployment Helpers** (`src/deploy-helper.js`, `src/server-aliases.js`): Advanced features + - Automated deployment strategies with permission handling + - Server alias management for simplified access + - Batch deployment scripts generation + +## Commands + +### Setup and Installation +```bash +npm install # Install Node.js dependencies +./scripts/setup-hooks.sh # Setup pre-commit hooks for development +``` + +### Server Management (Bash CLI) +```bash +ssh-manager server add # Add a new server +ssh-manager server list # List configured servers +ssh-manager server test SERVER # Test connection to specific server +ssh-manager server remove SERVER # Remove a server +ssh-manager server show SERVER # Show server details +``` + +### OpenAI Codex Integration +```bash +ssh-manager codex setup # Configure for Codex +ssh-manager codex migrate # Convert servers to TOML +ssh-manager codex test # Test Codex integration +ssh-manager codex convert to-toml # Convert .env to TOML +ssh-manager codex convert to-env # Convert TOML to .env +``` + +### Tool Management (NEW in v3.1) +```bash +ssh-manager tools list # Show all tools and status +ssh-manager tools configure # Interactive configuration wizard +ssh-manager tools enable # Enable a tool group +ssh-manager tools disable # Disable a tool group +ssh-manager tools reset # Reset to defaults (all tools) +ssh-manager tools export-claude # Export auto-approval config +``` + +**Tool Groups**: core (5), sessions (4), monitoring (6), backup (4), database (4), advanced (14) + +**Modes**: all (37 tools, ~43.5k tokens), minimal (5 tools, ~3.5k tokens), custom (variable) + +See [docs/TOOL_MANAGEMENT.md](docs/TOOL_MANAGEMENT.md) for complete guide. + +### Development and Testing +```bash +npm start # Start MCP server (requires stdin) +./scripts/validate.sh # Run all validation checks +node --check src/index.js # Check JavaScript syntax +python -m py_compile tools/*.py # Check Python syntax +``` + +### Debug Tools (in `debug/` directory) +```bash +./debug/test-claude-code.sh # Test Claude Code integration +node debug/test-mcp.js # Test MCP connection +node debug/test-ssh-command.js # Test SSH command execution +python debug/test_basic.py # Basic Python tests +python debug/test_fastmcp.py # FastMCP integration test +``` + +## MCP Tools Available + +The server exposes these tools to Claude Code and OpenAI Codex: + +### Core Tools +- `ssh_list_servers`: List all configured SSH servers +- `ssh_execute`: Execute commands on remote servers (supports default directories) +- `ssh_upload`: Upload files to remote servers +- `ssh_download`: Download files from remote servers + +### Backup & Restore (v2.1+) +- `ssh_backup_create`: Create database or file backups (MySQL, PostgreSQL, MongoDB, Files) +- `ssh_backup_list`: List all available backups with metadata +- `ssh_backup_restore`: Restore from previous backups +- `ssh_backup_schedule`: Schedule automatic backups using cron + +### Health & Monitoring (v2.2+) +- `ssh_health_check`: Comprehensive server health check (CPU, RAM, Disk, Network) +- `ssh_service_status`: Check status of services (nginx, mysql, docker, etc.) +- `ssh_process_manager`: List, monitor, or kill processes +- `ssh_alert_setup`: Configure health monitoring alerts and thresholds + +### Database Management (v2.3+) +- `ssh_db_dump`: Create database dumps (MySQL, PostgreSQL, MongoDB) +- `ssh_db_import`: Import SQL dumps or restore databases +- `ssh_db_list`: List databases or tables/collections +- `ssh_db_query`: Execute read-only SELECT queries (security validated) + +### Deployment & Management +- `ssh_deploy`: Deploy files with automatic permission/backup handling +- `ssh_execute_sudo`: Execute commands with sudo privileges +- `ssh_alias`: Manage server aliases (add/remove/list) +- `ssh_sync`: Bidirectional file synchronization with rsync +- `ssh_monitor`: System resource monitoring +- `ssh_tail`: Real-time log monitoring + +### Advanced Features +- `ssh_session_*`: Persistent SSH sessions +- `ssh_tunnel_*`: SSH tunnel management (local/remote/SOCKS) +- `ssh_group_*`: Server group operations +- `ssh_command_alias`: Command alias management +- `ssh_hooks`: Automation hooks +- `ssh_profile`: Profile management + +## Server Configuration + +### Configuration Formats + +MCP SSH Manager supports two configuration formats: + +1. **Environment Variables (.env)** - Traditional format for Claude Code +2. **TOML** - Modern format for OpenAI Codex + +### Configuration Loading Priority + +The system loads configurations in this order (highest to lowest priority): +1. Environment variables (process.env) +2. `.env` file in project root +3. TOML file (specified by SSH_CONFIG_PATH or ~/.codex/ssh-config.toml) + +### .env Format +``` +SSH_SERVER_[NAME]_HOST=hostname +SSH_SERVER_[NAME]_USER=username +SSH_SERVER_[NAME]_PASSWORD=password # For password auth +SSH_SERVER_[NAME]_KEYPATH=~/.ssh/key # For SSH key auth +SSH_SERVER_[NAME]_PASSPHRASE=passphrase # Optional, for passphrase-protected keys +SSH_SERVER_[NAME]_PORT=22 # Optional +SSH_SERVER_[NAME]_DEFAULT_DIR=/path # Optional default working directory +SSH_SERVER_[NAME]_SUDO_PASSWORD=pass # Optional for automated sudo +SSH_SERVER_[NAME]_PLATFORM=windows # Optional: "linux" (default) or "windows" +SSH_SERVER_[NAME]_PROXYJUMP=bastion # Optional: name of another server to use as jump host +SSH_SERVER_[NAME]_PROXYCOMMAND=command # Optional: custom proxy command (ncat, ssh -W, etc.) +``` + +### TOML Format +```toml +[ssh_servers.name] +host = "hostname" +user = "username" +password = "password" # For password auth +key_path = "~/.ssh/key" # For SSH key auth +passphrase = "key_passphrase" # Optional, for passphrase-protected keys +port = 22 # Optional +default_dir = "/path" # Optional default working directory +sudo_password = "pass" # Optional for automated sudo +platform = "windows" # Optional: "linux" (default) or "windows" +proxy_jump = "bastion" # Optional: name of another server to use as jump host +proxy_command = "command" # Optional: custom proxy command (ncat, ssh -W, etc.) +``` + +## Key Implementation Details + +1. **Connection Pooling**: The server maintains persistent SSH connections in a Map to avoid reconnection overhead (src/index.js:31) + +2. **Server Resolution**: Server names are resolved through aliases first, then direct lookup. Names are normalized to lowercase (src/index.js:54-68) + +3. **Default Directories**: If a server has a DEFAULT_DIR configured and no cwd is provided to ssh_execute, commands run in that directory + +4. **Deployment Strategy**: The deploy helper detects permission issues and automatically creates scripts for sudo execution when needed + +5. **Environment Loading**: Uses dotenv to load configuration from `.env` file in project root + +6. **Proxy Command Support**: Custom proxy commands (SOCKS5, ssh -W, etc.) are executed locally to establish connections, with proper error handling and timeout management (src/index.js:389-432) + +## Security Considerations + +- Never commit `.env` files (included in .gitignore) +- SSH keys preferred over passwords +- Sudo passwords stored separately from regular passwords +- Connection errors logged to stderr for debugging +- Pre-commit hooks check for sensitive data leaks + +## Validation and Quality + +Run `./scripts/validate.sh` before commits to check: +- JavaScript syntax validity +- Python syntax validity +- No `.env` file in git +- MCP server startup +- Dependencies installed + +## Claude Code Integration + +To install in Claude Code: +```bash +claude mcp add ssh-manager node /absolute/path/to/mcp-ssh-manager/src/index.js +``` + +Configuration is stored in `~/.config/claude-code/claude_code_config.json` \ No newline at end of file diff --git a/src/index.js b/src/index.js index 65fcf07..ac0d000 100755 --- a/src/index.js +++ b/src/index.js @@ -386,45 +386,49 @@ function cleanupOldConnections() { } // Create a socket from a proxy command (e.g., "ncat --proxy 127.0.0.1:1080 --proxy-type socks5 %h %p") +// The command is executed through the system shell, matching OpenSSH ProxyCommand semantics, +// so quoted arguments and shell metacharacters work as users expect. async function createProxyCommandSocket(proxyCommand, host, port) { const { spawn } = await import('child_process'); const { Duplex } = await import('stream'); - // Replace placeholders - let cmd = proxyCommand.replace(/%h/g, host).replace(/%p/g, port.toString()); - - // Parse command line (simple split, doesn't handle quotes) - const parts = cmd.split(/\s+/); - const program = parts[0]; - const args = parts.slice(1); + const cmd = proxyCommand.replace(/%h/g, host).replace(/%p/g, port.toString()); return new Promise((resolve, reject) => { - const child = spawn(program, args, { - stdio: ['pipe', 'pipe', 'pipe'] // stdin, stdout, stderr + const child = spawn(cmd, { + shell: true, + stdio: ['pipe', 'pipe', 'pipe'] }); - // Create duplex stream from child's stdout (readable) and stdin (writable) const socket = Duplex.from({ readable: child.stdout, writable: child.stdin, allowHalfOpen: false }); - // When socket ends, kill child process - socket.on('close', () => { - if (!child.killed) { - child.kill(); - } + // Forward proxy stderr to the MCP server's stderr for debugging + child.stderr.on('data', (chunk) => { + process.stderr.write(`[proxy-command] ${chunk}`); }); - child.on('error', reject); - child.on('spawn', () => { - resolve(socket); + let settled = false; + const settle = (fn, arg) => { + if (settled) return; + settled = true; + fn(arg); + }; + + socket.on('close', () => { + if (!child.killed) child.kill(); }); - // If child exits unexpectedly, destroy socket - child.on('exit', (code) => { - if (code !== 0) { + child.on('error', (err) => settle(reject, err)); + child.on('spawn', () => settle(resolve, socket)); + child.on('exit', (code, signal) => { + // Only surface unexpected exits — a kill() after a successful connection is normal. + if (!settled && code !== 0) { + settle(reject, new Error(`Proxy command exited with code ${code}${signal ? ` (${signal})` : ''}`)); + } else if (settled && code !== 0 && !signal && !socket.destroyed) { socket.destroy(new Error(`Proxy command exited with code ${code}`)); } }); @@ -534,6 +538,7 @@ async function getConnection(serverName) { port: serverConfig.port, method: serverConfig.password ? 'password' : 'key', proxyJump: serverConfig.proxyJump || null, + proxyCommand: serverConfig.proxyCommand ? '' : null }); // Execute post-connect hook