Skip to main content
Glama
vait90
by vait90

SSH MCP Server (paramiko)

Paramiko-based SSH MCP server that can run commands on remote machines and move files over SFTP. It is available on two transports, selectable with an environment variable / flag:

  • http – MCP streamable-http endpoint on the /mcp path (this is where Cherry Studio connects), plus a documented OpenAPI/Swagger interface (/docs, /openapi.json).

  • stdio – classic MCP stdio transport (for local launch / docker exec).

IMPORTANT about ports: 2222 is the MCP server port that Cherry Studio connects to. This is NOT the remote machine's SSH port! The remote machine's SSH port is usually 22 (SSH_PORT). So: Cherry Studio → http://<host-IP>:2222/mcp → MCP server → paramiko → the remote machine's SSH port 22.


Available MCP tools

Stateless tools — simple, one-off operations

Tool

Description

ssh_test

Tests the connection and authentication to a remote machine.

ssh_execute

Runs a SINGLE shell command in a fresh connection (stdout / stderr / exit code). No memory: the cd / export do not persist to the next call, and it cannot interactively prompt.

ssh_upload

Uploads a local file to the remote machine over SFTP.

ssh_download

Downloads a file from the remote machine over SFTP.

Stateful, interactive session tools — live shell

These keep a live shell open, where the state persists across calls (directory changes after cd, export-ed variables, handling interactive prompts: sudo password, apt [Y/n], etc.).

Tool

Description

ssh_open_session

Step 1 – opens a new interactive shell and returns a session_id.

ssh_send

Step 2 – sends text (a command or a prompt response) to the session. The session_id must always be passed.

ssh_read

Step 3 (optional) – reads further output without sending anything (for slow/long-running commands).

ssh_close_session

Step 4 – closes the session. Always close it when you are done.

ssh_list_sessions

Lists the open sessions (host, user, idle time), for example if a session_id was lost.

The tool descriptions (docstrings) intentionally contain a very detailed, plain-English "USE THIS WHEN..." guide so that the consuming model clearly knows when and how to use each tool.

Every tool's parameters (host, port, username, password, private_key, private_key_path, passphrase, timeout) can be specified:

  • per call, individually, or

  • as defaults in the .env file (SSH_* variables). Anything not given in the call is taken from the SSH_* environment variables.

Supported authentication: password and key (inline PEM or file path, optionally with a passphrase). Unknown host keys are automatically accepted by the server (AutoAddPolicy) so that automation works smoothly.


Related MCP server: SSH MCP Server

Stateless vs. stateful (interactive) use

Which one when?

  • A single, standalone command (e.g. ls, uptime, df -h) → ssh_execute. Every call opens a fresh connection, runs one command, and closes. No memory: the cd and export do not survive to the next call, and it cannot respond to interactive prompts.

  • Anything interactive or multi-step (state retention after cd/export, entering a sudo password, answering apt [Y/n], sequential commands that build on one another) → interactive session: ssh_open_sessionssh_sendssh_readssh_close_session.

  1. ssh_open_session → you get a session_id back (and the login banner / first prompt in initial_output).

  2. ssh_send → you type a command or respond to a prompt. The session_id must be passed in every call. It also sends an Enter by default.

  3. ssh_read (optional) → collect further output for slow / long-running commands without sending anything.

  4. ssh_close_session → once you are done, close the session.

With ssh_list_sessions you can view open sessions at any time (host, user, idle time), for example if a session_id was lost.

Examples (via REST endpoints)

Opening a session:

curl -X POST http://localhost:2222/api/ssh/session/open \
  -H "Content-Type: application/json" \
  -d '{"host":"192.168.1.100","username":"user","password":"secret"}'
# -> {"ok":true,"session_id":"<ID>", "initial_output":"...prompt..."}

Changing directory, which persists (stateful):

curl -X POST http://localhost:2222/api/ssh/session/send \
  -H "Content-Type: application/json" \
  -d '{"session_id":"<ID>","input":"cd /var/log && pwd"}'
# a következő ssh_send már a /var/log-ban futna

Sudo command + responding to the password prompt:

# 1) elindítod a sudo parancsot
curl -X POST http://localhost:2222/api/ssh/session/send \
  -H "Content-Type: application/json" \
  -d '{"session_id":"<ID>","input":"sudo apt-get update"}'
# 2) a kimenetben megjelenik a "[sudo] password for user:" prompt -> beküldöd a jelszót
curl -X POST http://localhost:2222/api/ssh/session/send \
  -H "Content-Type: application/json" \
  -d '{"session_id":"<ID>","input":"my_sudo_password"}'

Responding to apt [Y/n]:

curl -X POST http://localhost:2222/api/ssh/session/send \
  -H "Content-Type: application/json" \
  -d '{"session_id":"<ID>","input":"sudo apt-get install htop","read_timeout":5}'
# amikor jön a "Do you want to continue? [Y/n]" kérdés:
curl -X POST http://localhost:2222/api/ssh/session/send \
  -H "Content-Type: application/json" \
  -d '{"session_id":"<ID>","input":"Y"}'

Closing the session:

curl -X POST http://localhost:2222/api/ssh/session/close \
  -H "Content-Type: application/json" \
  -d '{"session_id":"<ID>"}'

Timeout / idleness / errors: every session operation opportunistically closes sessions that have been idle longer than the SSH_SESSION_IDLE_TIMEOUT (default 600 seconds), as well as those whose channel has died. At most SSH_MAX_SESSIONS (default 20) sessions can be open at the same time — reaching the limit yields a clear error message. If a session_id no longer exists, the response tells you exactly what to do (open a new session, or check with ssh_list_sessions).


Project structure

