Install
$ agentstack add mcp-uarlouski-ssh-mcp-server Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Destructive filesystem operation.
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
SSH MCP Server for AI Assistants - Secure Remote Server Management
A secure, production-ready Model Context Protocol (MCP) server that empowers AI assistants to manage remote infrastructure via SSH.
[](https://www.npmjs.com/package/@uarlouski/ssh-mcp-server) [](https://www.npmjs.com/package/@uarlouski/ssh-mcp-server) [](https://github.com/uarlouski/ssh-mcp-server/actions/workflows/ci.yml) [](https://opensource.org/licenses/Apache-2.0) [](https://nodejs.org) [](https://www.typescriptlang.org/) [](https://github.com/uarlouski/ssh-mcp-server)
The SSH MCP Server bridges the gap between Large Language Models (LLMs) and your infrastructure. It enables AI assistants like Claude Desktop, Cursor, and GitHub Copilot to securely execute commands, transfer files via SFTP, and manage port forwarding tunnels. Turn your AI into a capable DevOps assistant that can troubleshoot, deploy, and monitor your servers with strict security boundaries.
Table of Contents
- [Why use SSH MCP Server?](#why-use-ssh-mcp-server)
- [Compatibility](#compatibility)
- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
- [Available Tools](#available-tools)
- [Security](#security)
- [Examples](#examples)
- [License](#license)
Why use SSH MCP Server?
- DevOps Automation: Let your AI assistant check Docker container status, read Kubernetes pod logs, or restart systemd services.
- Infrastructure Debugging: Quickly analyze log files, check disk usage, and investigate network issues using natural language.
- Secure File Management: Safely read configuration files, update scripts, or retrieve logs via SFTP without leaving your chat interface.
- Complex Workflows: Chain multiple commands and tools to perform complex maintenance tasks with a single prompt.
Compatibility
This MCP server is designed to work with any client supporting the Model Context Protocol, including:
- Anthropic Claude Desktop
- Cursor Editor
- GitHub Copilot
Features
- 🔐 Secure SSH Command Execution - Run shell commands on remote servers with strict validation and timeouts.
- 🛡️ Granular Access Control - Whitelist specific commands and arguments to prevent unauthorized actions (e.g., allow
docker psbut blockdocker stop). - 📁 SFTP Integration - Full support for reading, writing, and listing files on remote filesystems.
- 🌉 Smart Port Forwarding - Automatically manage SSH tunnels to access internal services like databases or dashboards.
- 🔄 Robust Connection Pooling - Efficiently manages multiple persistent SSH connections for high performance.
- 🔑 Key-Based Authentication - Supports standard SSH keys (Ed25519, RSA) for secure, password-less authentication.
- ⚙️ SSH Config Import - Seamlessly imports hosts from your existing
~/.ssh/configfile. - 🎯 Parameterized Templates - Define safe, reusable command templates (macros) for common tasks.
- 📝 Audit Logging - Complete JSONL audit trails of all executed commands for compliance and security reviews.
Installation
As an MCP Server
The recommended way to use this package is as an MCP server with AI assistants like GitHub Copilot.
Prerequisites:
- Node.js 18.0.0 or higher
- SSH access to target servers
- SSH private keys configured
Using npx (recommended):
No installation required! Add to your MCP client configuration:
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": [
"@uarlouski/ssh-mcp-server@latest",
"--configPath=/path/to/your/ssh-mcp-config.json"
]
}
}
}
Global installation:
npm install -g @uarlouski/ssh-mcp-server
Then configure with:
{
"mcpServers": {
"ssh": {
"command": "ssh-mcp-server",
"args": ["--configPath=/path/to/your/ssh-mcp-config.json"]
}
}
}
Quick Start
1. Create SSH Keys
If you don't already have SSH keys for your servers:
ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -C "deploy@example.com"
ssh-copy-id -i ~/.ssh/deploy_key.pub user@your-server.com
2. Create Configuration File
Create a ssh-mcp-config.json file:
{
"allowedCommands": ["ls", "cat", "grep", "docker", "kubectl"],
"servers": {
"my-server": {
"host": "example.com",
"username": "deploy",
"privateKeyPath": "~/.ssh/deploy_key"
}
}
}
3. Configure Your MCP Client
Add the server to your MCP client (e.g., GitHub Copilot):
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": [
"@uarlouski/ssh-mcp-server@latest",
"--configPath=/Users/yourname/ssh-mcp-config.json"
]
}
}
}
4. Restart Your MCP Client
Restart your AI assistant to load the new server configuration.
Configuration
Basic Configuration
The configuration file supports the following options:
{
"allowedCommands": ["ls", "pwd", "cat", "grep", "docker", "kubectl"],
"servers": {
"server-name": {
"host": "hostname-or-ip",
"port": 22,
"username": "username",
"privateKeyPath": "~/.ssh/private_key"
}
},
"portForwardingServices": {
"service-name": {
"connectionName": "server-name",
"localPort": 8080,
"remoteHost": "localhost",
"remotePort": 80,
"description": "Optional description"
}
},
"commandTemplates": {
"k8s-pod-logs": {
"command": "kubectl logs -n {{namespace}} {{pod}} --tail={{lines:100}}",
"description": "Fetch Kubernetes pod logs with configurable tail size"
},
"app-deploy": {
"command": "cd /var/www/{{app}} && git pull origin {{branch:main}} && npm install && pm2 restart {{app}}",
"description": "Deploy application with git pull, npm install, and pm2 restart"
},
"docker-stats": "docker stats {{container:--all}} --no-stream --format 'table {{.Name}}\\t{{.CPUPerc}}'"
},
"commandTimeout": 30000,
"maxConnections": 10
}
Configuration Options
allowedCommands (optional)
Array of base command names that are permitted for execution.
- If specified (non-empty): Enables strict validation
- Only listed commands can be executed
- Validates complex commands including pipes (
|), chains (&&,||,;), and substitutions ($()) - Blocks bypass attempts like
ls | rm -rf / - If omitted or empty: Disables validation (all commands allowed - use with caution!)
Example:
"allowedCommands": ["ls", "cat", "grep", "docker", "kubectl", "systemctl"]
servers (required)
Named SSH server configurations. Each server must have:
host(required): Hostname or IP addressusername(required): SSH usernameprivateKeyPath(required): Path to SSH private key (supports~expansion)port(optional): SSH port (default: 22)
Example:
"servers": {
"staging-api": {
"host": "api-staging-01.example.com",
"username": "deploy",
"privateKeyPath": "~/.ssh/staging_deploy_key"
},
"staging-db": {
"host": "db-staging-master.example.com",
"port": 2222,
"username": "dbadmin",
"privateKeyPath": "~/.ssh/db_admin_key"
}
}
sshConfigImport (optional)
Import server configurations from your existing SSH config file (e.g. ~/.ssh/config). This feature allows you to reuse your existing SSH configurations without duplicating them in the MCP config file.
Benefits:
- 🔄 Reuse existing SSH configurations
- 🎯 Import specific hosts using pattern matching
- 🔒 Works cross-platform (macOS, Linux, Windows)
Configuration:
path(string, optional): Path to SSH config file (default:~/.ssh/config)hosts(array of strings, optional): Host patterns to import (e.g.,["prod-*", "staging-*"])- Supports wildcards:
*(matches any characters),?(matches single character) - If omitted, imports all valid hosts (excluding wildcard-only hosts like
*)
Note: Simply defining sshConfigImport in your config enables SSH config import. To disable it, remove the sshConfigImport field entirely.
Example - Import specific hosts with pattern matching:
{
"sshConfigImport": {
"path": "/custom/path/to/ssh_config",
"hosts": ["prod-*", "staging-*"]
}
}
Notes:
- Only hosts with all required fields (
HostName,User,IdentityFile) are imported - Wildcard SSH config entries (
Host *) apply their settings to specific hosts but aren't imported as standalone servers - If the SSH config file doesn't exist, the server continues with manually defined servers
- Important: If a server name exists in both manual configuration and SSH config import, the server will fail to start with a clear error message. Use the
hostspattern filter to avoid conflicts, or rename servers in one of the configurations.
portForwardingServices (optional)
Pre-configured named port forwarding services for common use cases.
connectionName(required): Name of the server fromserversconfigremoteHost(required): Remote host to forward toremotePort(required): Remote port to forward tolocalPort(optional): Local port to bind to (random if omitted)description(optional): Human-readable description
Example:
"portForwardingServices": {
"pg-staging-database": {
"connectionName": "staging-db",
"remoteHost": "db-internal-01.example.com",
"remotePort": 5432,
"description": "PostgreSQL database access"
}
}
commandTemplates (optional)
Reusable parameterized command templates with variable substitution.
Templates can be defined in two formats:
- String format:
"template-name": "command with {{variables}}" - Object format:
"template-name": { "command": "...", "description": "..." }
Variable syntax:
{{variable}}- Required variable{{variable:default}}- Optional variable with default value{{.field}}- Preserved for Docker/Go templates (not substituted)
Example:
"commandTemplates": {
"k8s-pod-logs": {
"command": "kubectl logs -n {{namespace}} {{pod}} --tail={{lines:100}}",
"description": "Fetch Kubernetes pod logs with configurable tail size"
},
"app-deploy": {
"command": "cd /var/www/{{app}} && git pull origin {{branch:main}} && npm install && pm2 restart {{app}}",
"description": "Deploy application"
},
"docker-stats": "docker stats {{container:--all}} --no-stream --format 'table {{.Name}}\\t{{.CPUPerc}}'",
"nginx-reload": "sudo nginx -t && sudo systemctl reload nginx"
}
Usage with AI:
"Get logs from the api-7d8f9 pod in the staging namespace"
The AI will recognize this matches the k8s-pod-logs template and execute it with the appropriate variables.
commandTimeout (optional)
Command execution timeout in milliseconds. Default: 30000 (30 seconds).
maxConnections (optional)
Maximum number of concurrent SSH connections. Default: 5.
auditLog (optional)
Configure audit logging for SSH sessions.
enabled(boolean, optional): Enable audit logging (default: false)folder(string, optional): Path to store audit logs (defaults to current directory)
Example:
"auditLog": {
"enabled": true,
"folder": "~/ssh-audit-logs"
}
Complete Example
See [config.example.json](config.example.json) for a complete configuration example.
Available Tools
ssh_execute_command
Execute commands on remote servers.
Parameters:
connectionName(string, required): Name of the server from your configcommand(string, required): Command to executecommandTimeout(number, optional): Command execution timeout in milliseconds (overrides globalcommandTimeout)
Example:
{
"connectionName": "staging-api",
"command": "docker ps -a"
}
Response:
{
"stdout": "CONTAINER ID IMAGE COMMAND ...",
"stderr": "",
"exitCode": 0,
"timedOut": false
}
ssh_list_servers
List all available SSH servers configured in your config file.
Parameters: None
Example:
{}
Response:
{
"success": true,
"servers": [
{
"name": "production-api",
"host": "api-prod-01.example.com",
"port": 22,
"username": "deploy"
},
{
"name": "staging-db",
"host": "db-staging.example.com",
"port": 2222,
"username": "admin"
}
],
"count": 2
}
This tool helps AI assistants discover what servers are available for SSH operations without needing to see the full configuration file.
ssh_port_forward
Set up SSH port forwarding to access remote services.
Parameters:
connectionName(string, required): Name of the server from your configremoteHost(string, required): Remote host to forward toremotePort(number, required): Remote port to forward tolocalPort(number, optional): Local port to bind to (random if omitted)
Example with specific local port:
{
"connectionName": "staging-db",
"localPort": 8080,
"remoteHost": "internal-db.cluster.local",
"remotePort": 5432
}
Example with automatic port assignment:
{
"connectionName": "staging-db",
"remoteHost": "internal-db.cluster.local",
"remotePort": 5432
}
Response:
{
"id": "a1b2c3d4",
"localPort": 8080,
"remoteHost": "internal-db.cluster.local",
"remotePort": 5432,
"status": "active"
}
ssh_close_port_forward
Close an active port forward.
Parameters:
id(string, required): Unique ID of the active port forward to close
Example:
{
"id": "a1b2c3d4"
}
ssh_restart_port_forward
Restart an active port forward using its unique ID.
Parameters:
id(string, required): Unique ID of the active port forward to restart
Example:
{
"id": "a1b2c3d4"
}
ssh_list_port_forwards
List all active port forwards across all connections.
Parameters: None
Response:
{
"forwards": [
{
"id": "a1b2c3d4",
"sshConnection": "admin@db-staging.example.com:2222",
"tunnel": "localhost:8080 -> internal-db.cluster.local:5432",
"status": "active"
}
]
}
ssh_port_forward_service
Start a pre-configured named port forwarding service from your config.
Parameters:
serviceName(string, required): Name of the service fromportForwardingServicesconfig
Example:
{
"serviceName": "pg-staging-database"
}
This is equivalent to calling ssh_port_forward with the pre-configured parameters (the returned result will include the generated unique id).
ssh_upload_file
Upload a file from local system to remote server via SFTP.
Parameters:
connectionName(string, required): Name of the server from your configlocalPath(string, required): Local file path to uploadremotePath(string, required): Remote destination pathpermissions(string, optional): File permissions in octal format (e.g., "0644", "0755")
Example:
{
"connectionName": "app-server",
"localPath": "~/configs/app.json",
"remotePath": "/var/www/app/config.json",
"permissions": "0644"
}
Response:
{
"success": true,
"bytesTransferred": 1024,
"message": "Successfully uploaded ~/configs/app.json to /var/www/app/config.json",
"localPath": "~/configs/app.json",
"remotePath": "/var/www/app/config.json"
}
ssh_download_file
Download a file from remote server to local system via SFTP.
Parameters:
connectionName(string, required): Name of the server from your configremotePath(string, required): Remote file path to downloadlocalPath(string, required): Local destination path
Example:
{
"connectionName": "app-server",
"remotePath": "/var/log/app/error.log",
"localPath": "~/downloads/error.log"
}
**Respon
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: uarlouski
- Source: uarlouski/ssh-mcp-server
- License: Apache-2.0
- Homepage: https://www.npmjs.com/package/@uarlouski/ssh-mcp-server
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.