SSH MCP Server

공식

SSH를 통해 에이전트에서 명령 실행, 파일 이동, 로그 검색 및 머신 감사를 수행합니다.

SSH MCP(으)로 무엇을 할 수 있나요?

  • 안전 가드레일로 명령 실행 — 어시스턴트가 ssh_exec를 통해 단일 또는 배치 명령을 실행하도록 요청하고, 서버에 도달하기 전에 되돌릴 수 없는 작업을 차단하는 파괴적 명령 보호 기능을 제공합니다.
  • 원격 파일 읽기, 쓰기, 나열ssh_file_read, ssh_file_write, ssh_file_list를 사용하여 파일을 검사하거나 수정하며, 원자적 쓰기와 선택적 SHA-256 검증을 지원합니다.
  • 로그 검색 및 서버 상태 확인 — 파일과 컨테이너 전반에 걸쳐 ssh_log_search 또는 ssh_log_tail을 쿼리하거나, ssh_snapshotssh_audit_baseline으로 구조화된 상태 스냅샷을 얻습니다.
  • 무결성 검사로 파일 전송ssh_uploadssh_download를 통해 파일과 디렉터리를 업로드하거나 다운로드하며, 구형 장치를 위한 자동 레거시 scp 대체 기능을 제공합니다.
  • 장기 실행 백그라운드 작업 관리 — 느린 작업을 ssh_exec로 분리하고 ssh_job_status, ssh_job_output, ssh_job_kill로 추적하며, 연결이 끊겨도 유지됩니다.

문서

SSH MCP Server — AI 에이전트를 위한 원격 서버 도구

SSH MCP Server

SSH MCP 서버 — 디버깅, 개발, 서버 유지보수에 드는 시간과 토큰을 아껴주는 멀티툴입니다.

SSH를 통해 명령 실행, 파일 이동, 로그 확인, 머신 감사 — 클라우드 VPS, 베어메탈 박스, 또는 벽장에 있는 BusyBox 라우터까지.

이미 시스템에 있는 OpenSSH 클라이언트를 사용합니다: 여러분의 키, ~/.ssh/config, 점프 호스트, 에이전트 포워딩. 번들된 것도, 컴파일할 것도, 네이티브 바인딩도 없습니다.

Claude Code, Codex CLI, Cline, opencode, Gemini CLI, Qwen Code, Hermes 및 기타 MCP 클라이언트와 호환됩니다.

MCP Registry Glama Smithery npm downloads tests

설치 · 도구 · 설정 · 보안 · 로드맵 · 문서 · 변경 로그


30초 만에 설치

전역 설치가 필요 없습니다. npx가 첫 사용 시 패키지를 다운로드합니다:

npx -y @hypnosis/ssh-mcp-server

MCP 클라이언트에 추가하세요 — 예를 들어 Claude Code — 모든 프로젝트에 적용됩니다:

claude mcp add ssh -s user \
  -e SSH_PROFILES_FILE="$HOME/.claude/ssh-profiles.json" \
  -- npx -y @hypnosis/ssh-mcp-server

또는 직접 작성하세요 — 대부분의 클라이언트가 공유하는 구성 형식의 동일한 서버입니다:

{
  "mcpServers": {
    "ssh": {
      "command": "npx",
      "args": ["-y", "@hypnosis/ssh-mcp-server"],
      "env": {
        "SSH_PROFILES_FILE": "~/.claude/ssh-profiles.json"
      }
    }
  }
}

그런 다음 최소 하나의 머신이 포함된 ~/.claude/ssh-profiles.json을 생성하세요:

{
  "profiles": {
    "production": {
      "host": "server.example.com",
      "username": "admin",
      "privateKeyPath": "~/.ssh/your_private_key"
    }
  }
}

이것으로 연결하기에 충분합니다.

Codex, opencode, Qwen Code 및 기타 클라이언트는 SSH MCP 서버 설정에서 다룹니다.

플러그인으로 설치

일부 클라이언트 — 예를 들어 Claude Code — 전체를 플러그인으로 사용할 수 있습니다:

/plugin marketplace add hypnosis/ssh-mcp-server
/plugin install ssh-mcp-server@ssh-mcp-server

플러그인은 SSH_PROFILES_FILE가 달리 지정하지 않는 한 ~/.claude/ssh-profiles.json을 읽으므로, 해당 파일을 먼저 생성하면 서버가 머신을 이미 로드한 상태로 시작됩니다.

요구 사항

npm version Node.js TypeScript MCP SDK

Node.js 18+PATH의 시스템 ssh 클라이언트. Windows에서는 키 기반 프로필을 사용하세요; 비밀번호 및 패스프레이즈 프로필은 현재 사용할 수 없습니다.

고정 버전 선호, 오프라인 작업, 또는 실행 시 레지스트리 확인을 한 번 줄이려면: npm install -g @hypnosis/ssh-mcp-server, 그런 다음 npx 대신 ssh-mcp-server을 명령으로 사용하세요.

대상 사용자

  • DevOps 및 SRE — 더 빠른 감사, 장애 확인, 일상적인 서버 작업을 원하는 분.
  • 바이브 코더 및 인디 빌더 — AI 어시스턴트와 함께 배포하고 자신의 서버에서 실행하는 분.
  • 시스템 관리자 및 플랫폼 엔지니어 — 제한 없는 원시 셸 대신 구조화된 도구를 원하는 분.
  • 전담 운영 팀 없이 자체 VPS를 운영하는 개발자 및 소규모 팀.
  • 홈랩, NAS 및 라우터 소유자 — 현대 프로토콜보다 오래 살아남은 유용한 하드웨어를 가진 분.

