Skip to main content
Glama
perhamm

ssh-mcp-server

by perhamm

ssh-mcp-server

CI npm

SSH 위의 MCP 서버: 에이전트가 원격 머신에서 명령을 실행하고, 키, 비밀번호, sudo는 우리 쪽에 남는다.

classfang/ssh-mcp-server의 ISC 포크.

Русский | English

이게 뭔가요

ssh-mcp-server는 MCP 클라이언트(Claude Code, Cursor, Cline)와 SSH 사이의 다리입니다. 에이전트가 도구를 호출하면 서버가 머신에 연결해 출력을 반환합니다. 모델은 개인 키, 비밀번호, sudo 비밀번호를 볼 수 없습니다. 이 모든 것은 로컬 구성과 프로세스 환경 변수에서 읽힙니다.

하나의 서버가 임의의 수의 호스트를 처리합니다. 호스트는 ~/.ssh/config의 별칭으로 즉시 선택되므로 MCP 클라이언트 구성에 각 머신을 적을 필요가 없습니다.

Related MCP server: ssh-mcp-server

이 포크에서 추가된 것

기능

이유

~/.ssh/config에서 즉시 호스트

전체 서버 팜에 MCP 하나. 별칭이 connectionName으로 전달되고, 첫 호출 시 연결이 수립됨

ProxyJump

배스천 뒤의 호스트가 별칭으로 접근 가능, ProxyJump 체인이 SSH 구성에서 파싱됨

환경 변수의 sudo

에이전트가 sudo: true를 요청하면 서버가 비밀번호를 넣고 출력에서 잘라냄

금지 코어

절대 실행되지 않는 작업 목록: sudo 아래에서도, 어떤 프로필에서도, SFTP를 통해서도 아님

가드 프로필

버전 관리되고 업데이트 가능한 safe 금지 세트와 readonly 화이트리스트

터널

임의의 로컬 포트에 SOCKS5(ssh -D와 유사) 및 포트 포워딩(ssh -L과 유사)

호스트 키 검증

known_hosts가 기본적으로 확인되며, 목록에 없는 키는 연결 거부를 의미함

현대 암호화

Ed25519가 목록 첫 번째, SHA-1, CBC, DSA 없음

감사 로그

각 호출이 회전 및 gzip 아카이브와 함께 JSONL로 기록됨

파일 업로드 없음

upload는 기본적으로 게시되지 않음: 가드가 읽지 못하는 파일은 호스트에 코드를 넣는 방법임

도구

도구

하는 일

execute-command

명령 실행, sudo 및 임의의 connectionName 지원

download

서버에서 파일 가져오기

list-servers

구성된 연결, 상태, 활성 가드 프로필 표시

list-ssh-hosts

connectionName으로 사용 가능한 SSH 구성의 별칭 표시

open-tunnel

연결을 통해 SOCKS5 프록시 또는 포트 포워딩 시작

close-tunnel

터널 닫기

list-tunnels

열린 터널 및 연결 카운터 표시

list-ssh-hosts는 --ssh-config-hosts 플래그가 있을 때만 나타나고, 터널 도구는 --disable-tunnels 플래그로 제거됩니다. 목록에 upload 도구는 없습니다. --enable-upload 플래그가 있을 때만 게시됩니다.

불필요한 명령 없이 호스트 정보 얻기

연결 시 서버는 머신 상태를 한 번 수집합니다: 이름, 주소, OS, 커널, 업타임, 디스크, 메모리, 프로세스 수. 모든 프로브가 마커로 하나의 명령에 결합되므로 ssh로 여섯 번 가는 것이 아니라 한 번 갑니다.

서버는 결과를 캐시에 보관하고 list-servers에서 반환합니다:

[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}}}]

즉, uname -a, df -h, free -h, uptime을 물어볼 필요가 없습니다. 답이 이미 왔습니다. 에이전트는 list-servers를 한 번 호출하고 상태를 거기서 읽습니다.

