$$$$$$\ $$$$$$\ $$\ $$\ $$\ $$\ $$$$$$\ $$$$$$$\
$$ __$$\ $$ __$$\ $$ | $$ |$$$\ $$$ |$$ __$$\ $$ __$$\
$$ / \__|$$ / \__|$$ | $$ |$$$$\ $$$$ |$$ / \__|$$ | $$ |
\$$$$$$\ \$$$$$$\ $$$$$$$$ |$$\$$\$$ $$ |$$ | $$$$$$$ |
\____$$\ \____$$\ $$ __$$ |$$ \$$$ $$ |$$ | $$ ____/
$$\ $$ |$$\ $$ |$$ | $$ |$$ |\$ /$$ |$$ | $$\ $$ |
\$$$$$$ |\$$$$$$ |$$ | $$ |$$ | \_/ $$ |\$$$$$$ |$$ |
\______/ \______/ \__| \__|\__| \__| \______/ \__|
Secure SSH & SFTP Client with MCP Protocol Support
sshx provides a barrier-free SSH command-line client while implementing the MCP (Model Context Protocol) interface, enabling AI assistants to easily invoke remote SSH/SFTP functionality.
Managing multiple servers means juggling different passwords, repeatedly entering sudo passwords, and manually executing SSH commands in AI assistants. sshx securely stores passwords in your system keyring, auto-fills sudo passwords, and enables AI assistants to directly operate remote servers through MCP protocol. One command, multiple servers, zero password hassle.
New! Host Configuration Management - Store your frequently used host configurations in ~/.sshmcp/settings.json and connect with just a name instead of typing full connection details every time. Import from your existing ~/.ssh/config or add hosts interactively!
cmd/sshx: Main binary entry point, responsible for command-line argument parsing, MCP mode startup, and password management features.internal/sshclient: Core SSH/SFTP/script execution logic, command security validation, and connection pool wrapper.internal/mcp: MCP stdio server implementation, exposing SSH/SFTP/script tools to external tools (e.g., AI assistants).
- Cross-platform SSH/SFTP operations (supports sudo auto-fill).
- Password management (Keychain / Secret Service / Credential Manager).
- MCP stdio mode for AI assistant integration.
- Connection pooling, script execution, and command security validation.
If you have Go 1.21+ installed, you can use Go's built-in tools:
# Run the latest version
go run github.com/talkincode/sshmcp/cmd/sshx@latest --help
# Run specific version
go run github.com/talkincode/sshmcp/cmd/sshx@v0.0.6 -h=192.168.1.100 "uptime"# Install latest version to $GOPATH/bin
go install github.com/talkincode/sshmcp/cmd/sshx@latest
# Then use it anywhere
sshx --help
sshx -h=192.168.1.100 "uptime"Note: Make sure $GOPATH/bin (typically ~/go/bin) is in your PATH.
curl -fsSL https://raw.githubusercontent.com/talkincode/sshmcp/main/install.sh | bashOr download and run:
wget https://raw.githubusercontent.com/talkincode/sshmcp/main/install.sh
chmod +x install.sh
./install.shInstall specific version:
./install.sh v0.0.2Open PowerShell as Administrator and run:
irm https://raw.githubusercontent.com/talkincode/sshmcp/main/install.ps1 | iexOr download and run:
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/talkincode/sshmcp/main/install.ps1" -OutFile "install.ps1"
.\install.ps1Install specific version:
.\install.ps1 -Version v0.0.2Download pre-built binaries from Releases:
Linux / macOS:
# Download and extract (replace <platform>-<arch> with your system)
tar -xzf sshx-<platform>-<arch>.tar.gz
# Move to system path
sudo mv sshx /usr/local/bin/
# Make executable
sudo chmod +x /usr/local/bin/sshx
# Verify installation
sshx --helpWindows:
- Download
sshx-windows-amd64.zip - Extract the archive
- Move
sshx.exeto a directory in your PATH (e.g.,C:\Program Files\sshx) - Or add the extracted directory to your system PATH
# Clone repository
git clone https://github.com/talkincode/sshmcp.git
cd sshmcp
# Build command-line tool
go build -o bin/sshx ./cmd/sshx
# Install to system (optional)
make install# Execute remote command
sshx -h=192.168.1.100 -u=root "uptime"
# Save password for easier access (interactive input)
sshx --password-set=root
# Or set password for specific host
sshx --password-set=192.168.1.100-root
# Execute command without password flag (uses saved password)
sshx -h=192.168.1.100 -u=root "df -h"
# Start MCP stdio mode
sshx mcp-stdioNEW! Manage your frequently used hosts in ~/.sshmcp/settings.json for quick access.
# Import hosts from your existing ~/.ssh/config
sshx --host-import
# Or add hosts interactively
sshx --host-add
# Add host with command line options
sshx --host-add --host-name=prod-web -h=192.168.1.100 -u=root --host-desc="Production Web Server"
# List all configured hosts
sshx --host-list
# Test connection to a configured host
sshx --host-test=prod-web
# Use configured host (auto-resolves from settings)
sshx -h=prod-web "systemctl status nginx"
# Test every configured host and show auth methods
sshx --host-test-allLocation: ~/.sshmcp/settings.json
{
"key": "/Users/username/.ssh/id_rsa",
"hosts": [
{
"name": "prod-web",
"description": "Production Web Server",
"host": "192.168.1.100",
"port": "22",
"user": "root",
"password_key": "prod-web-password",
"type": "linux"
}
]
}--host-add- Add new host (interactive or with options)--host-import- Import hosts from~/.ssh/config--host-list- List all configured hosts--host-test=<name>- Test connection to a host--host-test-all- Test connections to all hosts (per-host 10s dial timeout) and show auth method used--host-remove=<name>- Remove a host from configuration
Benefits:
- 📝 Store connection details once, use everywhere
- 🚀 Connect with just a name:
sshx -h=prod-web "command" - 🔄 Import from existing
~/.ssh/config - 🔐 Integrate with password manager for each host
- ✅ Test connections before use
sshx provides secure password storage using the operating system's native credential manager, eliminating the need to enter passwords repeatedly or store them in plaintext.
- macOS: Uses Keychain Access
- Linux: Uses Secret Service (GNOME Keyring / KDE Wallet)
- Windows: Uses Credential Manager
# Save default sudo password (interactive input, recommended)
sshx --password-set=master
# Save password for specific user
sshx --password-set=root
# Save password for specific host+user combination
sshx --password-set=192.168.1.100-root
# Set password inline (not recommended, insecure)
sshx --password-set=master:yourpasswordYou will be prompted to enter the password securely (input is hidden).
# Check if password exists
sshx --password-check=master
sshx --password-check=root
# Output example:
# ✓ Password exists for key: master# List common password keys
sshx --password-list
# Output example:
# Checking password keys in system keyring...
# Service: sshx
#
# Common keys:
# ✓ master (exists)
# ✓ root (exists)
# sudo (not set)# Get stored password (for debugging)
sshx --password-get=master
# Output example:
# ✓ Password retrieved from system keyring
# Service: sshx
# Key: master
#
# Password: yourpassword# Delete password
sshx --password-delete=master
sshx --password-delete=root
# Confirmation message:
# ✓ Password deleted from system keyring
# Service: sshx
# Key: masterOnce a password is saved, sudo commands will automatically retrieve the password from system keyring:
# 1. First save sudo password
sshx --password-set=master
# 2. Execute sudo commands (automatically uses stored password)
sshx -h=192.168.1.100 -u=root "sudo systemctl status nginx"
sshx -h=192.168.1.100 -u=root "sudo reboot"
# 3. Multi-server scenario: save different passwords for different servers
sshx --password-set=server-A
sshx --password-set=server-B
sshx --password-set=server-C
# 4. Use -pk parameter to specify sudo password key temporarily
sshx -h=192.168.1.100 -pk=server-A "sudo systemctl restart nginx"
sshx -h=192.168.1.101 -pk=server-B "sudo systemctl restart nginx"
sshx -h=192.168.1.102 -pk=server-C "sudo systemctl restart nginx"sshx now enforces strict host key verification just like the OpenSSH client. Instead of silently trusting unknown hosts, the tool reads the trust store from ~/.ssh/known_hosts (or the path you provide) and aborts the connection if the host is missing or the key changes.
Ways to manage host keys:
- Add hosts manually (recommended):
ssh-keyscan -H <host> >> ~/.ssh/known_hosts - One-time automatic trust:
sshx --accept-unknown-host -h=<host> ...(or setSSH_ACCEPT_UNKNOWN_HOST=1). The first connection records the key; subsequent runs stay strict. - Custom trust store:
sshx --known-hosts=/path/to/known_hostsorSSH_KNOWN_HOSTS=/path/to/known_hosts. - Legacy insecure mode (last resort):
sshx --insecure-hostkey ...orSSH_INSECURE_HOST_KEY=1. This re-enables the previousInsecureIgnoreHostKeybehavior and should only be used in controlled environments.
If the host key ever changes, sshx clearly explains how to remove the old entry before re-connecting, protecting you from potential man-in-the-middle attacks.
- master: Default sudo password key name, used for sudo commands
- root: Password for root user
- Custom keys: You can use any key name, e.g.,
server-A,server-B,prod-db, etc.
If you manage multiple servers with the same username but different passwords, use this strategy:
# Scenario: Manage 3 servers, all with root user but different passwords
# 1. Save password for each server (use meaningful key names)
sshx --password-set=prod-web # Production web server
sshx --password-set=prod-db # Production database server
sshx --password-set=dev-server # Development server
# 2. Execute commands using -pk parameter to specify password key
sshx -h=192.168.1.10 -u=root -pk=prod-web "sudo systemctl status nginx"
sshx -h=192.168.1.20 -u=root -pk=prod-db "sudo systemctl status mysql"
sshx -h=192.168.1.30 -u=root -pk=dev-server "sudo docker ps"
# 3. You can also use aliases to simplify commands (add to ~/.zshrc or ~/.bashrc)
alias ssh-prod-web='sshx -h=192.168.1.10 -u=root -pk=prod-web'
alias ssh-prod-db='sshx -h=192.168.1.20 -u=root -pk=prod-db'
alias ssh-dev='sshx -h=192.168.1.30 -u=root -pk=dev-server'
# Then use simply:
ssh-prod-web "sudo systemctl restart nginx"
ssh-prod-db "sudo systemctl restart mysql"
ssh-dev "sudo docker-compose up -d"You can customize the sudo password key name via environment variable (but using -pk parameter is more flexible):
# Use environment variable (can only specify one at a time, needs constant modification)
export SSH_SUDO_KEY=my-sudo-password
sshx --password-set=my-sudo-password
sshx -h=192.168.1.100 "sudo ls -la /root"
# Recommended: Use -pk parameter, more flexible, no need to modify environment variables
sshx -h=192.168.1.100 -pk=server-A "sudo ls -la /root"
sshx -h=192.168.1.101 -pk=server-B "sudo ls -la /root"- ✅ Passwords are stored using OS-native encryption
- ✅ Passwords are never stored in plaintext
- ✅ Each host+user combination has a separate password entry
- ✅ Password input is hidden during entry
⚠️ Requires OS credential manager to be available⚠️ On Linux, requires Secret Service daemon running (usually automatic with desktop environments)
You can use environment variables to avoid typing credentials repeatedly:
# Set in .env file or export in shell
export SSH_HOST=192.168.1.100
export SSH_USER=root
export SSH_PORT=22
export SUDO_PASSWORD=your_sudo_password
# Then run commands without flags
./bin/sshx "uptime"sshxnow prioritizes SSH keys and automatically falls back to password authentication when the server rejects your key (for example when a host only allows passwords). As long as a password is available, the client will transparently retry with a password-only session.- Use
--no-key(alias--password-only) to disable key authentication for a single command. You can re-enable it by supplying--key=<path>again. - Set
SSH_DISABLE_KEY=truein your environment to permanently disable key authentication (useful on hosts that never accept keys). This override is respected even if a default key path exists in~/.sshmcp/settings.json. - When key auth is enabled and no explicit path is provided,
sshxstill auto-loads~/.ssh/id_rsa(or the path specified in settings) before falling back to passwords.
You can control the logging verbosity using the SSHX_LOG_LEVEL environment variable:
# Set log level to DEBUG (shows detailed debugging information, including MCP requests/responses)
export SSHX_LOG_LEVEL=debug
# Set log level to INFO (default)
export SSHX_LOG_LEVEL=info
# Set log level to WARNING
export SSHX_LOG_LEVEL=warning
# Set log level to ERROR
export SSHX_LOG_LEVEL=errorDebug Logging in MCP Mode:
In MCP stdio mode, to avoid interfering with JSON-RPC communication, logs are written to a file instead of stdout. There are two ways to enable DEBUG level:
Method 1: Using --debug flag (Recommended)
# Start MCP server with --debug flag
sshx mcp-stdio --debug
# Log file location: ~/.sshmcp/sshx.log
# You can monitor logs in real-time
tail -f ~/.sshmcp/sshx.logMethod 2: Using environment variable
# Set environment variable to enable debug logging
export SSHX_LOG_LEVEL=debug
sshx mcp-stdio
# Log file location: ~/.sshmcp/sshx.log
# You can monitor logs in real-time
tail -f ~/.sshmcp/sshx.logNote: The --debug flag takes precedence over the environment variable.
Debug level logs include:
- All MCP requests received (JSON format)
- All MCP responses sent (JSON format)
- Detailed parameters and results of tool calls
- Detailed SSH/SFTP operation processes
# 1. Save sudo password (interactive input)
sshx --password-set=master
# Enter password for key 'master': ******
# 2. Verify it's saved
sshx --password-check=master
# ✓ Password exists for key: master
# 3. Use for SSH commands (sudo automatically uses stored password)
sshx -h=192.168.1.100 -u=root "sudo systemctl status docker"
sshx -h=192.168.1.100 -u=root "sudo df -h"
# 4. Use for SFTP operations
sshx -h=192.168.1.100 -u=root --upload=local.txt --to=/tmp/remote.txt
sshx -h=192.168.1.100 -u=root --download=/etc/hosts --to=./hosts.txt
# 5. List all saved password keys
sshx --password-list
# Common keys:
# ✓ master (exists)
# root (not set)
# 6. When done, optionally delete the password
sshx --password-delete=master
# ✓ Password deleted from system keyringSolution:
- Ensure
/usr/local/bin(or your installation directory) is in your PATH - Restart your terminal after installation
- Or run with full path:
/usr/local/bin/sshx
macOS may block the binary on first run:
sudo xattr -rd com.apple.quarantine /usr/local/bin/sshxOr go to System Preferences → Security & Privacy → Click "Allow Anyway"
Click "More info" and then "Run anyway" if Windows Defender SmartScreen shows a warning.
# Make sure the binary has execute permissions
sudo chmod +x /usr/local/bin/sshx# Run tests
go test ./...
# Format code
gofmt -w .
# Build for all platforms
make build-all
# Run linter
make lintThe lint target requires
golangci-lintv2.6.1 or newer. Install it withgo install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.6.1.
This project is licensed under the MIT License - see the LICENSE file for details.
Documentation • Issues • Discussions • Releases
Made with ❤️ by talkincode