ssh-mcp-server
ssh-mcp-server
MCP-Server über SSH: Der Agent führt Befehle auf entfernten Maschinen aus, während Schlüssel, Passwörter und sudo auf unserer Seite bleiben.
Ein Fork von classfang/ssh-mcp-server unter ISC.
Deutsch | English
Was ist das?
ssh-mcp-server ist eine Brücke zwischen einem MCP-Client (Claude Code, Cursor, Cline) und SSH. Der Agent ruft Werkzeuge auf, der Server verbindet sich mit der Maschine und gibt die Ausgabe zurück. Das Modell sieht weder den privaten Schlüssel noch das Passwort noch das sudo-Passwort: All das wird aus der lokalen Konfiguration und den Umgebungsvariablen des Prozesses gelesen.
Ein einzelner Server bedient beliebig viele Hosts. Der Host wird spontan über einen Alias aus ~/.ssh/config gewählt, daher muss nicht jede Maschine in die Konfiguration des MCP-Clients eingetragen werden.
Related MCP server: ssh-mcp-server
Was in diesem Fork hinzugefügt wurde
Funktion | Wozu |
Hosts aus | Ein MCP für die gesamte Flotte. Der Alias wird in |
ProxyJump | Ein Host hinter einem Bastion ist über den Alias erreichbar, die |
sudo aus einer Umgebungsvariable | Der Agent fragt |
Verbotener Kern | Eine Liste von Operationen, die niemals ausgeführt werden: weder unter sudo, noch in irgendeinem Profil, noch über SFTP |
Guard-Profile | Fertiger Satz von Verboten |
Tunnel | SOCKS5 (Analogon zu |
Host-Key-Prüfung |
|
Moderne Kryptografie | Ed25519 zuerst in der Liste, ohne SHA-1, CBC und DSA |
Audit-Log | Jeder Aufruf wird in JSONL mit Rotation und gzip-Archiven geschrieben |
Kein Datei-Upload |
|
Werkzeuge
Werkzeug | Was es tut |
| Führt einen Befehl aus, unterstützt |
| Holt eine Datei vom Server |
| Zeigt konfigurierte Verbindungen, deren Status und das aktive Guard-Profil |
| Zeigt Aliase aus der SSH-Konfiguration, die als |
| Startet einen SOCKS5-Proxy oder eine Portweiterleitung über die Verbindung |
| Schließt einen Tunnel |
| Zeigt offene Tunnel und Verbindungszähler |
list-ssh-hosts erscheint nur mit dem Flag --ssh-config-hosts, Tunnel-Werkzeuge werden durch das Flag --disable-tunnels entfernt. Das Werkzeug upload ist nicht in der Liste: Es wird nur mit dem Flag --enable-upload veröffentlicht.
Host-Fakten ohne überflüssige Befehle
Beim Verbinden erfasst der Server einmal den Zustand der Maschine: Name, Adressen, Betriebssystem, Kernel, Uptime, Festplatte, Speicher, Anzahl der Prozesse. Alle Abfragen sind mit Markern zu einem einzigen Befehl zusammengefügt, sodass es ein einziger SSH-Zugriff ist und nicht sechs.
Der Server hält das Ergebnis im Cache und gibt es in list-servers aus:
[connected] prod-1 | deploy@10.0.0.5:22 | hostname=prod-1 | os=Linux | updated=2026-08-19T18:14:23Z
Raw JSON:
[{"name":"prod-1","connected":true,"guards":"guards=safe ruleset=2026.08.19 ...",
"status":{"reachable":true,"osVersion":"Ubuntu 24.04.1 LTS","kernelVersion":"6.8.0-51-generic",
"uptime":"12 days","diskSpace":{"free":"9.8G","total":"229.6G"},
"memory":{"free":"5.6G","total":"15.5G"},"processes":{"running":214}}}]Das heißt, uname -a, df -h, free -h und uptime müssen nicht abgefragt werden, die Antworten sind bereits da. Der Agent ruft list-servers einmal auf und liest den Status daraus.
Die Abfragen werden einzeln durch die Guards geleitet. Mit einer Whitelist bleiben im Status nur die erlaubten Felder. Ein unvollständiger Status bedeutet nicht, dass der Host nicht erreichbar ist.
Ein erfolgreicher Befehl ohne Ausgabe gibt [exit code] 0 zurück, keine leere Zeichenkette. Eine leere Antwort liest das Modell als unklaren Ausgang und prüft über echo $? nach – das ist ein zusätzlicher Zugriff auf den Server und zusätzliche Token.
Schnellstart: ein Server für die gesamte Flotte
Konfiguration des MCP-Clients:
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": [
"-y",
"@perhamm/ssh-mcp-server",
"--ssh-config-hosts",
"--guards-profile", "safe"
],
"env": {
"SSH_MCP_SUDO_PASSWORD": "..."
}
}
}
}Danach arbeitet der Agent so:
Ruft
list-ssh-hostsauf und findet den gewünschten Alias, z. B.r-ulybka-prod-master. Bei großen Konfigurationen wird die Liste gekürzt, daher übergibt der Agentfilter: eine Teilzeichenkette oder ein Muster wier-ulybka-*.Ruft
execute-commandmitconnectionName: "r-ulybka-prod-master"auf.Der Server liest den Alias aus
~/.ssh/config, übernimmt darausHostName,User,Port,IdentityFileundProxyJump, baut die Verbindung auf und führt den Befehl aus.
Der Schlüssel verlässt dabei die Maschine nicht: Der Server liest die Datei selbst, in den Dialog gelangt nur der Pfad aus der SSH-Konfiguration. Wenn IdentityFile nicht angegeben ist, wird der ssh-agent aus SSH_AUTH_SOCK verwendet. Ein Alias ohne HostName verbindet sich unter seinem eigenen Namen, wie es ssh tut.
Erreichbar ist nur der Alias, der in der Konfiguration als eigener Host-Block deklariert ist. Ein Host *-Block liefert Standardwerte, macht aber keinen beliebigen Namen zu einem erreichbaren Host.
Die Liste der Aliase lässt sich eingrenzen:
"args": [
"-y", "@perhamm/ssh-mcp-server",
"--ssh-config-hosts",
"--allowed-hosts", "r-ulybka-*,*-stage-*",
"--ssh-config-file", "/home/user/.ssh/config_work"
]Die Muster unterstützen * und ?. Passt ein Alias auf kein Muster, wird keine Verbindung aufgebaut und der Agent erhält den Fehler SSH_HOST_NOT_ALLOWED.
Sicherheitsmodus und Guards
Guards sind ein versionierter Regelsatz, der jeden Befehl vor dem Senden an den Server prüft. Die Regeln liegen in guards/default-guards.json und werden zusammen mit dem Repository aktualisiert.
Profile
Profil | Verhalten |
| Die Profilregeln sind deaktiviert, nur der verbotene Kern ist aktiv. Standardwert |
| Zusätzlich Verbot destruktiver Befehle, alles andere ist erlaubt |
| Erlaubt nur Lesen und Diagnose, erbt alle Verbote von |
"args": ["-y", "@perhamm/ssh-mcp-server", "--ssh-config-hosts", "--guards-profile", "safe"]Was safe zusätzlich zum Kern abfängt: shutdown und reboot, Zurücksetzen der Firewall, Stoppen von sshd und kubelet, kubectl delete, helm uninstall, docker system prune, Entfernen von Paketen, DROP DATABASE, curl | sh, git push --force, Bereinigen von Logs, Entladen von Kernelmodulen, interaktive Editoren. Die vollständige Liste mit Begründungen steht im JSON.
readonly verlangt zusätzlich, dass jeder Teil des Befehls in die Whitelist fällt: ls, cat, grep, find, ps, ss, df, journalctl, systemctl status, kubectl get/describe/logs, docker ps/logs und Ähnliches. sudo ist in diesem Profil vollständig verboten, zusammen mit su, doas und pkexec.
Verbotener Kern
Einige Operationen werden niemals ausgeführt: weder im Profil off, noch unter sudo, noch über eine eigene Guard-Datei, noch über SFTP an Befehlen vorbei. Die Liste lebt im Block forbidden.
Kategorie | Was gesperrt ist |
Benutzerkonten |
|
sudo | Schreiben in |
Zeitpläne |
|
systemd | Schreiben von Units und Timern in |
SSH | Bearbeiten von |
Interpreter |
|
Massenlöschung |
|
Datenträger und Geheimnisse |
|
Die normale Arbeit bleibt dabei erhalten: crontab -l, cat /etc/ssh/sshd_config, systemctl restart nginx, rm -rf /var/lib/myapp/cache/tmp kommen durch. Auch ein zerlegtes bash -c "..." funktioniert: Sein Inhalt wird mit denselben Regeln geprüft.
Der Kern sperrt auch die Datei-Werkzeuge. download holt weder /etc/shadow noch den Inhalt von ~/.ssh, und allowedRemotePaths erlaubt hier nichts zurück. Auch die lokale Seite ist geschützt: download legt keine Datei in unser eigenes ~/.ssh ab.
Der Datei-Upload ist vollständig deaktiviert. Das Werkzeug upload wird nicht veröffentlicht, solange nicht --enable-upload übergeben wird, und das Profil readonly lehnt den Upload auch mit diesem Flag ab.
Wenn der Server gerade zum Anlegen von Benutzern oder zum Bearbeiten von Cron benötigt wird, muss der Kern bewusst im Fork angepasst werden: Es gibt kein Flag, das ihn aufhebt.
Warum das nicht mit einem Semikolon umgangen wird
Der Befehl wird anhand von ;, |, &&, ||, &, Zeilenumbrüchen und Substitutionen $(...) in Teile zerlegt, und jeder Teil wird einzeln geprüft. Anführungszeichen werden beim Zerlegen berücksichtigt. So kommt ls; rm -rf / in keinem Profil durch, obwohl die gesamte Zeile mit dem erlaubten ls beginnt.
Wrapper werden vor der Prüfung entfernt: sudo, env, timeout 5, nohup und Zuweisungen wie LC_ALL=C verstecken den Befehl nicht vor den Regeln. Ein Skript innerhalb von bash -c "..." wird separat zerlegt und mit denselben Regeln geprüft. Die Befehlslänge ist auf 5000 Zeichen begrenzt.
Guards verhindern Fehler des Agenten, keinen absichtlichen Umgehungsversuch. Einen Interpreter mit beliebigem Code darin, wie python -c, können die Regeln nicht zerlegen. Wo eine Umgehung nicht zulässig ist, schränken wir die Rechte des SSH-Benutzers selbst ein.
Aktualisierung der Regeln
Drei Möglichkeiten, die Regeln aktuell zu halten:
Wir mergen den Upstream in unseren Fork. Die Regeln werden über das Feld
versionversioniert, die Version ist inlist-serversund im Ablehnungstext sichtbar.Wir halten eine eigene Datei und geben sie über
--guards-file /etc/ssh-mcp/guards.jsonan. Die Regeln daraus werden zu den eingebauten hinzugefügt, die Version wird2026.08.19+local-1.Wir aktualisieren die Datei nach Zeitplan:
node scripts/update-guards.js https://example.com/guards.json /etc/ssh-mcp/guards.jsonDas Skript prüft das JSON und kompiliert jeden regulären Ausdruck, und erst danach ersetzt es die Datei. Eine beschädigte Übertragung zerstört nicht den funktionierenden Regelsatz.
Format der eigenen Datei:
{
"version": "local-1",
"profiles": {
"safe": {
"deny": [
{ "id": "no-ansible", "pattern": "^ansible-playbook\\b", "reason": "выкат идёт из CI" }
]
}
}
}Das Feld scope: "command" zwingt die Regel, den gesamten Befehl zu prüfen und nicht nur Teile. So funktionieren die Regeln zu curl | sh und SQL. In den Block forbidden der eigenen Datei können eigene Verbote ergänzt werden, aber die eingebauten lassen sich daraus nicht entfernen: Die Listen werden addiert.
Die alten --whitelist und --blacklist sind weiterhin vorhanden und werden vor den Guards geprüft.
sudo ohne Passwort im Dialog
Das sudo-Passwort liegt in der Umgebungsvariable des Serverprozesses. Der Agent übergibt sudo: true, sieht das Passwort selbst aber weder in den Aufrufargumenten noch in der Ausgabe.
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": ["-y", "@perhamm/ssh-mcp-server", "--ssh-config-hosts", "--guards-profile", "safe"],
"env": {
"SSH_MCP_SUDO_PASSWORD": "..."
}
}
}
}Tool-Aufruf:
{
"tool": "execute-command",
"params": {
"cmdString": "systemctl restart nginx",
"connectionName": "r-ulybka-prod-master",
"sudo": true
}
}Der Befehl geht als sudo -S -k -p '' -u root -- /bin/sh -c '<Befehl>' an den Server, das Passwort wird in den stdin-Kanal geschrieben. In der Kommandozeile steht es nicht, daher landet es weder in ps noch in der History. Für solche Befehle wird das Pseudoterminal deaktiviert, sonst würde das tty die Eingabe zurück in die Ausgabe spiegeln. Sicherheitshalber wird das Passwort aus der Ausgabe und aus Fehlertexten entfernt.
Name der Variable und des Zielbenutzers werden über die Flags --sudo-password-env und --sudo-user geändert. Ist die Variable leer, schlägt der Aufruf bereits vor der Verbindung mit SUDO_PASSWORD_MISSING fehl. Das Profil readonly verbietet sudo grundsätzlich.
Im Modus shell wird das Passwort als separate Zeile direkt hinter dem Befehl angehängt, da sudo denselben stdin liest wie die Shell selbst. Das Flag -k stellt sicher, dass die Passwortabfrage immer erfolgt und die Zeile nicht als Befehl ausgeführt wird. Für sudo ist der Modus exec besser.
Tunnel
open-tunnel startet einen lokalen Listener und leitet den Datenverkehr über die SSH-Verbindung. Nützlich, wenn es keinen direkten Zugriff auf die Cluster-Dienste gibt, aber auf den Knoten schon.
SOCKS5 auf Port 8777:
{
"tool": "open-tunnel",
"params": {
"type": "socks5",
"localPort": 8777,
"connectionName": "r-ulybka-prod-master"
}
}Danach läuft jeder Client über den Proxy, Namen werden auf der entfernten Seite aufgelöst:
curl --socks5-hostname 127.0.0.1:8777 http://prometheus.monitoring.svc:9090/api/v1/query?query=up
kubectl --request-timeout=30s ... # через HTTPS_PROXY=socks5h://127.0.0.1:8777Weiterleitung eines einzelnen Ports, Analog zu ssh -L:
{
"tool": "open-tunnel",
"params": {
"type": "local",
"localPort": 15432,
"remoteHost": "pg-master.internal",
"remotePort": 5432
}
}Wenn localPort nicht angegeben ist, wählt das System den Port und gibt ihn in der Antwort zurück. Tunnel leben bis close-tunnel, bis zum Abbruch der SSH-Verbindung oder bis zum Stopp des Servers.
Einschränkungen werden über Flags gesetzt:
Flag | Standardwert | Funktion |
|
| Adresse, auf der Tunnel lauschen |
| keine Einschränkung | Liste der Ports, die belegt werden dürfen |
| 8 | Wie viele Tunnel gleichzeitig gehalten werden |
| aus | Entfernt die Tunnel-Tools aus der Liste |
Der Listener wird standardmäßig auf Loopback gestartet. Eine Adresse weiter als Loopback öffnet den Proxy in Ihr Netzwerk, daher ändern wir sie bewusst.
Prüfung der Host-Keys
Der Serverschlüssel wird bei jeder Verbindung mit known_hosts abgeglichen, einschließlich der Zwischenhosts der ProxyJump-Kette. Standardmäßig gilt der Modus strict: Ein Host, der nicht in known_hosts steht, bedeutet Ablehnung.
Modus | Verhalten |
| Standard. Verbindung nur zu Hosts aus |
| Unbekannter Host wird bei der ersten Verbindung eingetragen, Schlüsselabweichung bleibt Ablehnung |
| Keine Prüfung, Verhalten des Upstreams |
Geprüft werden ~/.ssh/known_hosts, ~/.ssh/known_hosts2 und /etc/ssh/ssh_known_hosts, und für einen Alias mit UserKnownHostsFile die Datei, die in der SSH-Konfiguration angegeben ist. Eine eigene Liste wird über das Flag --known-hosts-file gesetzt. Verstanden werden gehashte Einträge, Muster, die Form [host]:port und das Label @revoked.
Die Ablehnung kommt mit dem Code SSH_HOST_KEY_REJECTED und einem Text mit dem Fingerprint:
Host key of prod.example.com is not in known_hosts (~/.ssh/known_hosts): ssh-ed25519 SHA256:xxxx.
Verify that fingerprint, add the host to known_hosts, or start the server with --host-key-checking accept-new.Eine Schlüsselabweichung wird in keinem Modus und niemals akzeptiert: Der Server weigert sich, sich zu verbinden, und schreibt, dass der Host entweder neu erstellt wurde oder jemand in der Mitte steht.
Für die erste Bekanntschaft mit dem Bestand ist es praktisch, einmal mit --host-key-checking accept-new durchzugehen und danach wieder strict zu setzen.
Audit-Log
Jeder Aufruf wird als JSON-Zeile geschrieben: Befehl, Verbindung, sudo-Flag, Guard-Urteil, Dauer, Ausgabeumfang. Der Inhalt der Ausgabe gelangt nicht ins Log, das sudo-Passwort wird entfernt.
{"time":"2026-08-19T08:12:44.101Z","pid":8123,"event":"command","result":"blocked","connection":"r-ulybka-prod-master","command":"useradd deploy","sudo":true,"code":"COMMAND_VALIDATION_FAILED","reason":"Blocked by the forbidden core ..."}
{"time":"2026-08-19T08:12:51.880Z","pid":8123,"event":"command","result":"ok","connection":"r-ulybka-prod-master","command":"systemctl status nginx","sudo":false,"durationMs":412,"bytes":1840}Geschrieben werden die Ereignisse connect, command, download, upload, tunnel-open, tunnel-close, host-key.
Standardmäßig liegt die Datei unter $XDG_STATE_HOME/ssh-mcp-server/audit.jsonl, also üblicherweise ~/.local/state/ssh-mcp-server/audit.jsonl, mit Rechten 0600.
Flag | Standard | Funktion |
| XDG-State-Verzeichnis | Pfad zum Log, der Wert |
| 10485760 | Größe, nach der die Datei rotiert wird. |
| 10 | Wie viele gzip-Archive gehalten werden |
Die Rotation ist eingebaut: Bei Erreichen des Limits wandert die aktuelle Datei nach audit.jsonl.1.gz, alte Archive werden verschoben, alles außerhalb von --audit-keep wird gelöscht. Zehn Archive à 10 MiB sind in unkomprimierter Form etwa hundert Megabyte und nach gzip deutlich weniger.
Wenn die Logs bereits von logrotate verwaltet werden, setzen wir --audit-max-size 0 und konfigurieren die Rotation im Modus copytruncate.
Ein Schreibfehler bringt den Befehl nicht zu Fall: Der Server schreibt einmal darüber nach stderr und arbeitet weiter.
Verbindungsarten
Unten Szenarien vom Einfachen zum Komplexen. In args sind jedes Flag und sein Wert zwei separate Array-Elemente: "--host", "192.168.1.1", nicht "--host 192.168.1.1".
Login und Passwort
{
"mcpServers": {
"ssh-mcp-server": {
"command": "npx",
"args": [
"-y",
"@perhamm/ssh-mcp-server",
"--host", "192.168.1.1",
"--port", "22",
"--username", "root",
"--password", "pwd123456"
]
}
}
}Privater Schlüssel
"args": [
"-y", "@perhamm/ssh-mcp-server",
"--host", "192.168.1.1",
"--username", "root",
"--privateKey", "~/.ssh/id_rsa",
"--passphrase", "pwd123456"
]Das Passwort für den Schlüssel muss nicht in die Konfiguration geschrieben werden, sondern kann in die Variable SSH_MCP_PASSPHRASE gelegt werden.
Ein Alias aus ~/.ssh/config
"args": ["-y", "@perhamm/ssh-mcp-server", "--host", "myserver"]Der Server liest HostName, Port, User, IdentityFile und ProxyJump aus dem Block Host myserver, einschließlich der Direktiven Include und Muster. Flags der Kommandozeile haben Vorrang: --port 2222 überschreibt den Port aus der Konfiguration.
Bastion und ProxyJump
Wenn der Alias ein ProxyJump hat, wird die Kette automatisch aufgebaut:
Host r-ulybka-prod-master
HostName 10.20.30.40
User ops
ProxyJump bastion
IdentityFile ~/.ssh/prod_keyJeder nächste Hop verbindet sich über den Kanal des vorherigen, wie es ssh -J tut. Die Kette kann auch manuell angegeben werden: --proxy-jump "bastion,gateway:2222". Die Tiefe der Kette ist auf fünf Hops begrenzt.
Proxy
"args": [
"-y", "@perhamm/ssh-mcp-server",
"--host", "192.168.1.1",
"--username", "root",
"--password", "pwd123456",
"--proxy", "socks5://user:pwd@proxy-host:1080"
]Unterstützt werden socks://, socks5://, http:// und https://. HTTP und HTTPS laufen über die Methode CONNECT mit Basic-Authentifizierung, Standardport 80 und 443. Für SOCKS5 ist der Port Pflicht. Das alte Flag --socksProxy funktioniert, akzeptiert aber nur SOCKS. --proxy und --proxy-jump werden nicht zusammen verwendet.
Jump-Host mit interaktiver Shell
transportMode ist standardmäßig exec. Wir wechseln auf shell, wenn nach erfolgreichem Login Befehle nicht ausgeführt werden oder das Gerät nur eine interaktive Sitzung ausgibt:
"args": [
"-y", "@perhamm/ssh-mcp-server",
"--host", "bastion.example.com",
"--username", "ops",
"--password", "pwd123456",
"--transport-mode", "shell",
"--shell-ready-timeout", "15000"
]Im Modus shell laufen Befehle nacheinander über eine permanente Sitzung, und upload und download funktionieren nicht: SFTP ist dort deaktiviert.
Zwei-Faktor-Authentifizierung
Das Flag --try-keyboard aktiviert keyboard-interactive. Passwort und Schlüssel werden automatisch eingesetzt, der Code aus dem zweiten Faktor wird aus der Variable SSH_MCP_2FA_CODE gelesen.
Mehrere Verbindungen in einem Server
Neben den Aliasen aus der SSH-Konfiguration bleibt die alte Methode: eine Datei mit der Beschreibung der Verbindungen.
[
{
"name": "dev",
"host": "1.2.3.4",
"port": 22,
"username": "alice",
"privateKey": "~/.ssh/dev_key",
"guardProfile": "safe",
"commandTimeoutMs": 120000
},
{
"name": "prod",
"host": "5.6.7.8",
"port": 22,
"username": "bob",
"privateKey": "~/.ssh/prod_key",
"guardProfile": "readonly",
"allowedRemotePaths": ["/var/log", "/tmp"]
}
]"args": ["-y", "@perhamm/ssh-mcp-server", "--config-file", "/abs/path/ssh-config.json"]Auch das Objektformat, bei dem der Schlüssel der Verbindungsname ist, wird unterstützt. Die Verbindung wird über den Parameter connectionName gewählt, ohne ihn wird die erste genommen.
Einschränkungen für Befehle und Pfade
Weiße und schwarze Listen
"args": [
"-y", "@perhamm/ssh-mcp-server",
"--host", "192.168.1.1",
"--username", "root",
"--privateKey", "~/.ssh/id_rsa",
"--whitelist", "^ls( .*)?,^cat .*,^df.*",
"--blacklist", "^rm .*,^shutdown.*"
]Muster sind reguläre Ausdrücke, durch Kommas getrennt. Der Befehl wird zuerst gegen die weiße Liste geprüft, dann gegen die schwarze, dann gegen das Guard-Profil, und muss alle drei Prüfungen bestehen.
Befehlsvorlage
--command-template umhüllt jeden Befehl. <quotedCommand> setzt den Befehl als maskiertes Argument ein, <command> fügt ihn unverändert ein. Die Vorlage wird nach der Substitution des Arbeitsverzeichnisses angewendet.
su root -c <quotedCommand>
docker exec -i mycontainer sh -c <quotedCommand>Pfade für Dateioperationen
--allowed-local-paths erweitert die Liste der lokalen Verzeichnisse, die für upload und download verfügbar sind (standardmäßig nur das aktuelle Verzeichnis). --allowed-remote-paths begrenzt die entfernten Pfade, dort schreiben wir absolute POSIX-Pfade durch Kommas getrennt. Ohne dieses Flag sieht SFTP das gesamte Dateisystem des Hosts, wovor der Server beim Start warnt.
Timeouts und Ausgabelimit
Parameter | Standard | Was begrenzt wird |
| keine | Einen Befehl, überschreibt die Verbindungseinstellungen |
| 30000 | Befehl im Modus |
| 30000 | Befehl im Modus |
| 30000 | Verbindungsaufbau und Handshake |
| 300000 | SFTP-Operationen |
| 10485760 | Erfasste Ausgabe eines Befehls |
| 10000 | Keepalive-Intervall |
Bei Überschreitung des Ausgabelimits wird der Befehl abgebrochen und das Tool gibt OUTPUT_LIMIT_EXCEEDED zusammen mit dem bereits gesammelten Teil zurück. Fehler kommen als Struktur aus code, message und retriable.
Flags der Kommandozeile
--config-file <path> Файл с описанием соединений
--ssh-config-file <path> Путь к SSH-конфигу (по умолчанию ~/.ssh/config)
--ssh <config> Соединение как JSON или пары key=value
-h, --host <host> Хост или алиас из SSH-конфига
-p, --port <port> Порт
-u, --username <name> Пользователь
-w, --password <password> Пароль
-k, --privateKey <path> Путь к приватному ключу
-P, --passphrase <passphrase> Пароль от ключа
-a, --agent <path> Сокет ssh-agent
-W, --whitelist <patterns> Белый список команд, через запятую
-B, --blacklist <patterns> Чёрный список команд, через запятую
--proxy <url> Прокси SOCKS5, HTTP или HTTPS
-s, --socksProxy <url> Старый флаг только для SOCKS5
--allowed-local-paths <paths> Локальные каталоги для upload и download
--allowed-remote-paths <paths> Удалённые каталоги для SFTP
--transport-mode <mode> exec или shell (по умолчанию exec)
--shell-ready-timeout <ms> Таймаут готовности shell (по умолчанию 10000)
--command-template <template> Шаблон с <command> или <quotedCommand>
--pty Псевдотерминал для exec (по умолчанию включён)
--try-keyboard Keyboard-interactive для 2FA
--pre-connect Подключиться ко всем хостам при старте
--ssh-config-hosts Разрешить хосты из SSH-конфига на лету
--allowed-hosts <patterns> Шаблоны разрешённых алиасов, через запятую
--proxy-jump <chain> Цепочка ProxyJump, через запятую
--guards-profile <name> off, safe или readonly (по умолчанию off)
--guards-file <path> Свой набор правил поверх встроенного
--sudo-password-env <var> Переменная с паролем sudo
--sudo-user <user> Пользователь для sudo (по умолчанию root)
--host-key-checking <mode> strict, accept-new или off (по умолчанию strict)
--known-hosts-file <paths> Свои файлы known_hosts, через запятую
--host-key-algorithms <list> Алгоритмы хост-ключа, через запятую
--enable-upload Опубликовать инструмент upload (по умолчанию выключен)
--audit-log <path|off> Путь к аудит-логу (по умолчанию каталог состояния XDG)
--audit-max-size <bytes> Порог ротации, 0 отключает (по умолчанию 10485760)
--audit-keep <count> Сколько архивов держим (по умолчанию 10)
--disable-tunnels Убрать туннельные инструменты
--tunnel-bind-address <addr> Адрес для туннелей (по умолчанию 127.0.0.1)
--allowed-tunnel-ports <ports> Разрешённые порты туннелей, через запятую
--max-tunnels <count> Лимит одновременных туннелей (по умолчанию 8)
--version, -v Версия пакета
--help СправкаSicherheit
Für Produktion aktivieren wir
--guards-profile safe, für die Bereitschaftsanalyse von Vorfällen passtreadonly. Mitoffbleibt nur der verbotene Kern: Alles andere wird ausgeführt, wovor der Server auch im Log warnt.Der Schlüssel, sein Passwort und das sudo-Passwort werden aus Dateien und Umgebungsvariablen gelesen. In der MCP-Client-Konfiguration speichern wir den Pfad zum Schlüssel, nicht den Schlüssel selbst.
Tunnel lauschen auf Loopback. SOCKS5 hat keine Authentifizierung, daher öffnet ein Proxy auf
0.0.0.0das interne Netzwerk für alle, die den Port erreichen, und der Server schreibt beim Start eine Warnung darüber.Ohne
--allowed-remote-pathswerden über SFTP beliebige Pfade auf dem Host gelesen und geschrieben, einschließlich~/.ssh/authorized_keys.Der Host-Key wird im Modus
strictmitknown_hostsabgeglichen. Die Prüfung über--host-key-checking offzu deaktivieren, lohnt sich nur im Labor.Es gibt keine Einschränkungen der Aufruffrequenz.
Entwicklung
npm install
npm run build
npm testDie Tests laufen mit dem eingebauten Node.js-Runner und liegen in test/.
Upstream und Lizenz
Das Projekt ist aus classfang/ssh-mcp-server (Autor junki.cn) entstanden, Lizenz ISC. Das Copyright des Upstreams ist in LICENSE erhalten, dort befindet sich auch der Link zum Quellrepository.
Der Guard-Satz ist teilweise nach Ideen von tufantunc/ssh-mcp (MIT) zusammengestellt.
Das Paket in NPM: @perhamm/ssh-mcp-server.
This server cannot be installed
Maintenance
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
- AlicenseBqualityFmaintenanceAn MCP server that allows AI models to execute system commands on local machines or remote hosts via SSH, supporting persistent sessions and environment variables.13228MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that enables remote SSH command execution and bidirectional file transfers through a standardized interface. It allows AI assistants to securely manage remote servers while keeping credentials isolated and applying command-level security controls.ISC
- AlicenseAqualityBmaintenanceMCP server for managing multiple SSH servers via AI assistants, offering tools for remote command execution, file operations, and system monitoring.11MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that gives AI agents SSH capabilities to execute commands, transfer files, and inspect remote systems through a preconfigured host list.43MIT
Related MCP Connectors
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
MCP server connecting AI agents to non-custodial staking data across 130+ networks.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/perhamm/ssh-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server