SSH MCP Server

官方

透過SSH從您的代理程式執行指令、移動檔案、搜尋日誌及稽核機器。

你可以用 SSH MCP 做什麼?

  • 以安全防護執行指令 — 要求您的助理透過 ssh_exec 執行單一或批次指令,並具備破壞性指令防護,可在不可逆操作送達伺服器前予以阻擋。
  • 讀取、寫入及列出遠端檔案 — 使用 ssh_file_readssh_file_writessh_file_list 檢查或修改檔案,支援原子寫入及選用的 SHA-256 驗證。
  • 搜尋日誌並檢查伺服器健康狀態 — 跨檔案與容器查詢 ssh_log_searchssh_log_tail,或透過 ssh_snapshotssh_audit_baseline 取得結構化的健康狀態快照。
  • 傳輸檔案並進行完整性檢查 — 透過 ssh_uploadssh_download 上傳或下載檔案與目錄,並針對較舊裝置自動使用傳統 scp 作為備援方案。
  • 管理長時間執行的背景工作 — 使用 ssh_exec 將緩慢操作分離至背景,並透過 ssh_job_statusssh_job_outputssh_job_kill 追蹤,即使斷線也能持續運作。

文件

SSH MCP Server — 供 AI 代理使用的遠端伺服器工具

SSH MCP Server

一個 SSH MCP 伺服器——一個多功能工具,能為你和你的 AI 代理在除錯、開發和伺服器維護上節省時間與 token。

透過 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

此外掛會讀取 ~/.claude/ssh-profiles.json,除非 SSH_PROFILES_FILE 另有指定,所以 請先建立該檔案,伺服器啟動時就會載入你的機器。

系統需求

npm version Node.js TypeScript MCP SDK

Node.js 18+ 以及系統上的 ssh 用戶端,適用於 PATH。在 Windows 上,請使用金鑰型設定檔; 目前不提供密碼和通行密碼片語設定檔。

偏好固定版本、離線工作,或每次啟動少一次 registry 檢查: npm install -g @hypnosis/ssh-mcp-server,然後使用 ssh-mcp-server 作為指令,而不是 npx

適用對象

  • DevOps 和 SRE——想要更快的稽核、事件檢查和例行伺服器工作。
  • Vibe 程式設計師和獨立開發者——使用 AI 助理發布產品,並在自己伺服器上運行所建構的內容。
  • 系統管理員和平台工程師——想要結構化工具,而不是不受限制的原始 shell。
  • 自行運行 VPS 的開發者和小型團隊——沒有專職維運團隊。
  • Homelab、NAS 和路由器擁有者——其實用硬體已超出其現代協定的支援範圍。

為什麼選擇 SSH MCP 伺服器而不是原始 shell

更少的 token,更低的 AI 成本

原始 shell 給 AI 代理的是大量資訊流:重複的指令、ASCII 表格和日誌傾印。 它會消耗 token 將這些雜訊轉換成伺服器狀態的圖像——也就是你的錢。

更快的伺服器除錯

專用工具會批次處理例行檢查、限制過多輸出,並回傳重要的部分。 代理花較少時間翻譯終端機輸出,能更快找到修復方法。

更少的猜測,更少的 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檔案仍然會送達——自動使用舊協定
一台十年前的老伺服器工作流程仍然有效;只是每個指令會開啟新連線,而不是重複使用
一個精簡映像,沒有辦法計算檔案雜湊上傳會顯示「無法驗證」,而不是宣稱沒人檢查過的相符
一台根本沒安裝某工具的機器答案會說「未測量」——絕不會是讀起來像「什麼都沒有」的零

專為 Model Context Protocol 打造

基於官方 MCP SDK,全程使用 TypeScript,超過 2500 個單元測試,加上針對真實容器 而非模擬物件運行的即時測試套件。


原始 SSH 與 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 的機器,在連接埠檢查從未執行時,可能看起來像是零個監聽者。

結構化 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 個 token,而原始方式為 765 個。節省來自於完整的 工作流程,而不是讓單一回應更短。

在真實的故障排除過程中,專用工具將 49 次單獨的指令呼叫減少為 4 次 MCP 呼叫。每次額外的呼叫都會以累積的對話內容開始另一個模型回合。 提示快取可以降低重複輸入的成本,但新指令及其輸出仍會消耗上下文。更少的往返 意味著整個工作階段中更少的 token、更少的重複分析,以及更快的答案路徑。

需要全貌而不是脈搏? ssh_audit_baseline 會批次處理系統、磁碟、 記憶體、連接埠、sshd、失敗的單元、Docker、防火牆和更新。結果以 CRITICAL / WARNING / OK 呈現;未測量的區段會被明確標示,而不是默默讀作零。

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你的收穫
四次搜尋和四個輸出一次跨檔案和 glob 的搜尋更少的 token 和往返
權限錯誤可能消失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