원시 셸 대신 SSH MCP 서버를 사용하는 이유

더 적은 토큰, 더 낮은 AI 비용

원시 셸은 AI 에이전트에게 홍수 같은 출력을 제공합니다: 반복 명령, ASCII 테이블, 로그 덤프. 그 노이즈를 서버 상태로 변환하는 데 토큰이 소모됩니다 — 여러분의 비용으로.

더 빠른 서버 디버깅

목적에 맞는 도구는 일상적인 확인을 일괄 처리하고, 시끄러운 출력을 제한하며, 중요한 부분만 반환합니다. 에이전트는 터미널 출력을 해석하는 데 시간을 덜 쓰고 더 빨리 수정에 도달합니다.

더 적은 추측, 더 적은 AI 실수

구조화된 답변은 무엇이 발견되었는지, 무엇을 측정할 수 없었는지, 무엇이 잘렸는지 말해줍니다. 이는 에이전트가 환각으로 빈틈을 메울 여지를 줄이고 — 더 적은 잘못된 수정, 더 차분한 배포, 더 안정적인 코드를 제공합니다.

SSH 호환성: 현대 서버, 레거시 장비 및 Windows

기존 OpenSSH 설정 사용

번들 SSH 구현도, 네이티브 바인딩도, 플랫폼별 재빌드도 없습니다. 명령은 시스템 ssh 클라이언트를 사용하므로, 여러분의 키, ~/.ssh/config, 점프 호스트 및 에이전트 포워딩이 터미널에서와 똑같이 작동합니다. 지원되는 경우, 대상별 공유 멀티플렉스 연결로 명령마다 인증하는 대신 한 번만 인증합니다.

레거시 서버, 라우터 및 NAS 장치용 SSH 지원

현대 scp을 사용하는 라우터에 파일을 보내면 다음과 같은 결과가 나옵니다:

scp app.conf router:/etc/
# scp: subsystem request failed on channel 0

아무것도 고장난 것이 아닙니다 — 현재 scp은 새 프로토콜을 말하지만 라우터는 그것을 모릅니다. 터미널에서는 포럼 스레드를 읽고 추가 플래그를 가지고 돌아와야 합니다. 여기서는 아무것도 할 필요가 없습니다: 전송이 시도되고, 거부가 인식되며, 이전 프로토콜이 대신 사용되고, 해당 머신이 기억되어 다음 파일은 바로 전송됩니다.

이전 SSH 클라이언트 및 누락된 도구에 대한 폴백

오래된 장비는 막다른 길이 아닌 폴백을 얻습니다. 현대 기능이 없으면 서버는 가능한 경우 이전 경로를 사용합니다:

여러분의 머신제공되는 기능
현대 파일 전송에 너무 작은 라우터 또는 NAS파일은 여전히 도착합니다 — 이전 프로토콜이 자동으로 사용됩니다
10년 된 서버워크플로는 여전히 작동합니다; 명령마다 새 연결을 여는 대신 재사용합니다
파일 해시 방법이 없는 축소된 이미지업로드는 "확인할 수 없음"이라고 말합니다 — 아무도 확인하지 않은 일치를 주장하지 않습니다
도구가 설치되지 않은 박스답변은 "측정되지 않음"이라고 말합니다 — "아무것도 없음"으로 읽히는 0이 아닙니다

Model Context Protocol을 위해 설계됨

공식 MCP SDK 기반, 전체 TypeScript, 2500개 이상의 단위 테스트와 실제 컨테이너에서 실행되는 라이브 테스트 스위트.


원시 SSH vs SSH MCP 서버: 같은 작업, 두 가지 방식

SSH 서버 상태 확인

상황: 배포가 방금 나갔습니다. 서버가 느리고, 디스크, 메모리, 서비스, 컨테이너 또는 오류 중 무엇이 원인인지 모릅니다.

질문: "이 박스가 정상인가요?"

원시 SSH

$ uptime
 10:42:17 up 18 days,  3:21,  2 users,  load average: 0.42, 0.31, 0.28
$ df -hT
Filesystem     Type   Size  Used Avail Use% Mounted on
/dev/sda1      ext4    40G   35G  5.0G  87% /
overlay        overlay  40G   35G  5.0G  87% /var/lib/docker/overlay2/...
$ free -h
               total        used        free      shared  buff/cache   available
Mem:           7.7Gi       4.9Gi       612Mi       121Mi       2.2Gi       2.5Gi
$ systemctl --failed
  UNIT              LOAD   ACTIVE SUB    DESCRIPTION
● api-worker.service loaded failed failed API background worker
$ docker ps -a
CONTAINER ID   IMAGE          STATUS                     PORTS
8e14d0b41c2a   api:latest     Up 3 minutes               0.0.0.0:8080->8080/tcp
65b894af2430   worker:latest  Exited (1) 2 minutes ago
$ ss -tulpn
Netid  State   Local Address:Port   Process
tcp    LISTEN  0.0.0.0:22          users:(("sshd",pid=842,fd=3))
tcp    LISTEN  0.0.0.0:8080        users:(("docker-proxy",pid=1942,fd=4))
$ journalctl -p err --since -1h | tail -50
Aug 20 10:39:14 prod api-worker[22104]: database connection timed out
Aug 20 10:39:14 prod systemd[1]: api-worker.service: Failed with result 'exit-code'.

이것도 여전히 축약된 결과입니다. 완전한 확인은 CPU, 서비스 상태, 컨테이너 수 및 최근 오류에 대한 더 많은 명령이 필요하며, 각각 고유한 출력 형식이 있습니다. 더 나쁜 것은, ss가 없는 박스는 포트 확인이 실행되지 않았을 때 리스너가 0개인 것처럼 보일 수 있습니다.

