Skip to content

async-ssh-mcp

Coming soon

This project is not yet released.

A security-focused, asynchronous Model Context Protocol (MCP) server that lets AI assistants manage remote systems over SSH and SFTP. Built on asyncssh, it is strictly typed (mypy --strict) and carries 100% statement coverage across all modules.

Python · MIT License

Why

MCP gives an AI assistant a standard way to call tools, but handing that assistant a raw shell is a good way to regret it. This server sits between the two: every command, file read, and file write goes through permission toggles, rate limits, and regex allow/deny filters before it ever reaches a remote host, and every call is written to a local, redacted audit log.

Features

  • Asynchronous first -- built on asyncssh for non-blocking I/O, so connection pooling and SFTP transfers run concurrently without blocking the event loop.
  • Resilience -- automatic reconnection with exponential backoff on transient network drops.
  • Credential safety -- environment variable interpolation ($VAR, ${VAR}) keeps secrets out of the configuration file.
  • OS-level sandboxing -- experimental support for seccomp-BPF (Linux), Capsicum (FreeBSD), pledge/unveil (OpenBSD), and Seatbelt (macOS). Windows has no native sandbox yet; use Docker for isolation there.
  • Per-server permissions -- toggle allow_execute, allow_sftp_read, and allow_sftp_write independently for each configured host.
  • Rate limiting -- per-server call frequency and concurrency caps.
  • Command filtering -- configurable regex allowlist / denylist.
  • Audit logging -- local-only, structured JSONL with automatic credential redaction and result truncation.
  • Path anchoring -- restrict file operations to a remoteRoot.
  • Cross-platform targets -- personality abstraction handles command generation, quoting, and path resolution for both POSIX and Windows remote hosts.

Toolset

execute-command, get-system-info, list-directory, read-file, write-file, patch-file, diff-files, find-files, mkdir, remove, pre-flight, file-stat, compute-hash, upload, download.

Quick start

pip install async-ssh-mcp
async-ssh-mcp --host your-host --username your-user --agent-path auto

For multi-server setups, use a config file instead:

# config.yaml
servers:
  - name: "prod-web"
    host: "10.0.1.5"
    username: "admin"
    password: "$PROD_PASSWORD"   # interpolated from the environment
    remoteRoot: "/var/www"
    allowlist: ["^ls", "^git status"]

allowed_local_paths: ["/home/user/deploy"]
audit_log: "ssh_audit.log"
async-ssh-mcp --config-file config.yaml --check-config

Architecture

The server is layered so that CLI parsing, protocol handling, and transport stay decoupled:

  • Entry layer (main.py, config.py) -- Click-based CLI argument parsing and Pydantic-validated configuration; also applies OS sandboxing before the event loop starts.
  • Orchestration layer (server.py) -- implements the MCP handlers and dispatches call_tool / read_resource / get_prompt requests. Tools, resources, and prompts are aggregated through a factory pattern, so new capabilities plug in without touching the core server.
  • Transport layer (ssh/, utils.py) -- a ConnectionManager orchestrates pooled SSH clients and multi-hop ProxyJump tunnels; a SshPersonality abstraction (POSIX vs. Windows) centralizes all OS-specific command generation and quoting.

Security is enforced at three points on every request: the sandbox layer restricts the server process itself, the logic layer applies regex filters and path anchoring to what the assistant can request, and the audit layer records the attempt with credentials redacted.

Sandboxing

Sandboxing follows a "lockdown after init" pattern -- load configuration, pre-open resources, apply OS-level restrictions, then start serving tool calls. It is experimental and opt-in via --sandbox.

Platform Mechanism Status
Linux Seccomp-BPF Experimental (KILL default)
FreeBSD Capsicum Experimental
OpenBSD pledge / unveil Experimental
macOS Seatbelt Experimental
Windows Mitigation policies / integrity level Experimental

Windows uses SetProcessMitigationPolicy to block child-process spawning and SetTokenInformation to drop the process to Low Integrity Level, rather than a POSIX-style syscall sandbox.