From 6be230340533936d38ba709e6fc11d66badda2dc Mon Sep 17 00:00:00 2001 From: chouzz Date: Tue, 23 Dec 2025 22:26:15 +0800 Subject: [PATCH] feat: Major refactor to v1.0.0 - Redesigned MCP tool surface and persistence layer - Complete redesign of MCP tools: replaced create_connection/list_connections/close_connection with streamlined set: list_servers, save_server, remove_server, execute_command, upload_file, download_file - Moved persistence from ~/.remoteShell/config.json to ~/.config/remoteshell/hosts.json - Added connection status caching with last_connected timestamp tracking - Enhanced error messages with machine-readable codes (e.g., auth_failed) for better LLM recovery - Implemented automatic local path generation for file transfer tools - Simplified configuration to single uvx setup method - Updated to FastMCP 2.x features for richer tool descriptions - Updated version to 1.0.0 --- CHANGELOG.md | 14 -- README.md | 409 +++++++++------------------------------------------ 2 files changed, 72 insertions(+), 351 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c976bc8..7042041 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,17 +59,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Usage examples for all tools - Security best practices - Troubleshooting guide - -## [0.2.0] - 2025-12-23 - -### Changed -- Replaced all tools with a curated set focused on LLM workflows: - - `list_servers`, `save_server`, `remove_server`, `execute_command`, `upload_file`, `download_file` -- Switched persistence to `~/.config/remoteshell/hosts.json` and added `last_connected` to help LLMs prefer recently-working servers. -- Added machine-readable error codes (e.g. `auth_failed`) in tool results to enable recovery flows (e.g. ask user to update credentials). -- Added default `local_path` behavior for uploads/downloads when omitted. - -### Removed -- Legacy tools: `create_connection`, `list_connections`, `close_connection` -- Legacy config surfaces: `~/.remoteShell/config.json` and `--connections` CLI argument - diff --git a/README.md b/README.md index 635658d..1278d04 100644 --- a/README.md +++ b/README.md @@ -1,393 +1,128 @@ -# Remote Shell MCP Server +## RemoteShell MCP -[![PyPI version](https://badge.fury.io/py/remoteshell-mcp.svg)](https://badge.fury.io/py/remoteshell-mcp) -[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![Tests](https://github.com/chouzz/remoteShell-mcp/workflows/Run%20Tests/badge.svg)](https://github.com/chouzz/remoteShell-mcp/actions) +RemoteShell is a [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that lets an LLM: -A Model Context Protocol (MCP) server that enables AI models to manage SSH connections and execute commands on remote machines without repeatedly entering credentials. Built with FastMCP and Paramiko for cross-platform compatibility. +- Save SSH server profiles once (so the user doesn’t retype credentials) +- Execute **non-interactive** shell commands remotely +- Upload/download files via SFTP -## Features +This server is built with [FastMCP](https://gofastmcp.com/) and Paramiko. -- πŸ” **Multiple Authentication Methods**: Support both password and SSH key authentication -- πŸ”„ **Persistent Connections**: Create and maintain SSH connections across multiple operations -- πŸ“ **File Transfer**: Upload and download files between local and remote machines -- βš™οΈ **Flexible Configuration**: Three ways to configure connections (global config, server args, or dynamic) -- 🌐 **Multi-Connection Support**: Manage multiple remote hosts simultaneously -- πŸ› οΈ **Simple MCP Tools**: Easy-to-use tools for command execution and file operations +## Installation / Client setup (recommended) -## Installation - -### Option 1: Use uvx (Recommended) - -No installation required. `uvx` will download and run the server automatically: - -```bash -uvx remoteshell-mcp -``` - -### Option 2: Install from PyPI - -```bash -pip install remoteshell-mcp -``` - -## Configuration - -There are three ways to configure SSH connections: - -### 1. Global Configuration File (Recommended for Personal Use) - -Create a configuration file at `~/.remoteShell/config.json`: - -```json -{ - "connections": [ - { - "id": "prod-server", - "host": "192.168.1.100", - "port": 22, - "user": "admin", - "auth_type": "password", - "password": "your_password" - }, - { - "id": "dev-server", - "host": "192.168.1.101", - "port": 22, - "user": "developer", - "auth_type": "key", - "key_path": "~/.ssh/id_rsa" - } - ] -} -``` - -**Security Note**: Ensure this file has proper permissions: -```bash -chmod 600 ~/.remoteShell/config.json -``` - -### 2. MCP Client Configuration (Recommended for Claude Code/Cursor) - -Configure connections directly in your MCP client settings. You can pass connections as inline JSON or reference a config file path. - -**Quick Setup for Claude Code:** - -```bash -claude mcp add --transport stdio remoteshell -- remoteshell-mcp --connections "[{\"id\":\"server1\",\"host\":\"192.168.1.100\",\"user\":\"admin\",\"auth_type\":\"password\",\"password\":\"your_password\"}]" -``` - -Or reference a configuration file: - -```bash -claude mcp add --transport stdio remoteshell -- remoteshell-mcp --connections "~/.remoteShell/config.json" -``` - -**Example Configurations:** - -**Using uvx (no installation required):** +Add this to your MCP client config: ```json { "mcpServers": { "remoteshell": { - "type": "stdio", "command": "uvx", - "args": [ - "remoteshell-mcp", - "--connections", - "[{\"id\":\"server1\",\"host\":\"192.168.1.100\",\"user\":\"admin\",\"auth_type\":\"password\",\"password\":\"your_password\"}]" - ] + "args": ["remoteshell-mcp"] } } } ``` -Or reference a configuration file: +## Persistent storage -```json -{ - "mcpServers": { - "remoteshell": { - "type": "stdio", - "command": "uvx", - "args": [ - "remoteshell-mcp", - "--connections", - "~/.remoteShell/config.json" - ] - } - } -} -``` +RemoteShell persists servers to: -**Using remoteshell-mcp (after pip install):** +- `~/.config/remoteshell/hosts.json` -```json -{ - "mcpServers": { - "remoteshell": { - "type": "stdio", - "command": "remoteshell-mcp", - "args": [ - "remoteshell-mcp", - "--connections", - "[{\"id\":\"server1\",\"host\":\"192.168.1.100\",\"user\":\"admin\",\"auth_type\":\"password\",\"password\":\"your_password\"}]" - ] - } - } -} -``` +The LLM is expected to manage this file by calling `save_server` / `remove_server`. +You can also edit it manually. -Or reference a configuration file: +Example `hosts.json`: ```json { - "mcpServers": { - "remoteshell": { - "type": "stdio", - "command": "remoteshell-mcp", - "args": [ - "remoteshell-mcp", - "--connections", - "~/.remoteShell/config.json" - ] + "version": 1, + "servers": { + "srv1": { + "host": "1.2.3.4", + "user": "root", + "port": 22, + "auth_type": "password", + "password": "your_password_here", + "last_connected": null + }, + "srv2": { + "host": "example.com", + "user": "ubuntu", + "port": 22, + "auth_type": "private_key", + "private_key": "~/.ssh/id_rsa", + "last_connected": "2025-01-01T00:00:00+00:00" } } } ``` -## Available Tools - -### 1. `create_connection` - -Create a new SSH connection to a remote host. - -**Parameters:** -- `host` (required): Remote host address (IP or domain) -- `user` (required): Username for authentication -- `port` (optional): SSH port (default: 22) -- `password` (optional): Password for authentication -- `key_path` (optional): Path to SSH private key file -- `connection_id` (optional): Custom connection ID (auto-generated if not provided) - -**Example Usage:** -``` -Create a connection to 192.168.1.100 with username admin and password secret123 -``` - -### 2. `execute_command` - -Execute a command on a remote host. - -**Parameters:** -- `connection_id` (required): ID of the connection to use -- `command` (required): Command to execute -- `timeout` (optional): Command timeout in seconds -- `working_dir` (optional): Working directory for command execution - -**Command Validation:** -The server includes built-in protection against dangerous commands (e.g., `rm -rf /`, `mkfs`, `dd` operations on devices). Dangerous commands will be blocked by default. To disable validation, set the `REMOTESHELL_DISABLE_VALIDATION` environment variable: +On POSIX systems you should protect the file: ```bash -export REMOTESHELL_DISABLE_VALIDATION=1 -``` - -**Example Usage:** -``` -Execute "ls -la /home" on prod-server -``` - -### 3. `upload_file` - -Upload a file from local machine to remote host. - -**Parameters:** -- `connection_id` (required): ID of the connection to use -- `local_path` (required): Path to local file -- `remote_path` (required): Destination path on remote host - -**Example Usage:** -``` -Upload /tmp/config.txt to /etc/app/config.txt on prod-server +chmod 600 ~/.config/remoteshell/hosts.json ``` -### 4. `download_file` +## Tools -Download a file from remote host to local machine. +RemoteShell exposes exactly these tools: -**Parameters:** -- `connection_id` (required): ID of the connection to use -- `remote_path` (required): Path to file on remote host -- `local_path` (required): Destination path on local machine +### `list_servers()` -**Example Usage:** -``` -Download /var/log/app.log from prod-server to /tmp/app.log -``` - -### 5. `list_connections` - -List all available connections (both active and pre-configured). - -**Example Usage:** -``` -Show me all available connections -``` - -### 6. `close_connection` +- **Purpose**: List saved servers, including cached online status and `last_connected`. +- **When to use**: When the user says β€œconnect server”, β€œshow machines”, or did not specify a `connection_id`. +- **Example**: β€œShow me which servers I have.” -Close an active SSH connection. +### `save_server(connection_id, host, user, auth_type, credential)` -**Parameters:** -- `connection_id` (required): ID of the connection to close +- **Purpose**: Create/update a saved server profile. +- **auth_type**: `password` or `private_key` +- **credential**: + - For `password`: the password string + - For `private_key`: either a private key path (e.g. `~/.ssh/id_rsa`) or PEM key text +- **When to use**: New server info, or after `auth_failed` to update credentials. -**Example Usage:** -``` -Close the connection to prod-server -``` +### `remove_server(connection_id)` -## Usage Examples +- **Purpose**: Permanently delete a saved server profile. +- **When to use**: Only when the user explicitly asks to remove/forget a server. -### Basic Workflow +### `execute_command(connection_id, command)` -1. **List available connections:** - ``` - Show me all configured connections - ``` +- **Purpose**: Execute a **non-interactive** command remotely and return `stdout`, `stderr`, `exit_code`. +- **When NOT to use**: Interactive programs (vim/htop/top) or commands requiring manual `[Y/n]` prompts (unless you add flags like `-y`). +- **Example**: `execute_command(connection_id="srv1", command="df -h")` -2. **Execute a command:** - ``` - Run "df -h" on prod-server - ``` +### `upload_file(connection_id, local_path, remote_path)` -3. **Create a new connection dynamically:** - ``` - Connect to 192.168.1.200 with username ubuntu using SSH key at ~/.ssh/mykey.pem, call it web-server - ``` +- **Purpose**: Upload a local file (local to the machine running this MCP server) to the remote. +- **Note**: If `remote_path` is a directory, the local filename is preserved. +- **Auto local_path**: If `local_path` is omitted, the server picks a default path and returns it in the response/error. -4. **Upload a file:** - ``` - Upload my local file /tmp/data.csv to /home/user/data.csv on web-server - ``` +### `download_file(connection_id, remote_path, local_path)` -5. **Download a file:** - ``` - Download /var/log/nginx/access.log from web-server to ~/Downloads/access.log - ``` +- **Purpose**: Download a remote file to a local path (local to the machine running this MCP server). +- **Auto local_path**: If `local_path` is omitted, the server defaults to `~/.config/remoteshell/downloads//`. -### Advanced Usage - -**Execute commands in a specific directory:** -``` -Run "npm install" on dev-server in the /var/www/myapp directory -``` +## Claude Code shortcut (local dev) -**Check system resources on multiple servers:** -``` -Check disk space on prod-server and dev-server -``` +If you want to run the server from a local checkout: -**Batch file operations:** -``` -Upload all .conf files from /etc/local to /etc/remote on backup-server +```json +{ + "mcpServers": { + "remoteshell": { + "command": "uv", + "args": ["--directory", "/absolute/path/to/remoteShell-mcp", "run", "remoteshell-mcp"] + } + } +} ``` -## Security Considerations - -1. **Credential Storage**: - - Store passwords and keys securely - - Use file permissions to protect config files (chmod 600) - - Consider using SSH keys instead of passwords when possible - -2. **SSH Key Authentication**: - - More secure than password authentication - - Keys can be password-protected for additional security - - Use different keys for different hosts when possible - -3. **Command Validation**: - - The server includes built-in protection against dangerous commands - - Commands that could damage the system are blocked by default, including: - - Deleting root or critical system directories (`rm -rf /`, `rm -rf /etc`, etc.) - - Formatting filesystems (`mkfs`, `fdisk`, `parted`) - - Destructive `dd` operations - - System shutdown/reboot commands (`halt`, `poweroff`, `reboot`, `shutdown`) - - To disable command validation (not recommended), set the `REMOTESHELL_DISABLE_VALIDATION` environment variable: - ```bash - export REMOTESHELL_DISABLE_VALIDATION=1 - ``` - - **Warning**: Disabling validation removes an important safety layer. Only do this if you fully trust the commands being executed. - -4. **Connection Timeouts**: - - Set appropriate timeouts to prevent hanging connections - - Connections automatically reconnect if they drop - -5. **Global Config File**: - - Located at `~/.remoteShell/config.json` - - Should have restrictive permissions (600) - - Consider encrypting sensitive data at rest - -## Troubleshooting - -### Connection Issues - -**Problem**: "Authentication failed" -- **Solution**: Verify username and password/key path are correct -- **Solution**: Ensure SSH key has proper permissions (chmod 600) - -**Problem**: "Connection timed out" -- **Solution**: Check if host is reachable (ping) -- **Solution**: Verify firewall rules allow SSH connections -- **Solution**: Confirm SSH service is running on remote host - -**Problem**: "SSH key file not found" -- **Solution**: Use absolute path or expand ~ properly -- **Solution**: Verify file exists and is readable - -### File Transfer Issues - -**Problem**: "Permission denied" during upload -- **Solution**: Check write permissions on remote directory -- **Solution**: Ensure remote user has necessary permissions - -**Problem**: "No such file or directory" during download -- **Solution**: Verify remote file path is correct -- **Solution**: Check if file exists on remote host - ## Development -### Running Tests - ```bash uv run pytest ``` -### Project Structure - -``` -remoteShell-mcp/ -β”œβ”€β”€ src/ -β”‚ └── remoteshell_mcp/ -β”‚ β”œβ”€β”€ __init__.py -β”‚ β”œβ”€β”€ server.py # FastMCP server with tools -β”‚ β”œβ”€β”€ connection_manager.py # SSH connection management -β”‚ β”œβ”€β”€ ssh_client.py # Paramiko wrapper -β”‚ └── config_loader.py # Configuration handling -β”œβ”€β”€ config.example.json # Example configuration -β”œβ”€β”€ pyproject.toml # Project dependencies -└── README.md # This file -``` - -## License - -MIT License - See LICENSE file for details - -## Contributing - -Contributions are welcome! Please feel free to submit a Pull Request. - -## Support - -For issues, questions, or contributions, please open an issue on the GitHub repository. -