-
Notifications
You must be signed in to change notification settings - Fork 0
Skills SSH MCP Dev
name: "ssh-mcp-dev" description: "SSH MCP server development guide. Invoke when working on ssh-licco project, including setup, debugging, version management, Docker deployment, and releases."
- Project Name: ssh-licco
- Description: SSH Model Context Protocol Server - Enable SSH functionality for AI models
- Repository: https://github.com/Echoqili/ssh-licco
-
Current Version: 2.6.0 (stored in
ssh_mcp/__init__.py) - Python: >=3.10, <3.14
- License: MIT
ssh-mcp/
├── ssh_mcp/ # Main source code
│ ├── __init__.py # Version info (main version file)
│ ├── server.py # MCP server implementation (SSHMCPServer)
│ ├── service.py # SSH service protocol & connection info
│ ├── config_manager.py # Config file management (hosts.json)
│ ├── session_manager.py # SSH session lifecycle management
│ ├── connection_config.py # Pydantic connection config model
│ ├── connection_pool.py # Connection pool with health check
│ ├── executor.py # Thread pool executor (async bridge)
│ ├── batch_executor.py # Batch command execution across hosts
│ ├── key_manager.py # SSH key pair generation (RSA/Ed25519)
│ ├── security.py # Multi-level security (command/path validation)
│ ├── audit_logger.py # Structured audit logging
│ ├── logging_config.py # Centralized logging (SSHLogger singleton)
│ ├── watchdog.py # Task monitoring & health check
│ ├── exceptions.py # Custom exception hierarchy
│ ├── cli.py # Python entry point (simplified to only start server)
│ └── clients/ # SSH client implementations
│ ├── __init__.py # Exports: SSHClientInterface, ClientType, etc.
│ ├── interface.py # Abstract base class + data models
│ ├── factory.py # Client factory with registration
│ ├── paramiko_client.py # Paramiko implementation
│ └── additional_clients.py # AsyncSSH/Fabric/SSH2 (optional)
├── ssh-licco.js # Node.js wrapper - auto-install + integrity check + startup
├── install.js # npm postinstall script - incremental install
├── smart_install.py # Standalone diagnostic installer with SSH test
├── config/ # Runtime configuration
│ ├── hosts.json # SSH host configurations
│ ├── mcp.user.config.json.example
│ ├── mcp.presets.json
│ └── ssh-hosts.example.json
├── .github/workflows/
│ ├── pypi.yml # PyPI release workflow
│ └── mcp-registry.yml # MCP Registry publish workflow
├── openspec/ # OpenSpec specifications
│ └── specs/ # Feature specs
├── docs/ # Documentation
│ ├── API_REFERENCE.md
│ ├── CONTRIBUTING.md
│ └── skills/ # Skill documentation copies
├── pyproject.toml # Package configuration
├── sync_version.py # Version sync script
├── Dockerfile # Docker image build (multi-stage)
└── .trae/skills/ # Trae IDE skills
The npx auto-install uses a three-layer architecture:
User → npx ssh-licco
↓
┌──── ssh-licco.js (Node Layer) ────┐
│ ① Find Python 3.10+ │
│ ② Detect Anaconda environment │
│ ③ Create/reuse ~/.ssh-licco-venv │
│ ④ pip install dependencies │
│ ⑤ Verify dependency integrity │
└──────────┬────────────────────────┘
↓
┌── cli.py (Python Entry) ──────┐
│ Only starts MCP server │
└──────────┬────────────────────┘
↓
┌── SSHMCPServer (MCP Service) ─┐
│ SSH connect, execute, etc. │
└───────────────────────────────┘
-
Node.js wrapper (
ssh-licco.js) handles all environment prep - Python finding, venv creation, dependency installation, integrity verification. This ensures the Python layer can focus purely on MCP logic. -
Incremental install (
install.js) - The postinstall script checksvenvHasInstallation()first. If the venv already has valid dependencies, it skips deletion and does incrementalpip install -e .. This makes re-installs nearly instant. -
cli.py is stripped down - No duplicate install logic. Only 17 lines: imports
run_server()and calls it. -
Dependency integrity check - Every startup verifies
from ssh_mcp.server import SSHMCPServer; from ssh_mcp.session_manager import SessionManagerworks. If not, auto-repairs. -
Anaconda detection - Both
ssh-licco.jsandinstall.jsdetect Anaconda/Miniconda Python and log a warning, ensuring users know their conda environment won't be touched.
| Feature | Description |
|---|---|
| Anaconda Auto-Detect | Detects conda environment, uses isolated venv |
| Dependency Integrity Check | Verifies on startup, auto-repairs if missing |
| Incremental Update | Doesn't delete venv, pip install -e . only |
| Auto-Repair | Re-installs when deps corrupted |
git checkout master
git pull github master
git checkout -b feature/your-feature-name| Type | Example | Use Case |
|---|---|---|
feat/ |
feat/add-server-management |
New features |
fix/ |
fix/password-display-issue |
Bug fixes |
docs/ |
docs/update-readme |
Documentation |
refactor/ |
refactor/improve-code |
Code improvements |
<type>: <description>
Types: feat, fix, docs, refactor, chore, test, style
pip install -e .
python -m pytest
python -m build
python -m twine upload dist/* -u __token__ -p <TOKEN>
python -c "from ssh_mcp import __version__; print(__version__)"python sync_version.py 0.5.6-
ssh_mcp/__init__.py- Main version file -
pyproject.toml- Auto-synced -
VERSION- Backup
- Update version:
python sync_version.py x.x.x - Build:
python -m build - Upload:
python -m twine upload dist/* - Create GitHub Release:
git tag vx.x.x && git push origin vx.x.x
| Tool | Description |
|---|---|
ssh_connect |
Connect to SSH server (auto-reads env vars, saved config, or explicit params). Supports password/key/agent auth, optional save_config, and optional post-connect command. |
ssh_execute |
Execute commands on remote server. Auto-connects if no session_id. Auto-detects background execution for long-running tasks. Supports background, wait, workdir, log_file, wait_timeout params. |
ssh_disconnect |
Close a session (with session_id) or list all active sessions (without session_id). |
ssh_file_transfer |
Upload/download/list/write/append/delete/mkdir/stat files via SFTP. v2.1.3+ delete validates Windows/Unix paths and blocks sensitive paths / traversal. |
ssh_host |
Manage server configs: action=list (view all), action=add (register new), action=remove (delete). |
ssh_docker |
Docker management: action=ps (list containers), action=images (list images), action=build (build image in background), action=logs (view container logs). |
ssh_generate_key |
Generate SSH key pair (RSA/Ed25519). |
| Level | Env Value | Use Case |
|---|---|---|
| Strict | SSH_SECURITY_LEVEL=strict |
Production (whitelist only) |
| Balanced | SSH_SECURITY_LEVEL=balanced |
Default |
| Relaxed | SSH_SECURITY_LEVEL=relaxed |
Development/testing |
-
CommandValidator (
security.py): Whitelist-based command validation -
PathValidator (
security.py): Path traversal prevention - Rate Limiting: Sliding window algorithm (configurable)
- Audit Logging: Structured event logging (connect/disconnect/command/file transfer)
| Variable | Default | Description |
|---|---|---|
SSH_SECURITY_LEVEL |
balanced | Security level (strict/balanced/relaxed) |
SSH_EXTRA_ALLOWED_COMMANDS |
- | Additional allowed commands |
SSH_RATE_LIMIT |
true | Enable rate limiting (bool: true/false) |
SSH_RATE_LIMIT_MAX |
30 | Max requests per window |
SSH_RATE_LIMIT_WINDOW |
60 | Time window in seconds |
SSH_AUDIT_LOG_PATH |
- | Audit log file path |
Supported types (via SSHClientFactory):
-
paramiko- Pure Python, stable, registered by default -
asyncssh- Async high performance (optional) -
fabric- High-level API (optional) -
ssh2- C extension (optional)
Default client type in ConnectionConfig: asyncssh
Default mode (user params highest):
- User parameters (args) - Highest
- hosts.json (by name) - Medium
- MCP environment variables - Lowest (fallback)
Force env mode (SSH_FORCE_ENV_CONFIG=true):
- MCP environment variables - Highest
- User parameters - Fallback
{
"mcpServers": {
"ssh": {
"command": "ssh-licco",
"env": {
"SSH_HOST": "192.168.1.100",
"SSH_USER": "root",
"SSH_PASSWORD": "your_password",
"SSH_PORT": "22",
"SSH_TIMEOUT": "60",
"SSH_KEEPALIVE_INTERVAL": "30",
"SSH_SESSION_TIMEOUT": "7200",
"SSH_CLIENT_TYPE": "asyncssh",
"SSH_SECURITY_LEVEL": "balanced",
"SSH_RATE_LIMIT": "true"
}
}
}
}| Module | Purpose |
|---|---|
ssh-licco.js |
Node.js wrapper - auto-install, Anaconda detection, integrity check |
install.js |
npm postinstall - incremental venv install |
cli.py |
Python entry - simplified startup only |
server.py |
MCP server (SSHMCPServer) - tool registration & dispatch |
service.py |
SSH service protocol, ClientType enum, HealthCheckResult |
session_manager.py |
Session lifecycle (create/close/list), SessionInfo, SessionState |
connection_config.py |
Pydantic model with validation (port, timeout, auth) |
connection_pool.py |
PooledConnection, PoolConfig, health monitoring |
executor.py |
ThreadPoolExecutor singleton, async bridge for blocking ops |
batch_executor.py |
BatchExecutionResult, HostResult, parallel execution |
security.py |
CommandValidator, PathValidator, SecurityLevel, SecurityError |
audit_logger.py |
AuditLogger singleton, AuditEventType enum |
watchdog.py |
Watchdog monitor, TaskInfo, WatchdogEvent |
key_manager.py |
SSHKeyPair generation (RSA/Ed25519), save/load |
logging_config.py |
SSHLogger singleton, file handler support |
exceptions.py |
Exception hierarchy (Connection/Auth/Command/File/Session/Timeout/Pool) |
clients/interface.py |
SSHClientInterface ABC, ClientType, CommandResult, FileTransferResult |
clients/factory.py |
SSHClientFactory, ClientConfig, dynamic registration |
clients/paramiko_client.py |
ParamikoClient implementation |
docker build -t ssh-licco:latest .
docker build -t ssh-licco:0.5.5 .
docker build --build-arg DOCKER_MIRRORS='["https://docker.mirrors.sjtug.sjtu.edu.cn"]' -t ssh-licco:latest .docker run -d \
-e SSH_HOST=192.168.1.100 \
-e SSH_USER=root \
-e SSH_PASSWORD=your_password \
-e SSH_SECURITY_LEVEL=balanced \
ssh-licco:latest- Builder stage: Install dependencies in venv
- Runtime stage: Minimal runtime (~150MB)
Passwords with special characters work fine in JSON - no escaping needed.
- Check server SSH service:
sudo systemctl status sshd - Restart if needed:
sudo systemctl restart sshd
- Restart Trae IDE after updating
- Or restart MCP server process
- Check
SSH_SECURITY_LEVELenv var - Add allowed commands via
SSH_EXTRA_ALLOWED_COMMANDS - Or temporarily set
SSH_SECURITY_LEVEL=relaxed
- Check
SSH_RATE_LIMIT_MAXandSSH_RATE_LIMIT_WINDOW - Disable temporarily:
SSH_RATE_LIMIT=false
- Cause: Damaged npm global package
- Fix:
npm uninstall -g ssh-licco
- ssh-licco auto-verifies and repairs on startup
- Manual:
node install.js
- Create branch from master
-
Make changes to source code in
ssh_mcp/or wrapper files (ssh-licco.js,install.js) -
Test locally:
pip install -e . -
Commit and push:
git push -u github feat/your-feature - Create Pull Request on GitHub
- After PR merged: Update version, build, upload to PyPI
-
Update local master:
git pull github master
| File | Purpose |
|---|---|
ssh-licco.js |
Node.js auto-install wrapper |
install.js |
npm postinstall script |
ssh_mcp/__init__.py |
Version (main) |
ssh_mcp/server.py |
MCP server logic + all tool handlers |
ssh_mcp/security.py |
Security validation (command/path) |
ssh_mcp/audit_logger.py |
Audit logging |
ssh_mcp/connection_config.py |
Connection config Pydantic model |
ssh_mcp/session_manager.py |
Session management |
ssh_mcp/service.py |
Service protocol & health check |
ssh_mcp/exceptions.py |
Exception hierarchy |
ssh_mcp/cli.py |
Python entry point |
config/hosts.json |
Saved SSH hosts |
pyproject.toml |
Package config |
Dockerfile |
Docker image build |
sync_version.py |
Version sync script |
| Document | Purpose |
|---|---|
README.md |
Project overview, quick start, and full usage guide |
docs/API_REFERENCE.md |
API documentation |
docs/CONTRIBUTING.md |
Contribution guidelines |
from ssh_mcp import SSHMCPServer
import asyncio
async def test():
server = SSHMCPServer()
# Use server.server methods...
asyncio.run(test())