Archived
166 lines
8.6 KiB
Markdown
166 lines
8.6 KiB
Markdown
← [Home](Home)
|
|
|
|
# Architecture
|
|
|
|
ssh-mcp is a plain JavaScript (ESM) MCP server built on the `@modelcontextprotocol/sdk`. It exposes 37 tools organized into 6 groups that operate on remote servers over SSH.
|
|
|
|
---
|
|
|
|
## Source Files
|
|
|
|
The `src/` directory contains 19 modules:
|
|
|
|
| File | Responsibility |
|
|
|------|----------------|
|
|
| `index.js` | MCP server entry point. Registers all 37 tools, manages the connection pool, and wires modules together. |
|
|
| `ssh-manager.js` | Thin wrapper around the `ssh2` library. Handles connect, exec, file transfer, and stream operations. |
|
|
| `config.js` | Constants for output limits, timeouts, and helper functions (`truncateOutput`, `formatJSONResponse`). |
|
|
| `config-loader.js` | Loads server definitions from `.env`, TOML, and environment variables with a priority chain. |
|
|
| `backup-manager.js` | Builds shell commands for MySQL, PostgreSQL, MongoDB, and file backups. Manages metadata and retention. |
|
|
| `database-manager.js` | Builds shell commands for database dump, import, list, and read-only query operations. Includes query safety validation. |
|
|
| `health-monitor.js` | Builds shell commands for CPU, memory, disk, network, and load average checks. Parses results and determines overall health status. |
|
|
| `deploy-helper.js` | Deployment strategy builder. Detects permission issues and generates sudo scripts when needed. |
|
|
| `session-manager.js` | Persistent SSH session lifecycle (create, send, list, close). Sessions maintain working directory state across commands. |
|
|
| `tunnel-manager.js` | SSH tunnel creation and management (local, remote, dynamic/SOCKS). Tracks active tunnels and connection statistics. |
|
|
| `server-aliases.js` | Maps short alias names to full server names. Persisted to `~/.ssh-manager/aliases.json`. |
|
|
| `command-aliases.js` | Maps short command strings to full commands. Supports suggestion of aliases for frequently typed commands. |
|
|
| `server-groups.js` | Server group CRUD and multi-server command execution with parallel, sequential, and rolling strategies. |
|
|
| `hooks-system.js` | Automation hooks that run before/after operations (e.g., `pre-backup`, `post-bench-update`). |
|
|
| `profile-loader.js` | Profile management for switching between project-specific tool/configuration sets. |
|
|
| `ssh-key-manager.js` | Host key verification, fingerprint comparison, and `known_hosts` management. |
|
|
| `tool-registry.js` | Centralized registry of all 37 tools and their group assignments. Provides validation and statistics. |
|
|
| `tool-config-manager.js` | Reads `~/.ssh-manager/tools-config.json` to determine which tool groups are enabled. |
|
|
| `logger.js` | Structured logging with levels, command history tracking, and transfer logging. |
|
|
|
|
---
|
|
|
|
## Component Diagram
|
|
|
|
```
|
|
Claude Code / MCP Client
|
|
|
|
|
| stdio (JSON-RPC)
|
|
v
|
|
+-----------+
|
|
| index.js | <-- MCP Server (tool registration + dispatch)
|
|
+-----------+
|
|
|
|
|
+---> ssh-manager.js ---> ssh2 library ---> Remote Server
|
|
|
|
|
+---> config-loader.js ----> .env / TOML / env vars
|
|
|
|
|
+---> tool-config-manager.js ---> tools-config.json
|
|
|
|
|
+---> session-manager.js (persistent sessions)
|
|
+---> tunnel-manager.js (port forwarding)
|
|
+---> backup-manager.js (backup commands)
|
|
+---> database-manager.js (db commands)
|
|
+---> health-monitor.js (monitoring commands)
|
|
+---> deploy-helper.js (deployment logic)
|
|
+---> server-groups.js (multi-server ops)
|
|
+---> hooks-system.js (pre/post hooks)
|
|
+---> server-aliases.js (alias resolution)
|
|
+---> command-aliases.js (command shortcuts)
|
|
+---> profile-loader.js (profiles)
|
|
+---> ssh-key-manager.js (host key mgmt)
|
|
+---> logger.js (logging + history)
|
|
```
|
|
|
|
---
|
|
|
|
## Tool Activation System
|
|
|
|
Not every user needs all 37 tools. Unused tools consume context tokens in Claude Code without providing value. The tool activation system solves this.
|
|
|
|
### How It Works
|
|
|
|
1. On startup, `tool-config-manager.js` loads `~/.ssh-manager/tools-config.json`.
|
|
2. The config specifies a mode (`all`, `minimal`, or `custom`) and per-group enabled/disabled flags.
|
|
3. In `index.js`, every tool is registered through `registerToolConditional()`, which checks `isToolEnabled(toolName)` before calling `server.registerTool()`.
|
|
4. Disabled tools are silently skipped -- the MCP client never sees them.
|
|
|
|
### Configuration Modes
|
|
|
|
| Mode | Tools | Context Usage |
|
|
|------|-------|---------------|
|
|
| `all` | 37 | ~43.5k tokens |
|
|
| `minimal` | 5 (core only) | ~3.5k tokens |
|
|
| `custom` | Variable | Variable |
|
|
|
|
The CLI (`ssh-manager tools configure`) provides an interactive wizard for selecting groups.
|
|
|
|
### Tool Groups
|
|
|
|
| Group | Count | Tools |
|
|
|-------|-------|-------|
|
|
| core | 5 | `ssh_execute`, `ssh_upload`, `ssh_download`, `ssh_sync`, `ssh_list_servers` |
|
|
| sessions | 4 | `ssh_session_start`, `ssh_session_send`, `ssh_session_list`, `ssh_session_close` |
|
|
| monitoring | 6 | `ssh_health_check`, `ssh_service_status`, `ssh_process_manager`, `ssh_monitor`, `ssh_tail`, `ssh_alert_setup` |
|
|
| backup | 4 | `ssh_backup_create`, `ssh_backup_list`, `ssh_backup_restore`, `ssh_backup_schedule` |
|
|
| database | 4 | `ssh_db_dump`, `ssh_db_import`, `ssh_db_list`, `ssh_db_query` |
|
|
| advanced | 14 | `ssh_deploy`, `ssh_execute_sudo`, `ssh_alias`, `ssh_command_alias`, `ssh_hooks`, `ssh_profile`, `ssh_connection_status`, `ssh_tunnel_create`, `ssh_tunnel_list`, `ssh_tunnel_close`, `ssh_key_manage`, `ssh_execute_group`, `ssh_group_manage`, `ssh_history` |
|
|
|
|
---
|
|
|
|
## Connection Pooling
|
|
|
|
ssh-mcp maintains a pool of SSH connections to avoid the overhead of re-authenticating on every tool call.
|
|
|
|
### Pool Mechanics
|
|
|
|
| Aspect | Behavior |
|
|
|--------|----------|
|
|
| **Storage** | Active connections are held in a `Map<serverName, SSHClient>`. |
|
|
| **Reuse** | `getConnection(serverName)` returns an existing connection if it is still valid (tested via ping), or creates a new one. |
|
|
| **Timeout** | Connections idle for more than 30 minutes are closed by a periodic cleanup sweep. |
|
|
| **Keepalive** | Every 5 minutes, a ping is sent to each connection. If the ping fails, the connection is removed from the pool and will be re-established on the next call. |
|
|
| **Cleanup on error** | If a command times out, the connection is disposed of immediately so subsequent calls get a fresh channel. |
|
|
|
|
### Proxy Jump Support
|
|
|
|
When `PROXYJUMP` is set, the server first connects to the jump host, then tunnels through it to reach the target. Jump host connections are also pooled. Dependency tracking ensures that closing a jump host also closes all connections that depend on it.
|
|
|
|
`PROXYCOMMAND` provides an alternative mechanism. The configured command (e.g., `ncat`, `ssh -W`) is spawned as a local child process, and its stdin/stdout are used as the transport socket.
|
|
|
|
---
|
|
|
|
## Command Execution
|
|
|
|
Commands are executed via `execCommandWithTimeout()`:
|
|
|
|
1. **Windows targets** are detected by the `platform` config field. Commands are UTF-16LE base64-encoded and passed to PowerShell via `-EncodedCommand`, avoiding quoting issues.
|
|
2. **Linux/macOS targets** wrap commands in the system `timeout` utility for reliable kill semantics on long-running operations.
|
|
3. Output is truncated to configurable limits to prevent Claude Code crashes from extremely large command output.
|
|
|
|
---
|
|
|
|
## Design Decisions
|
|
|
|
### Plain JavaScript (no TypeScript)
|
|
|
|
The project uses plain JavaScript with ES modules. This keeps the build step to zero -- `node src/index.js` is all that is needed. JSDoc comments provide type hints where useful.
|
|
|
|
### Command Building vs. Direct Execution
|
|
|
|
Manager modules (`backup-manager.js`, `database-manager.js`, `health-monitor.js`) build shell command strings rather than using database client libraries. This design means:
|
|
|
|
- No database drivers need to be installed on the MCP host.
|
|
- The remote server only needs standard tools (`mysqldump`, `pg_dump`, `mongodump`, `tar`, etc.).
|
|
- Commands run in the same security context as the SSH user.
|
|
|
|
### Read-Only Query Safety
|
|
|
|
`ssh_db_query` validates that the query is a `SELECT` statement before execution. The `isSafeQuery()` function in `database-manager.js` rejects `INSERT`, `UPDATE`, `DELETE`, `DROP`, and other mutating statements.
|
|
|
|
### Hooks System
|
|
|
|
Hooks run at defined lifecycle points (e.g., `pre-backup`, `post-bench-update`). They are shell scripts stored in `~/.ssh-manager/hooks/` and are opt-in -- disabled by default until explicitly enabled via `ssh_hooks`.
|
|
|
|
---
|
|
|
|
*Repo: [ssh-mcp](https://git.mokoconsulting.tech/MokoConsulting/ssh-mcp) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
|
|
|
|
| Revision | Date | Author | Description |
|
|
|---|---|---|---|
|
|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
|