구조화된 MCP 결과

ssh_snapshot({ "profile": "production" })
{
  "disk_pct": 87,
  "mem_pct": 64,
  "cpu_pct": 12,
  "load": "0.42 0.31 0.28",
  "containers": 7,
  "ports": 14,
  "services_running": 3,
  "recent_errors": 21,
  "unavailable": []
}

에이전트가 얻는 이점

원시 SSH구조화된 MCP여러분의 이점
여러 명령과 ASCII 테이블하나의 결과에 명명된 필드한 번의 호출, 명명된 필드, 더 적은 왕복
누락된 도구가 빈 출력처럼 보일 수 있음unavailable이 측정되지 않은 것을 명명더 적은 추측과 더 적은 잘못된 수정
디스크, 서비스, 오류를 직접 분류문제 신호가 이미 표면화됨더 빠른 디버깅

전체 ssh_audit_baseline 결과는 소수의 원시 명령 출력보다 길 수 있습니다 — 실험실 측정에서 약 1,077 토큰 대 765 토큰. 절약은 하나의 응답을 짧게 만드는 것이 아니라 전체 워크플로에서 나옵니다.

실제 문제 해결 세션에서 목적에 맞는 도구는 49개의 개별 명령 호출을 4개의 MCP 호출로 줄였습니다. 추가 호출마다 누적된 대화로 새 모델 턴이 시작됩니다. 프롬프트 캐싱은 반복 입력 비용을 줄일 수 있지만, 새 명령과 그 출력은 여전히 컨텍스트를 소비합니다. 더 적은 왕복은 세션 전체에서 더 적은 토큰, 더 적은 반복 분석, 더 빠른 답변 경로를 의미합니다.

전체 그림이 필요하신가요? ssh_audit_baseline는 시스템, 디스크, 메모리, 포트, sshd, 실패한 유닛, Docker, 방화벽 및 업데이트를 일괄 처리합니다. 결과는 CRITICAL / WARNING / OK로 도착합니다; 측정되지 않은 섹션은 조용히 0으로 읽히는 대신 명명됩니다.

Linux 서버 로그 검색

상황: API가 타임아웃되고 있지만, 같은 메시지가 nginx, syslog, journald 또는 일반 사용자로 읽을 수 없는 애플리케이션 로그에 있을 수 있습니다.

질문: "그 오류는 어디서 왔나요?"

원시 SSH