프로브는 각각 가드를 통과합니다. 화이트리스트를 사용하면 허용된 필드만 상태에 남습니다. 불완전한 상태가 호스트에 접근할 수 없다는 뜻은 아닙니다.

출력이 없는 성공적인 명령은 빈 문자열이 아니라 [exit code] 0을 반환합니다. 빈 응답은 모델이 이해할 수 없는 결과로 읽고 echo $?로 다시 확인하러 가는데, 이는 서버에 불필요한 왕복과 불필요한 토큰을 만듭니다.

빠른 시작: 전체 서버 팜에 서버 하나

MCP 클라이언트 구성:

{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": [
        "-y",
        "@perhamm/ssh-mcp-server",
        "--ssh-config-hosts",
        "--guards-profile", "safe"
      ],
      "env": {
        "SSH_MCP_SUDO_PASSWORD": "..."
      }
    }
  }
}

그 다음 에이전트는 다음과 같이 작동합니다:

  1. list-ssh-hosts를 호출하고 필요한 별칭(예: r-ulybka-prod-master)을 찾습니다. 큰 구성에서는 목록이 잘리므로 에이전트는 filter(부분 문자열 또는 r-ulybka-* 형태의 패턴)를 전달합니다.

  2. connectionName: "r-ulybka-prod-master"로 execute-command를 호출합니다.

  3. 서버가 ~/.ssh/config에서 별칭을 읽고, 거기서 HostName, User, Port, IdentityFile, ProxyJump를 가져와 연결을 수립하고 명령을 실행합니다.

키는 머신을 떠나지 않습니다: 서버가 파일을 직접 읽고, 대화에는 SSH 구성의 경로만 들어갑니다. IdentityFile이 지정되지 않으면 SSH_AUTH_SOCK의 ssh-agent가 사용됩니다. HostName이 없는 별칭은 ssh가 하는 것처럼 자체 이름으로 연결됩니다.

구성에서 별도의 Host 블록으로 선언된 별칭만 도달 가능합니다. Host * 블록은 기본값을 제공하지만 임의의 이름을 도달 가능한 호스트로 만들지는 않습니다.

별칭 목록을 좁힐 수 있습니다:

"args": [
  "-y", "@perhamm/ssh-mcp-server",
  "--ssh-config-hosts",
  "--allowed-hosts", "r-ulybka-*,*-stage-*",
  "--ssh-config-file", "/home/user/.ssh/config_work"
]

패턴은 *와 ?를 지원합니다. 별칭이 어떤 패턴에도 맞지 않으면 연결이 수립되지 않고 에이전트는 SSH_HOST_NOT_ALLOWED 오류를 받습니다.

안전 모드 및 가드

가드는 서버로 보내기 전에 각 명령을 검사하는 버전 관리된 규칙 세트입니다. 규칙은 guards/default-guards.json에 있으며 저장소와 함께 업데이트됩니다.

프로필

프로필

동작

off

프로필 규칙이 꺼져 있고 금지 코어만 작동. 기본값

safe

파괴적 명령 금지가 추가되고 나머지는 허용

readonly

읽기 및 진단만 허용, safe의 모든 금지를 상속

"args": ["-y", "@perhamm/ssh-mcp-server", "--ssh-config-hosts", "--guards-profile", "safe"]

safe가 코어 이상으로 잡는 것: shutdown 및 reboot, 방화벽 재설정, sshd 및 kubelet 중지, kubectl delete, helm uninstall, docker system prune, 패키지 삭제, DROP DATABASE, curl | sh, git push --force, 로그 정리, 커널 모듈 언로드, 대화형 편집기. 전체 목록과 이유는 JSON에 있습니다.

readonly는 추가로 명령의 각 부분이 화이트리스트에 있어야 합니다: ls, cat, grep, find, ps, ss, df, journalctl, systemctl status, kubectl get/describe/logs, docker ps/logs 등. 이 프로필에서는 sudo가 su, doas, pkexec와 함께 완전히 금지됩니다.

금지 코어

일부 작업은 절대 실행되지 않습니다: off 프로필에서도, sudo 아래에서도, 자체 가드 파일을 통해서도, 명령을 우회하는 SFTP를 통해서도. 목록은 forbidden 블록에 있습니다.