退出碼為零表示 shell 完成了。它不能證明哪些位元組實際寫入,而且 > 在新檔案的第一個位元組到達之前就截斷了舊檔案。如果連線在寫入中途 中斷,服務就會留下部分設定。

結構化 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你的收穫
目標在複製完成前就被截斷完整的暫存檔透過一次重新命名取代它不會有寫入一半的設定
只有退出碼位元組數和驗證結果都有名稱你知道實際寫入了什麼
權限存在於 shell 文字中sudomodeverify 是每個檔案的字段可預測的擁有權和更少的引號錯誤

verified 有三種誠實的結果:verified、伺服器沒有雜湊工具時的 unavailable, 以及未要求驗證時的 skipped。對於讀取,ssh_file_read 接受 路徑清單;ssh_file_list 處理 glob、遞迴、大小和權限模式。

使用 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

三個連線回傳三個不相關的輸出。如果指令用 ; 連接,shell 只會回報最後一個退出碼; 如果用 && 連接,後續的檢查會在第一次失敗後消失。

結構化 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你的收穫
三次呼叫和不相關的輸出一個有序的指令清單更少的往返
合併的 shell 可能隱藏中間狀態每個指令保留自己的 exit_code不會漏掉失敗的檢查
sudo 和引號在指令文字中重複出現sudo 套用於整個批次更少的引號錯誤

破壞性指令防護會在執行第一個指令前檢查完整清單。如果某個條目 被拒絕,其他所有條目都會標記為未執行,且不會傳送任何內容到伺服器。 每個指令都帶有各自的 stdoutstderr。已執行但未輸出任何內容的指令,其值為空字串;從未執行的指令則完全沒有該欄位,因此兩者不會混淆。每個指令超過 128 KB 的輸出會保留兩端——開頭用於表格、結尾用於日誌——中間以接縫標示被截斷的量,而 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安全斷線與重新啟動
重新連線意味著搜尋程序與檔案狀態與結束碼具有具名狀態無需猜測是否完成
重新讀取輸出會重複舊文字輸出從位元組偏移量繼續長時間任務的 Token 使用量更低

任務狀態儲存在遠端磁碟上,而非此伺服器的記憶體中。ssh_job_status 區分 runningfinishedlostssh_job_output 從最後的位元組偏移量繼續;而 ssh_job_kill 會對整個程序群組發出訊號,而不僅是其 shell。

傳輸檔案至舊款路由器與 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 驗證具有具名結果損毀不會被誤認為成功
直接取代可能留下不完整的目標暫存檔在傳輸後才移至定位運作中的檔案能承受中斷

如果裝置既沒有 sha256sum 也沒有 openssl,結果會顯示 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

Shell 會先刪除目錄,然後才發現備份來源已消失。防護機制會看到後續步驟讀取已被先前步驟摧毀的目標,因此整個呼叫會留在你的機器上。相同的檢查也會攔截 dropdb app && pg_dump app > backup.sql

拒絕不可逆的損失,警告可復原的變更

拒絕——容器本身僅警告——其內容
DROP DATABASEdropdbDROP TABLETRUNCATEDELETE FROM
docker volume rmdocker compose down -vdocker rm -f <name>
crontab -r編輯單一任務
mkfswipefs -alvremovezfs destroychmod 777
rebootshutdownhaltgit 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-1kill 4871systemctl stop app

若要繼續,請指名要停止的對象。名稱會與指令實際觸及的內容進行比對,因此已漂移到其他對象的遮罩會被拒絕而非確認:

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

針對指令列的樣式是另一種情況。它會比對到攜帶該樣式的指令本身,因此執行它的 shell 會在目標之前被發出訊號,而回覆會在中途斷開。此類打擊不會被確認,而是被改寫——以編號方式,或將一個字元寫成字元類別,使樣式不再比對到自身:

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列出目錄,可選 glob 與遞迴
ssh_upload透過 SSH 上傳檔案或目錄,二進位安全且具完整性檢查;目錄可取代目標或合併至其中
ssh_download透過 SSH 下載檔案或目錄,二進位安全且具完整性檢查
ssh_job_status背景任務的狀態:執行中、已完成或已遺失
ssh_job_output從位元組偏移量讀取累積輸出
ssh_job_list列出任務,清除超過 TTL 的已完成任務
ssh_job_kill對任務的整個程序群組發出訊號
ssh_log_tail一個或多個日誌的最後 N 行,支援 glob;可依名稱指定容器
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_statussystemctl status 加上單一單元的 journalctl 尾部

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、沒有 usernamemode: "local"——會被靜默略過,而它不認識的欄位會被保留,因此該檔案可與其他工具共用。具有損壞欄位的設定檔則不同:它會連同欄位與值一起被指名,而其健康的鄰近設定檔仍可繼續運作。