$ grep -i "timeout" /var/log/nginx/error.log
2026/08/20 10:38:54 [error] upstream timed out while reading response header
$ grep -i "timeout" /var/log/syslog
Aug 20 10:39:14 prod api-worker[22104]: database connection timed out
$ grep -i "timeout" /var/log/app/*.log 2>/dev/null
$ journalctl -u api --since "1 hour ago" | grep -i timeout
Aug 20 10:39:14 prod api[22104]: database connection timed out after 30000ms

세 번째 명령은 깨끗해 보이지만, 2>/dev/null도 권한 오류를 숨겼습니다. "일치 없음"과 "읽히지 않음"이 이제 동일해 보입니다. 바쁜 로그는 수천 줄을 반환하여 에이전트의 컨텍스트에서 나머지 사고를 밀어낼 수 있습니다.

구조화된 MCP 결과

ssh_log_search({ "profile": "production",
                 "path": ["/var/log/nginx/error.log", "/var/log/syslog", "/var/log/app/*.log"],
                 "query": "timeout", "context": 2, "since": "1h" })
{
  "matches": 34,
  "lines": [
    { "file": "/var/log/nginx/error.log", "line": 4821,
      "text": "upstream timed out while reading response header", "context": false },
    { "file": "/var/log/nginx/error.log", "line": 4822,
      "text": "client closed connection", "context": true }
  ],
  "files_searched": 6,
  "files_unreadable": ["/var/log/app/private"],
  "files_skipped": 12,
  "files_undated": [],
  "limited": false,
  "truncated": false
}

에이전트가 얻는 이점

원시 SSH구조화된 MCP여러분의 이점
네 번의 검색과 네 개의 출력파일과 글로브에 걸친 한 번의 검색더 적은 토큰과 왕복
권한 오류가 사라질 수 있음files_unreadable이 모든 놓친 경로를 명명거짓 "로그가 깨끗함" 결론 없음
출력이 유용한 상한 없이 커질 수 있음limitedtruncated가 모든 잘림을 노출부분 결과에서 더 안전한 결정

since은 서버의 시계를 사용하고, namesOnly: true은 일치하는 경로만 반환하며, ssh_log_tail는 한 번의 호출로 여러 로그에서 마지막 N줄을 읽습니다.

안전한 원격 구성 편집

상황: 라이브 서버에서 nginx 구성을 교체해야 합니다. 연결 끊김, 잘못된 모드 또는 확인되지 않은 복사는 서비스를 손상된 파일로 남길 수 있습니다.

질문: "부분 파일을 남기지 않고 이 구성을 교체할 수 있나요?"

원시 SSH

$ sudo sh -c 'cat > /etc/nginx/conf.d/api.conf' <<'EOF'
server {
    listen 80;
    location / { proxy_pass http://127.0.0.1:8080; }
}
EOF
$ echo $?
0

종료 코드 0은 셸이 완료되었음을 의미합니다. 어떤 바이트가 도착했는지 증명하지 않으며, >은 새 파일의 첫 바이트가 도착하기 전에 이전 파일을 잘라냅니다. 쓰기 중 연결이 끊기면 서비스는 부분 구성으로 남습니다.

구조화된 MCP 결과

ssh_file_write({ "profile": "production",
                 "files": [{ "path": "/etc/nginx/conf.d/api.conf",
                             "content": "server {\n    listen 80;\n    location / { proxy_pass http://127.0.0.1:8080; }\n}\n",
                             "mode": "644", "sudo": true, "verify": true }] })
{
  "files": [{ "path": "/etc/nginx/conf.d/api.conf", "written": true,
              "verified": "verified", "reason": null, "bytes": 79 }]
}

에이전트가 얻는 이점

원시 SSH구조화된 MCP여러분의 이점
복사가 완료되기 전에 대상이 잘림완전한 임시 파일이 한 번의 이름 변경으로 교체반쯤 쓰인 구성 없음
종료 코드만바이트와 검증 결과가 명명됨실제로 무엇이 도착했는지 알 수 있음
권한이 셸 텍스트 안에 있음sudo, modeverify은 파일별 필드예측 가능한 소유권과 더 적은 인용 실수

verified에는 세 가지 정직한 결과가 있습니다: verified, 서버에 해시 도구가 없을 때 unavailable, 검증이 요청되지 않았을 때 skipped. 읽기의 경우 ssh_file_read은 경로 목록을 허용합니다; ssh_file_list는 글로브, 재귀, 크기 및 모드를 처리합니다.

sudo로 배치 SSH 명령 실행

상황: 배포가 준비되었지만, 트래픽을 이동하기 전에 nginx 구문, 서비스 상태 및 최근 오류를 모두 확인해야 합니다. 하나의 실패한 확인이 결합된 덤프 안에서 사라지지 않아야 합니다.

질문: "모든 사전 점검이 통과했나요?"

원시 SSH

$ ssh admin@server.example.com 'sudo nginx -t'
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ ssh admin@server.example.com 'sudo systemctl is-active nginx'
active
$ ssh admin@server.example.com 'sudo tail -5 /var/log/nginx/error.log'
2026/08/20 10:38:54 [error] upstream timed out while reading response header

세 개의 연결이 세 개의 관련 없는 출력을 반환합니다. 명령이 ;으로 결합되면 셸은 마지막 종료 코드만 보고합니다; &&으로 결합되면 첫 번째 실패 후 이후 확인이 사라집니다.

구조화된 MCP 결과

ssh_exec({ "profile": "production",
           "command": ["nginx -t", "systemctl is-active nginx",
                       "tail -5 /var/log/nginx/error.log"],
           "sudo": true })
{
  "commands": [
    { "command": "nginx -t", "exit_code": 0, "truncated": false, "clipped_bytes": 0,
      "stdout": "", "stderr": "nginx: configuration file /etc/nginx/nginx.conf test is successful\n" },
    { "command": "systemctl is-active nginx", "exit_code": 0, "truncated": false,
      "clipped_bytes": 0, "stdout": "active\n", "stderr": "" },
    { "command": "tail -5 /var/log/nginx/error.log", "exit_code": 0, "truncated": false,
      "clipped_bytes": 0, "stdout": "2026/08/21 09:14:02 [error] upstream timed out\n", "stderr": "" }
  ],
  "job_id": null
}

에이전트가 얻는 이점

원시 SSH구조화된 MCP여러분의 이점
세 번의 호출과 관련 없는 출력하나의 순서 있는 명령 목록더 적은 왕복
결합된 셸이 중간 상태를 숨길 수 있음모든 명령이 자체 exit_code를 유지놓친 실패 확인 없음
sudo과 인용이 명령 텍스트에 반복됨sudo이 전체 배치에 적용더 적은 인용 실수

파괴적 명령 가드는 첫 번째 명령이 실행되기 전에 전체 목록을 확인합니다. 하나의 항목이 거부되면 다른 모든 항목은 실행되지 않은 것으로 표시되고 서버로 아무것도 전송되지 않습니다. 각 명령은 고유한 stdoutstderr를 지닙니다. 실행되어 아무것도 출력하지 않은 명령은 빈 문자열을 가지며, 실행되지 않은 명령은 해당 필드가 아예 없으므로 둘을 혼동할 수 없습니다. 명령당 128KB를 초과하는 출력은 양쪽 끝을 모두 유지합니다 — 표를 위한 앞부분과 로그를 위한 뒷부분 — 사이에 잘린 양을 명시하는 이음새가 있으며, clipped_bytes는 얼마나 잘렸는지 알려줍니다. 잘림은 바이트 경계에서 발생하며 문자 가장자리로 되돌아가므로, 잘린 답변에는 대체 표시가 포함되지 않습니다.

sudo는 터미널 없이 서버에 도달합니다: 프로필의 답변은 표준 입력으로 sudo에 전달됩니다. 어떤 비밀이 사용되는지는 프로필이 하나를 지정할 때 sudoPassword에서, 그 외에는 password에서 결정됩니다 — 키로 로그인하는 프로필은 로그인 비밀번호가 전혀 없으며, 시스템이 둘을 구분하는 경우 로그인 비밀번호는 잘못된 답변입니다. 답변할 것이 없을 때는 sudo의 -S 및 askpass 헬퍼에 대한 조언을 남기는 대신, 답변이 그 사실을 알리고 해결 방법을 제시합니다. 자체 표준 입력을 읽는 명령에는 비밀번호가 절대 제공되지 않으며, 그렇지 않으면 데이터에 섞여 들어갈 수 있습니다.

장기 실행 SSH 작업 실행

상황: 백업 또는 마이그레이션이 에이전트 세션보다 오래 실행됩니다. 연결이 닫힐 수 있지만, 나중에 상태, 출력 및 종료 코드가 여전히 필요합니다.

질문: "이 작업이 대화 중에도 유지됩니까?"

원시 SSH

$ ssh admin@server.example.com 'pg_dump app | gzip > /srv/backups/app.sql.gz'
client_loop: send disconnect: Broken pipe

터미널이 사라졌습니다. 이제 다시 연결하고, 프로세스를 찾고, 대상 파일을 검사하고 백업이 완료되었는지 중간에 중단되었는지 추측해야 합니다.

구조화된 MCP 결과

ssh_exec({ "profile": "production",
           "command": "pg_dump app | gzip > /srv/backups/app.sql.gz",
           "detach": true })
{
  "commands": [{
    "command": "pg_dump app | gzip > /srv/backups/app.sql.gz",
    "exit_code": null,
    "truncated": false,
    "timed_out": false,
    "blocked": false,
    "blocked_reason": null,
    "not_run": false,
    "warning": null
  }],
  "job_id": "mst0f2q1-9ab3c4d5"
}

에이전트가 얻는 이점

원시 SSH구조화된 MCP얻는 이점
작업이 하나의 SSH 세션에 묶여 있음원격 작업에 영구 ID가 있음안전한 연결 끊김 및 재시작
다시 연결하면 프로세스와 파일을 검색해야 함상태와 종료 코드에 명명된 상태가 있음완료 여부를 추측할 필요 없음
출력을 다시 읽으면 이전 텍스트가 반복됨출력이 바이트 오프셋에서 계속됨긴 작업에서 토큰 사용량 감소

작업 상태는 이 서버의 메모리가 아닌 원격 디스크에 저장됩니다. ssh_job_statusrunning, finishedlost를 구분하며, ssh_job_output는 마지막 바이트 오프셋에서 계속되고, ssh_job_kill는 셸뿐만 아니라 전체 프로세스 그룹에 신호를 보냅니다.

레거시 라우터 및 NAS 장치로 파일 전송

상황: 최신 OpenSSH 클라이언트가 SFTP를 시도하지만, 라우터나 NAS가 기존 scp 프로토콜만 이해합니다. 파일은 여전히 온전히 도착하고 대상을 안전하게 교체해야 합니다.

질문: "이 오래된 장치가 여전히 검증된 파일을 받을 수 있습니까?"

원시 SSH

$ scp app.conf operator@router:/etc/app.conf
subsystem request failed on channel 0
scp: Connection closed

일반적인 다음 단계는 레거시 플래그를 기억하고, 복사를 재시도한 다음 별도의 해시 명령을 실행하는 것입니다 — 장치에 해시 도구가 전혀 없는 경우에도 마찬가지입니다.

구조화된 MCP 결과

ssh_upload({ "profile": "router", "local_path": "./app.conf",
             "remote_path": "/etc/app.conf", "sudo": true,
             "mode": "644", "owner": "root:root", "verify": true })
{
  "files": [{
    "path": "/etc/app.conf",
    "written": true,
    "verified": "verified",
    "reason": null,
    "bytes": 1284
  }]
}

에이전트가 얻는 이점

원시 SSH구조화된 MCP얻는 이점
최신 SFTP 모드는 첫 오류에서 중단됨기존 scp 폴백이 자동으로 기억됨오래된 장비도 계속 작동
성공적인 복사가 무결성을 증명하지 않음SHA-256 검증에 명명된 결과가 있음손상이 성공으로 오인되지 않음
직접 교체는 부분 대상을 남길 수 있음전송 후 임시 파일이 제자리로 이동됨작업 파일이 중단에서 살아남음

장치에 sha256sumopenssl도 없는 경우, 결과는 unavailable를 말하고 거짓 일치를 보고하는 대신 이유를 제시합니다. 전체 디렉토리는 recursive: true를 사용하고 한 번에 해시를 검증합니다.

AI 에이전트를 위한 파괴적 명령 보호

가드는 SSH에 명령이 도달하기 전에 로컬에서 실행됩니다. 복구 가능한 작업과 데이터를 보유한 컨테이너를 파괴하는 작업을 구분하며, 체인 및 배치 내부의 명령 순서를 확인합니다.

파괴적 체인이 시작되기 전에 중지

안전한 백업 및 교체 시퀀스:

cp -r /srv/app /srv/app.bak && mv /srv/app /srv/app-old && rm -rf /srv/app

잘못된 순서의 동일한 작업:

rm -rf /srv/app && cp -r /srv/app /srv/app.bak && mv /srv/app /srv/app-old
# REFUSED before the first command runs

셸은 디렉토리를 삭제한 다음에야 백업 소스가 사라졌음을 발견할 것입니다. 가드는 이후 단계가 이전 단계에서 이미 파괴된 대상을 읽는 것을 감지하므로, 전체 호출이 사용자 머신에 유지됩니다. 동일한 검사가 dropdb app && pg_dump app > backup.sql도 포착합니다.

되돌릴 수 없는 손실 거부, 복구 가능한 변경 경고

거부됨 — 컨테이너 자체경고만 — 그 내용물
DROP DATABASE, dropdbDROP TABLE, TRUNCATE, DELETE FROM
docker volume rm, docker compose down -vdocker rm -f <name>
crontab -r하나의 작업 편집
mkfs, wipefs -a, lvremove, zfs destroychmod 777
reboot, shutdown, haltgit reset --hard

docker compose down -v-v가 명명된 Docker 볼륨(데이터베이스 볼륨 포함)을 제거하기 때문에 거부됩니다. -v 없이 서비스를 중지하는 것은 동일한 되돌릴 수 없는 작업으로 취급되지 않습니다.

파일 시스템 루트, 홈 디렉토리 또는 /etc, /var/usr과 같은 시스템 트리의 재귀적 삭제도 거부되며, 심볼릭 링크가 그곳으로 연결되는 경우도 포함됩니다. rm -rf "$DIR"/*과 같은 확인되지 않은 대상도 거부됩니다: "확인할 수 없음"은 "안전함"으로 취급되지 않습니다.

중지할 대상을 명명

대상을 찾는 대신 명명하는 명령은 전송되지 않습니다. 서버는 이를 확장하고 대상 뒤에 무엇이 있는지 답변합니다:

docker kill $(docker ps -q --filter ancestor=web)
# BLOCKED — would stop:
#   edge — web:latest, Up 34 days, 0.0.0.0:8443->8443/tcp

프로세스의 경우 답변은 사용 중임을 나타내는 신호를 추가합니다: 실행 시간, 연결을 수락하는 포트, 전달 중인 연결 수. 명명된 대상은 추가 비용 없이 조용히 통과합니다 — docker kill web-1, kill 4871, systemctl stop app.

계속하려면 중지할 대상을 명명하세요. 이름은 명령이 실제로 도달하는 대상과 대조 확인되므로, 다른 것으로 이동한 마스크는 확인 대신 거부됩니다:

docker kill $(docker ps -q --filter ancestor=web) # CONFIRMED-KILL: edge

명령줄에 대한 패턴은 별도의 경우입니다. 이를 전달하는 명령 자체와 일치하므로, 실행 중인 셸이 대상보다 먼저 신호를 받고 답변이 중간에 끊깁니다. 이러한 공격은 확인되지 않고 다시 작성됩니다 — 번호로, 또는 패턴이 자신과 일치하지 않도록 한 문자를 클래스로 작성하여:

pkill -f relay
# BLOCKED — two ways through:
#   kill 4871
#   pkill -f '[r]elay' # CONFIRMED-KILL: 4871

세 가지 결과는 구분됩니다: 대상을 찾음, 확장이 아무것도 도달하지 못함, 물어볼 것이 없음 — 머신에 엔진 없음, 잘린 답변, 실패한 연결. 마지막 두 가지도 거부입니다: 모르는 것이 진행 이유가 될 수 없습니다.

의도적인 파괴 명령 확인

영구적으로 금지된 것은 없습니다. 검토된 명령에 # CONFIRMED-DESTRUCTIVE를 추가하면 허용됩니다. 가드가 배치에서 하나의 항목을 거부하면, 전체 배치가 실행 전에 중지되므로 서버는 절반 실행된 작업 후에 남지 않습니다.

가드는 단일 호출 내에서 작동합니다. 한 호출의 삭제를 다음 호출의 읽기와 연결하거나, 인식하지 못하는 도구에 대해 추론할 수 없습니다. 안전벨트이지 정책 엔진이 아닙니다: 복구 가능한 작업은 여전히 사용자의 결정입니다. 경로 제한 및 따옴표 규칙은 **docs/security.md**에 문서화되어 있습니다.

도구

서버 운영을 위한 18개의 SSH MCP 도구. 전체 매개변수와 예제는 **docs/tools.md**에 있습니다.

도구기능
ssh_exec파괴적 명령 가드 및 선택적 분리와 함께 하나 또는 여러 명령 실행
ssh_file_read하나 또는 여러 파일 읽기, 텍스트 또는 바이너리
ssh_file_write원자적 이름 변경 및 선택적 SHA-256 검증으로 파일 쓰기
ssh_file_list선택적 글로브 및 재귀와 함께 디렉토리 나열
ssh_uploadSSH를 통한 파일 또는 디렉토리 업로드, 무결성 검사가 있는 바이너리 안전; 디렉토리는 대상을 교체하거나 병합
ssh_downloadSSH를 통한 파일 또는 디렉토리 다운로드, 무결성 검사가 있는 바이너리 안전
ssh_job_status백그라운드 작업 상태: 실행 중, 완료 또는 손실
ssh_job_output바이트 오프셋에서 누적 출력 읽기
ssh_job_list작업 나열, TTL을 지난 완료 작업 정리
ssh_job_kill작업의 전체 프로세스 그룹에 신호 보내기
ssh_log_tail하나 또는 여러 로그의 마지막 N줄, 글로브 지원; 이름으로 컨테이너
ssh_log_search로그 또는 컨테이너 로그를 통한 패턴 검색
ssh_snapshot일회성 상태 스냅샷: 서비스, 리소스, Docker, 네트워크, 오류
ssh_monitor전송 제어: 통계, 재로드, 테스트, 목록, 닫기
ssh_audit_baseline시스템, 디스크, 메모리, 네트워크, ssh, 서비스, Docker, 방화벽, 업데이트
ssh_tls_check도메인에 대한 인증서 만료, SAN, 체인 및 갱신 후크
ssh_disk_breakdown디스크가 어디로 갔는지: du 상위 N개, Docker, journald, 캐시
ssh_service_status하나의 유닛에 대한 systemctl statusjournalctl 꼬리

MCP 도구 안전 주석

표준 MCP 주석은 클라이언트에게 어떤 도구가 읽기 전용, 파괴적, 멱등적 또는 개방형인지 알려줍니다. 전체 표를 참조하세요.

SSH 명령 실행 및 원격 파일 관리

명령, 파일 읽기 및 쓰기, 디렉토리 목록 — 머신에서의 일반적인 작업, 각 답변은 이미 구문 분석되어 있습니다.

장기 실행 SSH 작업 모니터링

느린 작업은 분리되어 대기 대신 추적됩니다: 모든 확인이 얼마나 진행되었는지 알려줍니다.

로그 검색 및 서버 상태 확인

파일 및 컨테이너의 로그와 머신의 일회성 상태, 출력이 제한되어 꼬리가 컨텍스트 창을 먹지 않습니다.

SSH를 통한 파일 업로드 및 다운로드

무결성 검사가 있는 바이너리 안전 전송. 자세한 내용은 docs/transfer.md에 있습니다.

바이너리 및 대용량 파일에는 ssh_upload / ssh_download를 사용하세요 — base64 청크와 heredoc은 바이너리 안전 또는 원자적이지 않습니다.

SSH를 통한 Linux 서버 감사

읽기 전용이며 한 번의 왕복으로 일괄 처리됩니다. 자세한 내용은 docs/audit.md에 있습니다.

Windows SSH 호환 모드

Windows는 호환 모드를 자동으로 사용합니다. 연결 다중화가 불가능한 경우, 서버는 명령당 하나의 연결로 전환합니다. 동일한 도구가 키 기반 SSH를 통해 계속 사용 가능합니다 — 별도의 설정이나 Windows 전용 구현이 필요 없습니다.

파괴적 명령 가드는 AI 에이전트를 위한 파괴적 명령 보호에서 다룹니다.

SSH MCP 서버 설정

먼저 30초 설치에서 패키지를 실행한 다음, 프로필 파일을 만드세요.

SSH 연결 프로필 생성

원하는 곳에 두세요 — 에이전트 자체 구성 옆이 일반적인 선택입니다. 아래 예제는 ~/.claude/ssh-profiles.json를 사용합니다; 다른 에이전트는 디렉토리를 교체하세요 (~/.codex/, ~/.qwen/, ~/.config/opencode/):

{
  "profiles": {
    "production": {
      "host": "server.example.com",
      "username": "admin",
      "port": 22,
      "privateKeyPath": "~/.ssh/your_private_key"
    }
  }
}

SSH 프로필을 명시적으로 선택하세요

서버가 대체하는 프로필은 없습니다: 각각은 다른 머신이며, 잘못된 머신에 보낸 명령은 이후에 오류 메시지로 되돌릴 수 없습니다. 이름 없이 요청하면 답변이 선택할 이름을 나열합니다:

ssh_exec({ command: "uptime" })
→ No profile specified. Name one explicitly: production

SSH에 사용할 수 없는 프로필 — host 없음, username 없음 또는 mode: "local" — 은 불평 없이 건너뛰며, 인식하지 못하는 필드는 그대로 두므로 파일을 다른 도구와 공유할 수 있습니다. 손상된 필드가 있는 프로필은 다른 경우입니다: 필드와 값과 함께 이름이 지정되며, 건강한 이웃 프로필은 계속 작동합니다.

각 프로필은 선택적으로 파일 도구가 접근할 수 있는 경로를 허용 또는 차단하는 pathSecurity 블록을 사용합니다 — docs/security.md를 참조하세요.

키로 로그인하지만 원격 측에서 sudo이 필요한 프로필은 sudoPassword을 사용합니다 — sudo로 답변되는 비밀으로, 많은 머신에서 로그인 비밀번호가 아닙니다. 여기보다는 비밀 파일에 보관하세요.

프로필에서 SSH 비밀번호 및 암호문구 제외

키를 선호하세요. 비밀번호나 암호화된 키의 암호문구를 피할 수 없다면, 프로필 자체가 아닌 별도의 시크릿 파일에 보관하세요:

{
  "secretsFile": "~/.config/ssh-mcp/secrets.json",
  "profiles": {
    "production": {
      "host": "server.example.com",
      "username": "admin"
    }
  }
}

시크릿 파일은 프로필 이름을 키로 사용합니다 — secrets.json.example 참조:

{
  "production": { "password": "..." },
  "buildbox": { "sudoPassword": "..." }
}

sudoPassword은 해당 머신에서 sudo에 응답하는 값입니다. 키로 로그인하는 프로필은 제공할 로그인 비밀번호가 없으며, 둘이 다를 때 로그인 비밀번호가 잘못된 답입니다. 그것이 없으면 password가 사용됩니다.

시크릿 파일은 사용자 본인만 읽을 수 있어야 합니다 (chmod 600). 상대 경로는 프로필 파일 기준으로 해석됩니다. 시크릿은 argv에 남지 않으며 로그에서 마스킹됩니다. 자격 증명 보안 참조.

Claude Code, Codex 및 기타 MCP 클라이언트 구성

사용 중인 클라이언트를 선택하고 동일한 프로필 파일을 가리키게 하세요.

Claude Code

명령 하나로 완료됩니다. -s user는 모든 프로젝트에서 서버를 사용할 수 있게 합니다:

claude mcp add ssh -s user \
  -e SSH_PROFILES_FILE="$HOME/.claude/ssh-profiles.json" \
  -- npx -y @hypnosis/ssh-mcp-server

Codex CLI

codex mcp add ssh \
  --env SSH_PROFILES_FILE="$HOME/.codex/ssh-profiles.json" \
  -- npx -y @hypnosis/ssh-mcp-server

opencode

~/.config/opencode/opencode.json에 넣으세요:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ssh": {
      "type": "local",
      "command": ["npx", "-y", "@hypnosis/ssh-mcp-server"],
      "enabled": true,
      "environment": {
        "SSH_PROFILES_FILE": "~/.config/opencode/ssh-profiles.json"
      }
    }
  }
}

Qwen Code

다른 것들과 동일하게 명령 하나로 완료됩니다:

qwen mcp add ssh \
  -e SSH_PROFILES_FILE="$HOME/.qwen/ssh-profiles.json" \
  npx -y @hypnosis/ssh-mcp-server

기타 MCP 클라이언트

Gemini CLI, Hermes, Cline, 에디터 플러그인 또는 자체 에이전트도 동일한 방식으로 작동합니다. 필요한 것은 실행할 명령과 환경 변수 하나뿐입니다.

MCP 클라이언트 다시 시작

클라이언트를 다시 시작한 후 ssh_monitor({ action: "list" })을 실행하여 프로필이 로드되었는지 확인하세요.

SSH MCP 서버 구성

변수역할기본값
SSH_PROFILES_FILE프로필 JSON 경로 — 필수
SSH_MCP_LOG_LEVELdebug, info, warn, errorinfo
LOG_LEVEL대체값, SSH_MCP_LOG_LEVEL이 설정되지 않았을 때만 사용info
SSH_MCP_LOG_TIMESTAMP로그 줄의 타임스탬프true
SSH_MCP_CONTROL_PERSIST마지막 명령 후 공유 연결이 유지되는 시간(초). 0은 즉시 닫습니다600
SSH_MCP_CONTROL_DIR컨트롤 소켓이 위치하는 곳~/.ssh/ssh-mcp
SSH_MCP_PROFILES_CACHE_TTL프로필 캐시 TTL(ms)60000
SSH_MCP_PROFILES_WATCH프로필 파일이 변경되면 다시 로드true

공유 연결은 의도적으로 이 프로세스보다 오래 유지됩니다. 종료 시 닫으면 같은 머신의 다른 창에서 사용 중인 채널이 끊기기 때문입니다.

SSH MCP 서버 제한 사항

모든 제한은 해결 방법을 알려줍니다. 어떤 작업을 수행할 수 없는 도구는 그 사실을 말하고 ssh_exec을 언급합니다. 이는 머신에서 직접 명령을 실행합니다 — 지원되지 않는 로그 드라이버, 머신에 없는 유틸리티, 이 서버가 지원하지 않는 엔진 등이 해당됩니다. 도구의 한계를 미리 알 필요는 없습니다. 거부 메시지가 중요한 순간에 알려줍니다.

세 가지 거부는 의도적으로 셸에 대해 침묵합니다. 그곳에서는 그것이 잘못된 답이기 때문입니다: 프로필이 금지하는 경로(자신의 규칙을 우회하는 것은 해결책이 아님), 잘못된 형식의 호출(해결책은 호출에 있음), 그리고 ssh_exec 자체의 거부입니다.

  • 취소: 취소된 호출은 이제 서버의 명령도 중지합니다. 동일한 연결을 통해 두 번째 호출로 전송됩니다. 서버에 /proc이 없는 경우 명령은 ps을 통해 찾습니다. FreeBSD는 검증되지 않았습니다. 올바른 동작이 보장되지 않습니다. 파일 전송과 ssh_snapshot은 취소를 지원하지 않습니다.
  • 원자적 쓰기: BSD와 macOS는 파일 시스템 간 이름 변경을 사전에 확인할 수 없습니다.

SSH MCP 서버 로드맵

  • macOS SSH 호스트에 대한 전체 테스트 실행

  • Windows에서 엔드투엔드 호환성 실행

  • 다중 호스트 감사 — 한 번의 호출로 여러 SSH 프로필의 상태 비교

  • 기존 ~/.ssh/config에서 프로필 가져오기

  • 대용량 파일 및 불안정한 연결을 위한 재개 가능한 전송

  • 원격 작업 타임라인 — 명령, 전송 및 가드 결정을 하나의 감사 추적으로

  • 바로 사용 가능한 SSH 문제 해결 플레이북

  • 셸로 내려가지 않고 컨테이너 로그완료: ssh_log_tailssh_log_search은 컨테이너 이름을 받아 docker에 로그 위치를 묻고 다른 로그와 동일한 메커니즘으로 해당 파일을 읽습니다

  • 막다른 길에 빠지게 하는 거부완료: 모든 제한은 이제 ssh_exec을 해결 방법으로 언급하므로 도구의 한계에 부딪히면 추측 게임 대신 한 문장이면 충분합니다

  • 모델에 도달하는 답변완료: 명령 출력, 일치하는 로그 줄, 머신 이름 및 스냅샷 섹션이 텍스트뿐만 아니라 필드로 전달됩니다

  • 더 작은 MCP 도구 스키마완료: 도구 목록이 10% 가벼워졌고, 분리된 작업은 맹목적으로 폴링되는 대신 마지막으로 작성한 줄을 표시합니다

  • root 아래의 긴 작업완료: 분리된 작업은 sudo으로 실행되고 root로 추적되며, 키 전용 프로필은 sudo에 자체 sudoPassword으로 응답합니다

SSH MCP 서버 개발 및 테스트

npm install
npm run build           # tsc
npx tsc --noEmit        # types, plus dead declarations
npm run test:unit       # unit tests
npm run lab:up          # start the two test containers
npm run test:live       # live suite against those containers

라이브 테스트 스위트는 실제 컨테이너(BusyBox 하나, coreutils 하나)에서 실행됩니다. 두 컨테이너는 조용히 의견이 다르고, 목(mock)은 작성한 사람과 일치하기 때문입니다. 레이아웃은 docs/architecture.md를 참조하세요.

SSH MCP 서버가 마음에 드시나요? ⭐

이 도구가 마음에 든다면 GitHub에서 스타를 눌러주세요 — 더 많은 사람들이 프로젝트를 발견하는 데 도움이 됩니다.

SSH MCP 서버에 기여하기

이슈와 풀 리퀘스트는 github.com/hypnosis/ssh-mcp-server에서 환영합니다.

라이선스

MIT — LICENSE 참조.