카테고리

차단된 것

계정

useradd, usermod, userdel, groupadd, passwd, chpasswd, chage, vipw 및 /etc/passwd, /etc/shadow, /etc/group 쓰기

sudo

/etc/sudoers 및 /etc/sudoers.d 쓰기, visudo

스케줄

crontab -l을 제외한 crontab, /etc/cron*, /var/spool/cron, /etc/anacrontab 쓰기, at 및 batch 명령

systemd

/etc/systemd, /lib/systemd, /usr/lib/systemd에 유닛 및 타이머 쓰기, systemctl edit, systemd-run

SSH

/etc/ssh/*, ~/.ssh/*, authorized_keys, sshd_config 편집, ssh-keygen, ssh-copy-id, ssh-add

인터프리터

python, perl, ruby, node, php, lua, Rscript 및 파일로 스크립트 실행: bash /tmp/x.sh, sh -s, source. 가드는 남의 코드를 읽지 않으므로 이러한 실행은 완전히 차단됨

대량 삭제

1단계 디렉터리 또는 시스템 하위 디렉터리의 rm -r, 마스크가 있는 rm -r, find -delete, xargs rm을 통한 삭제, --no-preserve-root 플래그

디스크 및 비밀

mkfs, wipefs, dd of=/dev/, /dev/sd* 쓰기, 포크 폭탄, /etc/shadow 및 개인 키 읽기

일반 작업은 그대로 유지됩니다: crontab -l, cat /etc/ssh/sshd_config, systemctl restart nginx, rm -rf /var/lib/myapp/cache/tmp는 통과합니다. 파싱 가능한 bash -c "..."도 작동합니다: 그 내용은 동일한 규칙으로 검사됩니다.

코어는 파일 도구도 차단합니다. download는 /etc/shadow와 ~/.ssh의 내용을 가져가지 않으며 allowedRemotePaths는 여기서 아무것도 되돌려 허용하지 않습니다. 로컬 쪽도 보호됩니다: download는 우리 자신의 ~/.ssh에 파일을 넣지 않습니다.

파일 업로드는 완전히 꺼져 있습니다. --enable-upload가 전달될 때까지 upload 도구는 게시되지 않으며 readonly 프로필은 이 플래그가 있어도 업로드를 거부합니다.

서버가 사용자 생성이나 크론 편집을 위해 정확히 필요한 경우, 코어는 포크에서 의식적으로 편집해야 합니다: 이를 해제하는 플래그는 없습니다.

세미콜론으로 우회할 수 없는 이유

명령은 ;, |, &&, ||, &, 줄바꿈 및 $(...) 치환으로 분할되고 각 부분이 개별적으로 검사됩니다. 따옴표는 파싱 시 고려됩니다. 따라서 ls; rm -rf /는 어떤 프로필에서도 통과하지 않지만 전체 문자열은 허용된 ls로 시작합니다.

래퍼는 검사 전에 제거됩니다: sudo, env, timeout 5, nohup 및 LC_ALL=C 형태의 할당은 명령을 규칙에서 숨기지 않습니다. bash -c "..." 내부의 스크립트는 별도로 파싱되어 동일한 규칙으로 검사됩니다. 명령 길이는 5000자로 제한됩니다.

가드는 에이전트의 실수를 막는 것이지 의도적인 우회를 막는 것이 아닙니다. python -c와 같이 내부에 임의 코드가 있는 인터프리터는 규칙이 파싱할 수 없습니다. 우회가 허용되지 않는 곳에서는 SSH 사용자 자체의 권한을 제한합니다.

규칙 업데이트

규칙을 최신으로 유지하는 세 가지 방법:

  1. 업스트림을 자신의 포크에 병합. 규칙 파일은 version 필드로 버전 관리되며 버전은 list-servers와 거부 메시지에 표시됩니다.

  2. 자신의 파일을 유지하고 --guards-file /etc/ssh-mcp/guards.json으로 지정. 그 규칙이 내장 규칙에 추가되고 버전은 2026.08.19+local-1이 됩니다.

  3. 스케줄에 따라 파일 업데이트:

node scripts/update-guards.js https://example.com/guards.json /etc/ssh-mcp/guards.json

스크립트는 JSON을 검증하고 각 정규식을 컴파일한 다음에만 파일을 교체합니다. 손상된 다운로드는 작동 중인 규칙 세트를 망가뜨리지 않습니다.

자체 파일 형식:

{
  "version": "local-1",
  "profiles": {
    "safe": {
      "deny": [
        { "id": "no-ansible", "pattern": "^ansible-playbook\\b", "reason": "выкат идёт из CI" }
      ]
    }
  }
}

scope: "command" 필드는 규칙이 부분이 아닌 명령 전체를 검사하도록 합니다. curl | sh 및 SQL 규칙이 이렇게 작동합니다. 자체 파일의 forbidden 블록에 자신의 금지를 추가할 수 있지만 내장 금지는 제거할 수 없습니다: 목록이 합쳐집니다.

이전 --whitelist 및 --blacklist는 사라지지 않았으며 가드보다 먼저 검사됩니다.

대화에 sudo 비밀번호 없이

sudo 비밀번호는 서버 프로세스의 환경 변수에 저장됩니다. 에이전트는 sudo: true를 전달하지만, 비밀번호 자체는 호출 인자에도 출력에도 나타나지 않습니다.

{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": ["-y", "@perhamm/ssh-mcp-server", "--ssh-config-hosts", "--guards-profile", "safe"],
      "env": {
        "SSH_MCP_SUDO_PASSWORD": "..."
      }
    }
  }
}

도구 호출:

{
  "tool": "execute-command",
  "params": {
    "cmdString": "systemctl restart nginx",
    "connectionName": "r-ulybka-prod-master",
    "sudo": true
  }
}

명령은 sudo -S -k -p '' -u root -- /bin/sh -c '<명령>' 형태로 서버에 전송되며, 비밀번호는 stdin 채널에 기록됩니다. 명령줄에는 포함되지 않으므로 ps나 히스토리에 남지 않습니다. 이러한 명령에는 의사 터미널이 비활성화됩니다. 그렇지 않으면 tty가 입력을 출력으로 다시 반사할 수 있기 때문입니다. 만일을 대비해 비밀번호는 출력과 오류 메시지에서도 제거됩니다.

변수 이름과 대상 사용자는 --sudo-password-env 및 --sudo-user 플래그로 변경됩니다. 변수가 비어 있으면 연결 전에 SUDO_PASSWORD_MISSING 오류로 호출이 실패합니다. readonly 프로필은 sudo를 완전히 금지합니다.

shell 모드에서는 sudo가 셸과 동일한 stdin을 읽기 때문에 비밀번호가 명령 바로 다음에 별도의 줄로 추가됩니다. -k 플래그는 비밀번호 요청이 항상 발생하고 해당 줄이 명령으로 실행되지 않도록 보장합니다. sudo에는 exec 모드가 더 좋습니다.

터널

open-tunnel은 로컬 리스너를 시작하고 SSH 연결을 통해 트래픽을 전달합니다. 클러스터의 서비스에 직접 접근할 수 없지만 노드에는 접근할 수 있을 때 유용합니다.

포트 8777의 SOCKS5:

{
  "tool": "open-tunnel",
  "params": {
    "type": "socks5",
    "localPort": 8777,
    "connectionName": "r-ulybka-prod-master"
  }
}

이후 모든 클라이언트는 프록시를 통해 통신하며, 이름은 원격 측에서 해석됩니다:

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:8777

ssh -L과 유사한 단일 포트 포워딩:

{
  "tool": "open-tunnel",
  "params": {
    "type": "local",
    "localPort": 15432,
    "remoteHost": "pg-master.internal",
    "remotePort": 5432
  }
}

localPort가 지정되지 않으면 시스템이 포트를 선택하고 응답에 반환합니다. 터널은 close-tunnel 호출, SSH 연결 끊김 또는 서버 중지까지 유지됩니다.

제한 사항은 플래그로 설정됩니다:

플래그

기본값

기능

--tunnel-bind-address

127.0.0.1

터널이 수신 대기하는 주소

--allowed-tunnel-ports

제한 없음

점유할 수 있는 포트 목록

--max-tunnels

8

동시에 유지하는 터널 수

--disable-tunnels

비활성화

터널 도구를 목록에서 제거

리스너는 기본적으로 loopback에서 시작됩니다. loopback보다 넓은 주소는 프록시를 네트워크에 노출시키므로 신중하게 변경해야 합니다.

호스트 키 검증

서버 키는 ProxyJump 체인의 중간 호스트를 포함한 모든 연결에서 known_hosts와 대조됩니다. 기본 모드는 strict이며, 호스트가 known_hosts에 없으면 거부됩니다.

모드

동작

strict

기본값. known_hosts에 있는 호스트에만 연결

accept-new

처음 연결 시 알 수 없는 호스트를 기록하며, 키 불일치는 여전히 거부

off

검증 없음, 업스트림 동작

~/.ssh/known_hosts, ~/.ssh/known_hosts2, /etc/ssh/ssh_known_hosts가 확인되며, UserKnownHostsFile 별칭이 있으면 SSH 구성에 지정된 파일이 사용됩니다. 사용자 정의 목록은 --known-hosts-file 플래그로 설정됩니다. 해시된 항목, 패턴, [host]:port 형식 및 @revoked 마커가 지원됩니다.

거부는 SSH_HOST_KEY_REJECTED 코드와 지문이 포함된 텍스트로 반환됩니다:

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.

키 불일치는 어떤 모드에서도 절대 수락되지 않습니다. 서버는 연결을 거부하고 호스트가 재생성되었거나 중간자 공격이 있을 수 있다고 기록합니다.

새로운 호스트 그룹을 처음 사용할 때는 --host-key-checking accept-new로 한 번 실행한 다음 strict로 되돌리는 것이 편리합니다.

감사 로그

각 호출은 JSON 줄로 기록됩니다: 명령, 연결, sudo 플래그, 가드 판정, 지속 시간, 출력 크기. 출력 내용은 로그에 포함되지 않으며 sudo 비밀번호는 제거됩니다.

{"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}

connect, command, download, upload, tunnel-open, tunnel-close, host-key 이벤트가 기록됩니다.

기본적으로 파일은 $XDG_STATE_HOME/ssh-mcp-server/audit.jsonl, 즉 일반적으로 ~/.local/state/ssh-mcp-server/audit.jsonl에 있으며 권한은 0600입니다.

플래그

기본값

기능

--audit-log <path>

XDG 상태 디렉터리

로그 경로, off 값은 기록 비활성화

--audit-max-size <bytes>

10485760

이 크기에 도달하면 파일이 로테이션됨. 0은 내장 로테이션 비활성화

--audit-keep <count>

10

유지할 gzip 아카이브 수

로테이션은 내장되어 있습니다: 한도에 도달하면 현재 파일이 audit.jsonl.1.gz로 이동하고, 이전 아카이브는 이동되며, --audit-keep 범위를 벗어난 항목은 삭제됩니다. 각각 10MiB인 아카이브 10개는 압축되지 않은 상태로 약 100MB이며 gzip 후에는 훨씬 작아집니다.

로그가 이미 logrotate로 관리되는 경우 --audit-max-size 0을 설정하고 copytruncate 모드로 로테이션을 구성합니다.

기록 오류는 명령을 중단시키지 않습니다: 서버는 stderr에 한 번 기록하고 계속 작동합니다.

연결 방법

아래는 간단한 것부터 복잡한 것까지의 시나리오입니다. args에서 각 플래그와 해당 값은 배열의 두 개별 요소입니다: "--host", "192.168.1.1"이지 "--host 192.168.1.1"이 아닙니다.

로그인 및 비밀번호

{
  "mcpServers": {
    "ssh-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "@perhamm/ssh-mcp-server",
        "--host", "192.168.1.1",
        "--port", "22",
        "--username", "root",
        "--password", "pwd123456"
      ]
    }
  }
}

개인 키

"args": [
  "-y", "@perhamm/ssh-mcp-server",
  "--host", "192.168.1.1",
  "--username", "root",
  "--privateKey", "~/.ssh/id_rsa",
  "--passphrase", "pwd123456"
]

키의 비밀번호는 구성에 작성하는 대신 SSH_MCP_PASSPHRASE 변수에 넣을 수 있습니다.

~/.ssh/config의 별칭 하나

"args": ["-y", "@perhamm/ssh-mcp-server", "--host", "myserver"]

서버는 Host myserver 블록에서 HostName, Port, User, IdentityFile 및 ProxyJump를 읽으며, Include 지시문과 패턴도 포함합니다. 명령줄 플래그가 우선합니다: --port 2222는 구성의 포트를 덮어씁니다.

배스천 및 ProxyJump

별칭에 ProxyJump가 있으면 체인이 자동으로 구성됩니다:

Host r-ulybka-prod-master
    HostName 10.20.30.40
    User ops
    ProxyJump bastion
    IdentityFile ~/.ssh/prod_key

각 다음 홉은 ssh -J처럼 이전 홉의 채널을 통해 연결됩니다. 체인은 수동으로도 지정할 수 있습니다: --proxy-jump "bastion,gateway:2222". 체인 깊이는 5홉으로 제한됩니다.

프록시

"args": [
  "-y", "@perhamm/ssh-mcp-server",
  "--host", "192.168.1.1",
  "--username", "root",
  "--password", "pwd123456",
  "--proxy", "socks5://user:pwd@proxy-host:1080"
]

socks://, socks5://, http:// 및 https://가 지원됩니다. HTTP와 HTTPS는 Basic 인증이 있는 CONNECT 메서드로 작동하며, 기본 포트는 80과 443입니다. SOCKS5에는 포트가 필수입니다. 이전 --socksProxy 플래그는 작동하지만 SOCKS만 허용합니다. --proxy와 --proxy-jump는 함께 사용되지 않습니다.

대화형 셸이 있는 점프 호스트

transportMode의 기본값은 exec입니다. 로그인 성공 후 명령이 실행되지 않거나 장치가 대화형 세션만 제공하는 경우 shell로 전환합니다:

"args": [
  "-y", "@perhamm/ssh-mcp-server",
  "--host", "bastion.example.com",
  "--username", "ops",
  "--password", "pwd123456",
  "--transport-mode", "shell",
  "--shell-ready-timeout", "15000"
]

shell 모드에서는 명령이 하나의 영구 세션을 통해 순차적으로 실행되며, upload와 download는 작동하지 않습니다. SFTP가 비활성화되어 있기 때문입니다.

2단계 인증

--try-keyboard 플래그는 keyboard-interactive를 활성화합니다. 비밀번호와 키는 자동으로 제공되며, 2단계 코드는 SSH_MCP_2FA_CODE 변수에서 읽습니다.

하나의 서버에서 여러 연결

SSH 구성의 별칭 외에도 연결 설명 파일을 사용하는 기존 방식이 있습니다.

[
  {
    "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"]

키가 연결 이름인 객체 형식도 지원됩니다. 연결은 connectionName 매개변수로 선택되며, 지정하지 않으면 첫 번째가 사용됩니다.

명령 및 경로 제한

화이트리스트 및 블랙리스트

"args": [
  "-y", "@perhamm/ssh-mcp-server",
  "--host", "192.168.1.1",
  "--username", "root",
  "--privateKey", "~/.ssh/id_rsa",
  "--whitelist", "^ls( .*)?,^cat .*,^df.*",
  "--blacklist", "^rm .*,^shutdown.*"
]

패턴은 쉼표로 구분된 정규식입니다. 명령은 먼저 화이트리스트, 그다음 블랙리스트, 그다음 가드 프로필로 확인되며 세 가지 검사를 모두 통과해야 합니다.

명령 템플릿

--command-template은 각 명령을 래핑합니다. <quotedCommand>는 명령을 이스케이프된 인수로 대체하고, <command>는 그대로 삽입합니다. 템플릿은 작업 디렉터리 대체 후 적용됩니다.

su root -c <quotedCommand>
docker exec -i mycontainer sh -c <quotedCommand>

파일 작업 경로

--allowed-local-paths는 upload 및 download에 사용할 수 있는 로컬 디렉터리 목록을 확장합니다(기본적으로 현재 디렉터리만). --allowed-remote-paths는 원격 경로를 제한하며, 쉼표로 구분된 절대 POSIX 경로를 작성합니다. 이 플래그가 없으면 SFTP는 호스트의 전체 파일 시스템을 볼 수 있으며, 서버는 시작 시 이에 대해 경고합니다.

타임아웃 및 출력 제한

매개변수

기본값

제한 대상

도구 호출의 timeout

없음

단일 명령, 연결 설정을 덮어씀

commandTimeoutMs

30000

exec 모드의 명령

shellCommandTimeoutMs

30000

shell 모드의 명령

connectionTimeoutMs

30000

연결 설정 및 핸드셰이크

sftpTimeoutMs

300000

SFTP 작업

maxOutputBytes

10485760

단일 명령의 캡처된 출력

keepaliveIntervalMs

10000

keepalive 간격

출력 한도를 초과하면 명령이 중단되고 도구는 이미 수집된 부분과 함께 OUTPUT_LIMIT_EXCEEDED를 반환합니다. 오류는 code, message 및 retriable 구조로 반환됩니다.

명령줄 플래그

  --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                           Справка

보안

  • 프로덕션에서는 --guards-profile safe를 활성화하고, 인시던트 대응 분석에는 readonly가 적합합니다. off를 사용하면 금지된 핵심만 남고 나머지는 모두 실행되며, 서버는 로그에 경고를 기록합니다.

  • 키, 키 비밀번호 및 sudo 비밀번호는 파일과 환경 변수에서 읽습니다. MCP 클라이언트 구성에는 키 자체가 아닌 키 경로를 저장합니다.

  • 터널은 loopback에서 수신 대기합니다. SOCKS5에는 인증이 없으므로 0.0.0.0의 프록시는 포트에 도달할 수 있는 모든 사람에게 내부 네트워크를 노출하며, 서버는 시작 시 이에 대해 경고합니다.

  • --allowed-remote-paths가 없으면 SFTP를 통해 호스트의 모든 경로를 읽고 쓸 수 있으며, ~/.ssh/authorized_keys도 포함됩니다.

  • 호스트 키는 strict 모드에서 known_hosts와 대조됩니다. --host-key-checking off로 검증을 해제하는 것은 실험실에서만 해야 합니다.

  • 호출 빈도 제한은 없습니다.

개발

npm install
npm run build
npm test

테스트는 Node.js 내장 러너로 실행되며 test/에 있습니다.

업스트림 및 라이선스

프로젝트는 classfang/ssh-mcp-server(저자 junki.cn)에서 파생되었으며, ISC 라이선스입니다. 업스트림 저작권은 LICENSE에 보존되어 있으며, 원본 저장소 링크도 있습니다.

가드 세트는 부분적으로 tufantunc/ssh-mcp(MIT)의 아이디어를 기반으로 구성되었습니다.

NPM 패키지: @perhamm/ssh-mcp-server.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    F
    maintenance
    An MCP server that allows AI models to execute system commands on local machines or remote hosts via SSH, supporting persistent sessions and environment variables.
    1
    9 npm
    28
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    An 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
  • A
    license
    A
    quality
    B
    maintenance
    MCP server for managing multiple SSH servers via AI assistants, offering tools for remote command execution, file operations, and system monitoring.
    11
    71 PyPI
    2
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    An MCP server that gives AI agents SSH capabilities to execute commands, transfer files, and inspect remote systems through a preconfigured host list.
    33 npm
    MIT