每個設定檔可選擇性地帶有 pathSecurity 區塊,用於白名單或黑名單檔案工具可觸及的路徑——請參閱 docs/security.md

以金鑰登入但需要在遠端使用 sudo 的設定檔,會帶有 sudoPassword——用於回應 sudo 的密鑰,在許多機器上這並非登入密碼。請將其保存在密鑰檔案中,而非此處。

將 SSH 密碼與通行密碼短語排除在設定檔之外

優先使用金鑰。如果密碼或加密金鑰的通行詞短語無法避免,請將其保存在單獨的 secrets 檔案中,切勿放在設定檔本身:

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

secrets 檔案以設定檔名稱為鍵——請參閱 secrets.json.example

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

sudoPassword 是該機器上對 sudo 的回應。使用金鑰登入的設定檔沒有登入密碼可提供, 而當兩者不同時,登入密碼是錯誤的答案;若無此設定,則使用 password

secrets 檔案必須僅供您本人讀取(chmod 600)。相對路徑從設定檔解析; secrets 不會進入 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 server 設定

變數功能預設值
SSH_PROFILES_FILE設定檔 JSON 的路徑——必填
SSH_MCP_LOG_LEVELdebuginfowarnerrorinfo
LOG_LEVEL後備方案,僅在 SSH_MCP_LOG_LEVEL 未設定時使用info
SSH_MCP_LOG_TIMESTAMP日誌行中的時間戳記true
SSH_MCP_CONTROL_PERSIST共享連線在最後一個指令後保持存活的秒數;0 立即關閉它600
SSH_MCP_CONTROL_DIR控制 socket 的存放位置~/.ssh/ssh-mcp
SSH_MCP_PROFILES_CACHE_TTL設定檔快取 TTL,毫秒60000
SSH_MCP_PROFILES_WATCH當設定檔變更時重新載入true

共享連線刻意比此程序存活更久:在退出時關閉它會切斷同一機器上另一個視窗正在使用的通道。

SSH MCP server 限制

每個限制都告訴您繞過的方法。 無法執行某項操作的工具會明確說明,並指出 ssh_exec——它直接在機器上執行指令——例如不支援的日誌驅動程式、 機器上沒有的工具、此伺服器不支援的引擎。您不需要事先知道工具的邊界在哪裡: 拒絕訊息會在關鍵時刻說出來。

三種拒絕會刻意對 shell 保持沉默,因為在那裡它是錯誤的答案:您的設定檔禁止的路徑 (繞過自己的規則不是解決方案)、格式錯誤的呼叫(修正點在呼叫本身),以及 ssh_exec 本身的拒絕。

  • 取消: 已取消的呼叫現在也會停止伺服器上的指令,透過同一連線以第二個呼叫發送。在伺服器沒有 /proc 的地方,指令會改透過 ps 找到。FreeBSD 未經驗證:不保證其正確行為。檔案傳輸和 ssh_snapshot 完全不接受取消。
  • 原子寫入: BSD 和 macOS 無法預先檢查跨檔案系統的重新命名。

SSH MCP server 路線圖

  • 針對 macOS SSH 主機的完整測試執行

  • 在 Windows 上進行端對端相容性執行

  • 多主機稽核——在一次呼叫中比較多個 SSH 設定檔的健康狀態

  • 從現有的 ~/.ssh/config 匯入設定檔

  • 大型檔案和不穩定連線的可續傳傳輸

  • 遠端操作時間軸——指令、傳輸和守衛決策在單一稽核軌跡中

  • 現成的 SSH 疑難排解手冊

  • 容器日誌無需進入 shell已完成: ssh_log_tailssh_log_search 接受容器名稱,詢問 docker 日誌寫入位置,並使用與其他日誌相同的機制讀取該檔案

  • 讓您卡住的拒絕已完成: 每個限制現在都指出 ssh_exec 作為突破方式,因此碰到工具邊界只需一句話,而不是猜謎遊戲

  • 能送達模型的答案已完成: 指令輸出、相符的日誌行、機器名稱和快照區段會放在欄位中,而不僅在文字中

  • 更小的 MCP 工具 schema已完成: 工具清單輕量了 10%,且分離的工作現在會顯示其寫入的最後幾行,而不是盲目輪詢

  • 在 root 下的長時間工作已完成: 分離的工作以 sudo 執行並以 root 身分追蹤,且僅金鑰設定檔以自身的 sudoPassword 回應 sudo

開發和測試 SSH MCP server

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 Server?⭐

如果您喜歡這個工具,在 GitHub 上給它一顆星——這有助於更多人發現這個專案。

貢獻 SSH MCP server

歡迎在 github.com/hypnosis/ssh-mcp-server 提交 issue 和 pull request。

授權

MIT——請參閱 LICENSE