ssh-mcp-server/
├── app/
│   ├── __init__.py
│   ├── ssh_ops.py     # paramiko SSH/SFTP műveletek (közös logika)
│   └── server.py      # MCP tool-ok + FastAPI/OpenAPI + transport választás
├── requirements.txt
├── Dockerfile
├── docker-compose.yml # 2222:2222 publikálás
├── .env.example
└── README.md

Prerequisites

cd ssh-mcp-server
cp .env.example .env
# szerkeszd a .env-et: add meg a távoli gép adatait (SSH_HOST, SSH_USERNAME, stb.)

Build and start (HTTP mode)

docker compose up -d --build

This starts the server in HTTP mode and publishes the 2222 port to the host (ports: "2222:2222").

Verification

curl http://localhost:2222/health
# {"status":"ok","service":"ssh-mcp-server","mcp_endpoint":"/mcp"}
  • Swagger UI (in a browser): http://localhost:2222/docs

  • OpenAPI JSON: http://localhost:2222/openapi.json

  • MCP endpoint (Cherry Studio): http://<host-IP>:2222/mcp

Shutdown

docker compose down

2. HTTP mode manually (without Docker, for development)

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
export TRANSPORT=http HOST=0.0.0.0 PORT=2222
python -m app.server

3. stdio mode

With the server running in a container, using docker exec:

docker exec -i -e TRANSPORT=stdio ssh-mcp-server python -m app.server

Or directly, without Docker:

TRANSPORT=stdio python -m app.server

4. Cherry Studio integration

The container runs on your laptop in Docker, and Cherry Studio uses the host IP and port 2222.

  1. Start the server: docker compose up -d --build

  2. Find the IP address of the machine (host) where the Docker is running:

    • Linux: hostname -I → e.g. 192.168.1.50

    • If Cherry Studio is running on the same machine, localhost / 127.0.0.1 is fine too.

  3. Cherry Studio → SettingsMCP ServersAdd / New server.

  4. Enter the following:

    • Type: Streamable HTTP (if not available, use SSE / HTTP)

    • URL / Endpoint: http://<host-IP>:2222/mcp

      • e.g. http://192.168.1.50:2222/mcp

      • same machine: http://localhost:2222/mcp

  5. Save and enable it. Cherry Studio then loads the ssh_test, ssh_execute, ssh_upload, ssh_download tools.

If you are connecting from a remote machine, make sure that port 2222 is reachable (allow it in the firewall) and that Docker is listening on 0.0.0.0 (default).

B) stdio mode

If Cherry Studio expects a stdio MCP server (it launches a command):

  • Command: docker

  • Arguments:

exec -i -e TRANSPORT=stdio ssh-mcp-server python -m app.server

(For this, the sf-mcp-server container must be running — docker compose up -d.)


5. .env configuration

Variable

Description

Default

TRANSPORT

http or stdio

http

HOST

MCP HTTP bind address

0.0.0.0

PORT

MCP HTTP port (reached by Cherry Studio)

2222

SSH_HOST

Remote machine address

SSH_PORT

SSH port of the remote machine

22

SSH_USERNAME

SSH username

SSH_PASSWORD

SSH password (or use a key)

SSH_PRIVATE_KEY

Inline PEM private key

SSH_PRIVATE_KEY_PATH

Path to the private key file (inside the container)

SSH_PASSPHRASE

Passphrase for the private key

SSH_TIMEOUT

Connection timeout (in seconds)

15

SSH_SESSION_IDLE_TIMEOUT

Automatically close idle interactive sessions after this many seconds (0 = none)

600

SSH_MAX_SESSIONS

Maximum number of open interactive sessions at once

20

Key-based authentication in Docker

Mount the keys into the container and set the path. In docker-compose.yml, uncomment the volumes line:

    volumes:
      - ./keys:/keys:ro

then in .env:

SSH_PRIVATE_KEY_PATH=/keys/id_ed25519

6. REST endpoints for testing (OpenAPI)

In HTTP mode, in addition to the Cherry Studio MCP endpoint, REST endpoints are also available — these perform the same SSH operations and can be easily used with curl / from the Swagger UI:

Method

Path

Operation

GET

/health

Status

GET

/

Server info

POST

/api/ssh/test

Connection test

POST

/api/ssh/execute

Command execution

POST

/api/ssh/upload

File upload (SFTP)

POST

/api/ssh/download

File download (SFTP)

POST

/api/ssh/session/open

Open interactive session (step 1)

POST

/api/ssh/session/send

Send input to the session (step 2)

POST

/api/ssh/session/read

Read output without sending (step 3)

POST

/api/ssh/session/close

Close the session (step 4)

GET

/api/ssh/session/list

List open sessions

Example (stateless single-command run):

curl -X POST http://localhost:2222/api/ssh/execute \
  -H "Content-Type: application/json" \
  -d '{"host":"192.168.1.100","username":"user","password":"secret","command":"uname -a"}'

Security notes

  • Secrets are never in the code — everything is read from .env / call parameters.

  • The .env file is excluded by .dockerignore and typically also .gitignore — do not commit it to version control.

  • The server uses AutoAddPolicy (automatic acceptance of unknown host keys). Convenient on closed networks; in stricter environments, it is advisable to use known host keys.

  • Expose the 2222 MCP port only on a trusted network.

F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI assistants to securely execute commands, transfer files, and manage port forwarding on remote servers via SSH.
    98
    36
    Apache 2.0
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables remote server management via SSH, including command execution, file transfer (SFTP), and interactive shell sessions, with support for multiple hosts.
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to securely execute commands on remote hosts via SSH and SFTP, with persistent shells, file transfers, screenshots, and an audit log.
    1
    MIT

View all related MCP servers

Related MCP Connectors

  • Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.

  • Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.

  • Persistent memory and cross-session learning for AI coding assistants (hosted remote MCP).

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vait90/ssh-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server