SSH MCP Server

ทางการ

รันคำสั่ง ย้ายไฟล์ ค้นหาล็อก และตรวจสอบเครื่องผ่าน SSH จากเอเจนต์ของคุณ

GitHub
2
ลองใช้ MCP นี้ผู้สนับสนุน

คุณทำอะไรได้บ้างด้วย SSH MCP?

  • รันคำสั่งพร้อมการป้องกันความปลอดภัย — ขอให้ผู้ช่วยของคุณดำเนินการคำสั่งเดี่ยวหรือแบบชุดผ่าน ssh_exec พร้อมการป้องกันคำสั่งที่ทำลายล้างซึ่งจะบล็อกการดำเนินการที่ไม่สามารถย้อนกลับได้ก่อนที่จะถึงเซิร์ฟเวอร์
  • อ่าน เขียน และแสดงรายการไฟล์ระยะไกล — ใช้ ssh_file_read, ssh_file_write และ ssh_file_list เพื่อตรวจสอบหรือแก้ไขไฟล์ พร้อมการเขียนแบบอะตอมมิกและการตรวจสอบ SHA-256 ทางเลือก
  • ค้นหาล็อกและตรวจสอบสุขภาพเซิร์ฟเวอร์ — ค้นหา ssh_log_search หรือ ssh_log_tail ในไฟล์และคอนเทนเนอร์ หรือรับภาพรวมสุขภาพแบบมีโครงสร้างด้วย ssh_snapshot และ ssh_audit_baseline
  • ถ่ายโอนไฟล์พร้อมการตรวจสอบความถูกต้อง — อัปโหลดหรือดาวน์โหลดไฟล์และไดเรกทอรีผ่าน ssh_upload และ ssh_download พร้อมการสำรองแบบ scp ดั้งเดิมอัตโนมัติสำหรับอุปกรณ์รุ่นเก่า
  • จัดการงานเบื้องหลังที่ทำงานยาวนาน — แยกการทำงานที่ช้าออกด้วย ssh_exec และติดตามผ่าน ssh_job_status, ssh_job_output และ ssh_job_kill ซึ่งสามารถทนต่อการตัดการเชื่อมต่อได้

เอกสาร

SSH MCP Server — เครื่องมือเซิร์ฟเวอร์ระยะไกลสำหรับเอเจนต์ AI

SSH MCP Server

เซิร์ฟเวอร์ SSH MCP — มัลติทูลที่ช่วยคุณและเอเจนต์ AI ประหยัดเวลาและโทเค็นในการดีบัก พัฒนา และบำรุงรักษาเซิร์ฟเวอร์

รันคำสั่ง ย้ายไฟล์ อ่านล็อก และตรวจสอบเครื่องจักรผ่าน SSH — ไม่ว่าจะเป็น VPS บนคลาวด์ เครื่องจริง หรือเราเตอร์ BusyBox ที่วางอยู่ในตู้เสื้อผ้าของคุณ

มันใช้ OpenSSH client ที่มีอยู่แล้วบนเครื่องของคุณ: คีย์ของคุณ ~/.ssh/config โฮสต์กระโดดของคุณ การส่งต่อเอเจนต์ของคุณ ไม่มีอะไรถูกผูกไว้ ไม่มีอะไรให้คอมไพล์ ไม่มีการเชื่อมโยงเนทีฟ

ทำงานร่วมกับ Claude Code, Codex CLI, Cline, opencode, Gemini CLI, Qwen Code, Hermes และ MCP clients อื่นๆ

MCP Registry Glama Smithery npm downloads tests

ติดตั้ง · เครื่องมือ · การตั้งค่า · ความปลอดภัย · โรดแมป · เอกสาร · บันทึกการเปลี่ยนแปลง


ติดตั้งใน 30 วินาที

ไม่ต้องติดตั้งทั้งระบบ npx ดาวน์โหลดแพ็กเกจเมื่อใช้งานครั้งแรก:

npx -y @hypnosis/ssh-mcp-server

เพิ่มลงใน MCP client ของคุณ — Claude Code ตัวอย่างเช่น — สำหรับทุกโปรเจกต์:

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

หรือเขียนด้วยมือ — เซิร์ฟเวอร์เดียวกันในรูปแบบคอนฟิกที่ clients ส่วนใหญ่ใช้ร่วมกัน:

{
  "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 และ clients อื่นๆ ครอบคลุมใน ตั้งค่า SSH MCP server

ติดตั้งเป็นปลั๊กอิน

บาง clients — 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 client บน PATH บน Windows ให้ใช้โปรไฟล์แบบคีย์ โปรไฟล์รหัสผ่านและพาสเฟรสยังไม่พร้อมใช้งานในขณะนี้

ต้องการเวอร์ชันที่ปักหมุด ทำงานออฟไลน์ หรือลดการตรวจสอบรีจิสทรีหนึ่งครั้งต่อการเปิดใช้: npm install -g @hypnosis/ssh-mcp-server จากนั้นใช้ ssh-mcp-server เป็นคำสั่งแทน npx

ใครควรใช้สิ่งนี้

  • DevOps และ SREs ที่ต้องการตรวจสอบที่เร็วขึ้น การเช็คเหตุการณ์ และงานเซิร์ฟเวอร์ประจำ
  • Vibe coders และอินดี้บิลเดอร์ ที่ส่งงานด้วยผู้ช่วย AI และรันสิ่งที่สร้างบนเซิร์ฟเวอร์ของตัวเอง
  • Sysadmins และวิศวกรแพลตฟอร์ม ที่ต้องการเครื่องมือที่มีโครงสร้างแทนเชลล์ดิบที่ไม่จำกัด
  • นักพัฒนาและทีมเล็กๆ ที่รัน VPS ของตัวเอง โดยไม่มีทีมปฏิบัติการโดยเฉพาะ
  • เจ้าของ Homelab, NAS และเราเตอร์ ที่ฮาร์ดแวร์ที่มีประโยชน์มีอายุเกินโปรโตคอลสมัยใหม่

ทำไมต้อง SSH MCP server แทนเชลล์ดิบ

โทเค็นน้อยลง ต้นทุน AI ต่ำลง

เชลล์ดิบให้เอเจนต์ AI ได้ข้อมูลท่วมท้น: คำสั่งซ้ำๆ ตาราง ASCII และดัมพ์ล็อก มันเผาโทเค็นเพื่อแปลงเสียงรบกวนนั้นเป็นภาพของเซิร์ฟเวอร์ — เงินของคุณ

ดีบักเซิร์ฟเวอร์เร็วขึ้น

เครื่องมือที่ออกแบบมาโดยเฉพาะจัดกลุ่มการตรวจสอบประจำ จำกัดเอาต์พุตที่ดัง และคืนส่วนที่สำคัญ เอเจนต์ใช้เวลาน้อยลงในการแปลเอาต์พุตเทอร์มินัลและไปถึงจุดแก้ไขได้เร็วขึ้น

เดาน้อยลง ผิดพลาดน้อยลง

คำตอบที่มีโครงสร้างบอกว่าพบอะไร สิ่งใดวัดไม่ได้ และสิ่งใดถูกตัดทอน นั่นทำให้เอเจนต์มีช่องว่างน้อยลงในการเติมด้วยภาพหลอน — และทำให้คุณมีการแก้ไขที่แย่น้อยลง การดีพลอยที่สงบขึ้น และโค้ดที่เชื่อถือได้มากขึ้น

ความเข้ากันได้ของ SSH: เซิร์ฟเวอร์สมัยใหม่ อุปกรณ์รุ่นเก่า และ Windows

ใช้การตั้งค่า OpenSSH ที่มีอยู่ของคุณ

ไม่มีการรวม SSH ที่ผูกไว้ ไม่มีการเชื่อมโยงเนทีฟ ไม่ต้องคอมไพล์ใหม่ต่อแพลตฟอร์ม คำสั่งใช้ ระบบ ssh client ดังนั้นคีย์ของคุณ ~/.ssh/config โฮสต์กระโดดของคุณ และการส่งต่อเอเจนต์ของคุณ ทั้งหมดยังทำงานเหมือนในเทอร์มินัลทุกประการ เมื่อรองรับ การเชื่อมต่อแบบมัลติเพล็กซ์ที่ใช้ร่วมกันหนึ่งครั้งต่อปลายทาง หมายความว่าคุณยืนยันตัวตนครั้งเดียว ไม่ใช่ทุกคำสั่ง

รองรับ SSH สำหรับเซิร์ฟเวอร์รุ่นเก่า เราเตอร์ และ NAS

ส่งไฟล์ไปยังเราเตอร์ด้วย scp สมัยใหม่ แล้วคุณจะได้สิ่งนี้:

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

ไม่มีอะไรเสียหาย — scp ปัจจุบันพูดโปรโตคอลใหม่ และเราเตอร์ไม่รู้จัก ในเทอร์มินัล คุณต้องไปอ่านกระทู้ฟอรัมแล้วกลับมาพร้อมแฟล็กพิเศษ ที่นี่คุณไม่ต้องทำอะไร: การถ่ายโอนถูกพยายาม การปฏิเสธถูกรับรู้ โปรโตคอลเก่าถูกใช้แทน และเครื่องนั้นถูกจดจำ เพื่อให้ไฟล์ถัดไปไปถึงที่นั่นโดยตรง

การสำรองสำหรับ SSH clients รุ่นเก่าและเครื่องมือที่ขาดหายไป

อุปกรณ์เก่าได้รับการสำรอง ไม่ใช่ทางตัน เมื่อฟีเจอร์สมัยใหม่ขาดหายไป เซิร์ฟเวอร์ ใช้เส้นทางเก่าที่ทำได้:

เครื่องของคุณสิ่งที่คุณได้รับ
เราเตอร์หรือ NAS เล็กเกินไปสำหรับการถ่ายโอนไฟล์สมัยใหม่ไฟล์ยังไปถึง — โปรโตคอลเก่าถูกใช้โดยอัตโนมัติ
เซิร์ฟเวอร์จากสิบปีที่แล้วเวิร์กโฟลว์ยังทำงาน; เพียงเปิดการเชื่อมต่อใหม่ต่อคำสั่งแทนการ复用
อิมเมจที่ถูกตัดทอนโดยไม่มีวิธีแฮชไฟล์การอัปโหลดบอก "ไม่สามารถยืนยันได้" แทนการอ้างว่าตรงกันโดยไม่มีใครตรวจสอบ
เครื่องที่ไม่มีเครื่องมือติดตั้งอยู่คำตอบบอก "ไม่ได้วัด" — ไม่เคยเป็นศูนย์ที่อ่านว่า "ไม่มีอะไรอยู่"

สร้างขึ้นสำหรับ Model Context Protocol

สร้างบน MCP SDK อย่างเป็นทางการ TypeScript ตลอดทั้งชิ้น การทดสอบหน่วย 2500+ รายการบวกชุดทดสอบสดที่ รันกับคอนเทนเนอร์จริงแทนม็อก


Raw SSH เทียบกับ SSH MCP server: งานเดียวกัน ทั้งสองวิธี

การตรวจสอบสุขภาพเซิร์ฟเวอร์ SSH

สถานการณ์: การดีพลอยเพิ่งออกไป เซิร์ฟเวอร์รู้สึกช้า และคุณไม่รู้ว่า ดิสก์ หน่วยความจำ บริการ คอนเทนเนอร์ หรือข้อผิดพลาดเป็นต้นเหตุ

คำถาม: "เครื่องนี้สุขภาพดีหรือไม่"

Raw 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": []
}

สิ่งที่เอเจนต์ได้รับ

Raw SSHStructured MCPสิ่งที่คุณได้
หลายคำสั่งและตาราง ASCIIฟิลด์ที่มีชื่อในผลลัพธ์เดียวหนึ่งคอล ฟิลด์ที่มีชื่อ และรอบการเดินทางน้อยลง
เครื่องมือที่ขาดหายไปอาจดูเหมือนเอาต์พุตว่างunavailable ระบุสิ่งที่ไม่ได้วัดเดาน้อยลงและการแก้ไขที่แย่น้อยลง
คุณต้องจัดเรียงดิสก์ บริการ และข้อผิดพลาดสัญญาณปัญหาถูกผิวเผินแล้วดีบักเร็วขึ้น

ผลลัพธ์ ssh_audit_baseline เต็มรูปแบบอาจยาวกว่าคำสั่งดิบสองสามคำสั่ง — ประมาณ 1,077 โทเค็นเทียบกับ 765 ในการวัดในห้องแล็บของเรา การประหยัดมาจากเวิร์กโฟลว์ที่สมบูรณ์ ไม่ใช่จากการทำให้การตอบสนองหนึ่งครั้งสั้นลง

ในเซสชันการแก้ปัญหาจริง เครื่องมือที่ออกแบบมาโดยเฉพาะลดการเรียกคำสั่ง 49 ครั้งที่แยกจากกันเป็น การเรียก MCP 4 ครั้ง ทุกการเรียกเพิ่มเติมเริ่มต้นเทิร์นโมเดลใหม่พร้อมบทสนทนาที่สะสม Prompt caching สามารถลดต้นทุนของอินพุตซ้ำ แต่คำสั่งใหม่และเอาต์พุตยังคงใช้บริบท รอบการเดินทางน้อยลงหมายถึงโทเค็นน้อยลงตลอดเซสชัน การวิเคราะห์ซ้ำน้อยลง และเส้นทางที่เร็วกว่าสู่คำตอบ

ต้องการภาพรวมทั้งหมดแทนชีพจรหรือไม่? ssh_audit_baseline จัดกลุ่มระบบ ดิสก์ หน่วยความจำ พอร์ต sshd ยูนิตที่ล้มเหลว Docker ไฟร์วอลล์ และอัปเดต ผลการค้นพบมาถึงเป็น CRITICAL / WARNING / OK; ส่วนที่ไม่ได้วัดถูกระบุชื่อแทนการอ่านเป็นศูนย์อย่างเงียบๆ

การค้นหาล็อกเซิร์ฟเวอร์ Linux

สถานการณ์: API หมดเวลา แต่ข้อความเดียวกันอาจอยู่ใน nginx, syslog, journald หรือล็อกแอปพลิเคชันที่คุณไม่สามารถอ่านด้วยผู้ใช้ปกติของคุณ

คำถาม: "ข้อผิดพลาดนั้นมาจากไหน"

Raw 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
}

สิ่งที่เอเจนต์ได้รับ

Raw SSHStructured MCPสิ่งที่คุณได้
สี่การค้นหาและสี่เอาต์พุตหนึ่งการค้นหาข้ามไฟล์และ globsโทเค็นและรอบการเดินทางน้อยลง
ข้อผิดพลาดสิทธิ์อาจหายไปfiles_unreadable ระบุทุกเส้นทางที่พลาดไม่มีข้อสรุปเท็จว่า "ล็อกสะอาด"
เอาต์พุตสามารถเติบโตโดยไม่มีเพดานที่มีประโยชน์limited และ truncated เปิดเผยทุกจุดตัดการตัดสินใจที่ปลอดภัยขึ้นจากผลลัพธ์บางส่วน

since ใช้นาฬิกาของเซิร์ฟเวอร์ namesOnly: true คืนเฉพาะเส้นทางที่ตรงกัน และ ssh_log_tail อ่าน N บรรทัดสุดท้ายจากหลายล็อกในการเรียกเดียว

การแก้ไขคอนฟิกระยะไกลอย่างปลอดภัย

สถานการณ์: คุณต้องแทนที่คอนฟิก nginx บนเซิร์ฟเวอร์สด การเชื่อมต่อที่หลุด โหมดผิด หรือการคัดลอกที่ไม่ตรวจสอบอาจทำให้บริการมีไฟล์ที่เสียหาย

คำถาม: "ฉันสามารถแทนที่คอนฟิกนี้โดยไม่ทิ้งไฟล์บางส่วนได้หรือไม่"

Raw 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

รหัสออกศูนย์บอกว่าเชลล์เสร็จสิ้น มันไม่ได้พิสูจน์ว่าไบต์ใดลงจอด และ > ตัดทอนไฟล์เก่าก่อนไบต์แรกของไฟล์ใหม่มาถึง หากการเชื่อมต่อหลุดกลางการเขียน บริการจะเหลือคอนฟิกบางส่วน

ผลลัพธ์ 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 }]
}

สิ่งที่เอเจนต์ได้รับ

Raw SSHStructured MCPสิ่งที่คุณได้
เป้าหมายถูกตัดทอนก่อนการคัดลอกเสร็จสิ้นไฟล์ชั่วคราวที่สมบูรณ์แทนที่ด้วยการเปลี่ยนชื่อครั้งเดียวไม่มีคอนฟิกที่เขียนครึ่งเดียว
รหัสออกเท่านั้นไบต์และผลการยืนยันถูกระบุชื่อคุณรู้ว่าอะไรลงจอดจริง
สิทธิ์อยู่ในข้อความเชลล์sudo, mode และ verify เป็นฟิลด์ต่อไฟล์ความเป็นเจ้าของที่คาดเดาได้และข้อผิดพลาดการอ้างน้อยลง

verified มีสามผลลัพธ์ที่ซื่อสัตย์: verified, unavailable เมื่อเซิร์ฟเวอร์ไม่มีเครื่องมือแฮช และ skipped เมื่อไม่ได้ขอการยืนยัน สำหรับการอ่าน ssh_file_read ยอมรับ รายการเส้นทาง; ssh_file_list จัดการ globs การเรียกซ้ำ ขนาด และโหมด

รันคำสั่ง SSH แบบแบตช์ด้วย sudo

สถานการณ์: การดีพลอยพร้อมแล้ว แต่ไวยากรณ์ nginx สถานะบริการ และข้อผิดพลาดล่าสุดต้อง ถูกตรวจสอบทั้งหมดก่อนที่ทราฟฟิกจะย้าย การตรวจสอบที่ล้มเหลวหนึ่งครั้งไม่ควรหายไปในดัมพ์รวม

คำถาม: "การตรวจสอบก่อนดีพลอยทุกครั้งผ่านหรือไม่"

Raw 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
}

สิ่งที่เอเจนต์ได้รับ

Raw SSHStructured MCPสิ่งที่คุณได้
สามการเรียกและเอาต์พุตที่ไม่เกี่ยวข้องรายการคำสั่งที่เรียงลำดับหนึ่งรายการรอบการเดินทางน้อยลง
เชลล์รวมสามารถซ่อนสถานะกลางทุกคำสั่งรักษา exit_code ของตัวเองไม่พลาดการตรวจสอบที่ล้มเหลว
sudo และการอ้างซ้ำในข้อความคำสั่งsudo ใช้กับทั้งแบตช์ข้อผิดพลาดการอ้างน้อยลง

การ์ดคำสั่งทำลายล้างตรวจสอบรายการทั้งหมดก่อนคำสั่งแรกจะรัน หากหนึ่งรายการ ถูกปฏิเสธ ทุกรายการอื่นถูกทำเครื่องหมายว่าไม่ได้รัน และไม่มีอะไรถูกส่งไปยังเซิร์ฟเวอร์ แต่ละคำสั่งมี stdout และ stderr ของตัวเอง คำสั่งที่ทำงานและไม่พิมพ์อะไรเลย มีสตริงว่าง คำสั่งที่ไม่เคยทำงานไม่มีฟิลด์ดังกล่าวเลย ดังนั้นทั้งสองจึงไม่สามารถ สับสนกันได้ ผลลัพธ์ที่เกิน 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 ถาวรการตัดการเชื่อมต่อและการรีสตาร์ทอย่างปลอดภัย
การเชื่อมต่อใหม่หมายถึงการค้นหากระบวนการและไฟล์สถานะและรหัสออกมีสถานะที่มีชื่อไม่ต้องเดาว่าเสร็จหรือไม่
การอ่านผลลัพธ์อีกครั้งจะทำซ้ำข้อความเก่าผลลัพธ์ดำเนินต่อไปจากออฟเซ็ตไบต์ใช้โทเค็นน้อยลงสำหรับงานยาว

สถานะของงานอยู่บนดิสก์ระยะไกล ไม่ใช่ในหน่วยความจำของเซิร์ฟเวอร์นี้ ssh_job_status แยกแยะ running, finished และ lost; 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 มีผลลัพธ์ที่มีชื่อความเสียหายไม่ถูกเข้าใจผิดว่าสำเร็จ
การแทนที่โดยตรงอาจทิ้งเป้าหมายบางส่วนไฟล์ชั่วคราวถูกย้ายเข้าที่หลังการถ่ายโอนไฟล์ที่ใช้งานอยู่รอดจากการขัดจังหวะ

หากอุปกรณ์ไม่มีทั้ง 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

เชลล์จะลบไดเรกทอรีแล้วค้นพบว่าแหล่งสำรองหายไปเท่านั้น การ์ดเห็นว่าขั้นตอนหลังอ่าน เป้าหมายที่ถูกทำลายโดยขั้นตอนก่อนหน้าแล้ว ดังนั้นการเรียกทั้งหมดจึงอยู่บนเครื่องของคุณ การตรวจสอบเดียวกันจับ 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 ก็ถูกปฏิเสธเช่นกัน รวมถึงเมื่อ symlink นำไปที่นั่น เป้าหมายที่ไม่ได้รับการแก้ไข เช่น 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 เครื่องมือ MCP SSH สำหรับการดำเนินการเซิร์ฟเวอร์ พารามิเตอร์เต็มและตัวอย่างอยู่ใน docs/tools.md

เครื่องมือสิ่งที่มันทำ
ssh_execรันหนึ่งคำสั่งหรือชุดคำสั่ง พร้อมการ์ดป้องกันคำสั่งทำลายล้างและ detach ทางเลือก
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_tailN บรรทัดสุดท้ายของหนึ่งหรือหลายล็อก รองรับ glob คอนเทนเนอร์ตามชื่อ
ssh_log_searchค้นหารูปแบบในล็อก หรือผ่านล็อกของคอนเทนเนอร์
ssh_snapshotภาพรวมสุขภาพแบบครั้งเดียว: บริการ ทรัพยากร Docker เครือข่าย ข้อผิดพลาด
ssh_monitorการควบคุมการขนส่ง: สถิติ โหลดซ้ำ ทดสอบ รายการ ปิด
ssh_audit_baselineระบบ ดิสก์ หน่วยความจำ เครือข่าย ssh บริการ Docker ไฟร์วอลล์ อัปเดต
ssh_tls_checkการหมดอายุใบรับรอง SAN เชนและฮุคต่ออายุสำหรับโดเมน
ssh_disk_breakdownดิสก์ไปที่ไหน: du top-N, Docker, journald, แคช
ssh_service_statussystemctl status บวก journalctl tail สำหรับหนึ่งยูนิต

คำอธิบายความปลอดภัยของเครื่องมือ MCP

คำอธิบาย MCP มาตรฐานบอกไคลเอนต์ว่าเครื่องมือใดอ่านอย่างเดียว ทำลายล้าง idempotent หรือ open-world ดู ตารางเต็ม

รันคำสั่ง SSH และจัดการไฟล์ระยะไกล

คำสั่ง การอ่านและเขียนไฟล์ การแสดงรายการไดเรกทอรี — งานทั่วไปบนเครื่อง แต่ละคำตอบถูกแยกวิเคราะห์แล้ว

ติดตามงาน SSH ที่มีอายุยาวนาน

งานช้าถูกแยกและติดตามแทนที่จะรอ: ทุกการมองบอกว่ามันไปไกลแค่ไหน

ค้นหาล็อกและตรวจสอบสุขภาพเซิร์ฟเวอร์

ล็อกของไฟล์และคอนเทนเนอร์ และภาพรวมครั้งเดียวของเครื่อง โดยมีขีดจำกัดผลลัพธ์เพื่อให้ tail ไม่กินบริบทวินโดว์

อัปโหลดและดาวน์โหลดไฟล์ผ่าน SSH

การถ่ายโอนปลอดภัยไบนารีพร้อมการตรวจสอบความสมบูรณ์ รายละเอียดใน docs/transfer.md

สำหรับไบนารีและไฟล์ขนาดใหญ่ใช้ ssh_upload / ssh_download — ชิ้นส่วน base64 และ heredocs ไม่ปลอดภัยไบนารีหรืออะตอมมิก

ตรวจสอบเซิร์ฟเวอร์ Linux ผ่าน SSH

อ่านอย่างเดียวและรวมเป็นหนึ่งรอบ รายละเอียดใน 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 และ passphrase ออกจากโปรไฟล์

ให้ความสำคัญกับคีย์ หากต้องใช้รหัสผ่านหรือ passphrase ของคีย์ที่เข้ารหัสอย่างเลี่ยงไม่ได้ ให้เก็บไว้ในไฟล์ 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 clients อื่น ๆ

เลือก client ที่คุณใช้และชี้ไปที่ไฟล์โปรไฟล์เดียวกัน

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 clients อื่น ๆ

Gemini CLI, Hermes, Cline, ปลั๊กอินของตัวแก้ไข หรือ agent ของคุณเองทำงานในลักษณะเดียวกัน ทั้งหมดที่ต้องการคือคำสั่งให้รันและตัวแปรสภาพแวดล้อมหนึ่งตัว

รีสตาร์ท MCP client ของคุณ

รีสตาร์ท client จากนั้นรัน ssh_monitor({ action: "list" }) เพื่อยืนยันว่าโปรไฟล์โหลดแล้ว

การกำหนดค่า SSH MCP server

ตัวแปรหน้าที่ค่าเริ่มต้น
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ตำแหน่งที่เก็บ control sockets~/.ssh/ssh-mcp
SSH_MCP_PROFILES_CACHE_TTLอายุแคชของโปรไฟล์, มิลลิวินาที60000
SSH_MCP_PROFILES_WATCHโหลดไฟล์โปรไฟล์ใหม่เมื่อมีการเปลี่ยนแปลงtrue

การเชื่อมต่อที่ใช้ร่วมกันมีอายุยืนกว่า process นี้โดยตั้งใจ: การปิดเมื่อออกจากระบบจะตัดช่องทางที่หน้าต่างอื่นบนเครื่องเดียวกันกำลังใช้อยู่

ข้อจำกัดของ SSH MCP server

ทุกข้อจำกัดบอกวิธีแก้ไขให้คุณ เครื่องมือที่ไม่สามารถทำบางสิ่งได้จะแจ้งและระบุ ssh_exec ซึ่งรันคำสั่งบนเครื่องโดยตรง — ไดรเวอร์บันทึกที่ไม่รองรับ ยูทิลิตี้ที่เครื่องไม่มี เอ็นจินที่เซิร์ฟเวอร์นี้ไม่รองรับ คุณไม่จำเป็นต้องรู้ล่วงหน้าว่าเครื่องมือสิ้นสุดที่ใด: การปฏิเสธจะบอก ณ ช่วงเวลาที่สำคัญ

การปฏิเสธสามกรณีจงใจไม่พูดถึงเชลล์ เพราะที่นั่นเป็นคำตอบที่ผิด: เส้นทางที่โปรไฟล์ของคุณห้าม (การเลี่ยงกฎของคุณเองไม่ใช่การแก้ไข), การเรียกที่ผิดรูปแบบ (การแก้ไขอยู่ที่การเรียก), และการปฏิเสธจาก ssh_exec เอง

  • การยกเลิก: การเรียกที่ถูกยกเลิกตอนนี้จะหยุดคำสั่งบนเซิร์ฟเวอร์ด้วย โดยส่งเป็นการเรียกครั้งที่สองผ่านการเชื่อมต่อเดียวกัน ในกรณีที่เซิร์ฟเวอร์ไม่มี /proc คำสั่งจะถูกค้นหาผ่าน ps แทน FreeBSD ไม่ได้รับการตรวจสอบ: พฤติกรรมที่ถูกต้องที่นั่นไม่รับประกัน การถ่ายโอนไฟล์และ ssh_snapshot ไม่รองรับการยกเลิกเลย
  • การเขียนแบบอะตอม: BSD และ macOS ไม่สามารถตรวจสอบล่วงหน้าเรื่องการเปลี่ยนชื่อข้ามระบบไฟล์ได้

แผนงานของ SSH MCP server

  • ทดสอบเต็มรูปแบบกับโฮสต์ SSH บน macOS

  • ทดสอบความเข้ากันได้แบบครบวงจรบน Windows

  • การตรวจสอบหลายโฮสต์ — เปรียบเทียบสุขภาพในหลายโปรไฟล์ SSH ในการเรียกครั้งเดียว

  • นำเข้าโปรไฟล์จาก ~/.ssh/config ที่มีอยู่

  • การถ่ายโอนที่สามารถดำเนินการต่อได้สำหรับไฟล์ขนาดใหญ่และการเชื่อมต่อที่ไม่เสถียร

  • ไทม์ไลน์การทำงานระยะไกล — คำสั่ง การถ่ายโอน และการตัดสินใจด้านการป้องกันในเส้นทางการตรวจสอบเดียว

  • เพลย์บุ๊กการแก้ไขปัญหา SSH ที่พร้อมใช้

  • บันทึกคอนเทนเนอร์โดยไม่ต้องลงไปที่เชลล์เสร็จสิ้น: ssh_log_tail และ ssh_log_search รับชื่อคอนเทนเนอร์ ถาม docker ว่ามันเขียนที่ไหน และอ่านไฟล์นั้นด้วยกลไกเดียวกับบันทึกอื่น ๆ

  • การปฏิเสธที่ทำให้คุณติดอยู่เสร็จสิ้น: ทุกข้อจำกัดตอนนี้ระบุ ssh_exec เป็นทางผ่าน ดังนั้นการถึงขอบของเครื่องมือใช้เพียงหนึ่งประโยคแทนการเดา

  • คำตอบที่ไปถึงโมเดลเสร็จสิ้น: ผลลัพธ์คำสั่ง บรรทัดบันทึกที่ตรงกัน ชื่อเครื่อง และส่วนสแนปช็อตเดินทางในฟิลด์ ไม่ใช่เฉพาะในข้อความ

  • สคีมาเครื่องมือ MCP ที่เล็กลงเสร็จสิ้น: รายการเครื่องมือเบาลง 10% และงานที่แยกออกไปตอนนี้แสดงบรรทัดสุดท้ายที่เขียนแทนการถูกสอบถามแบบไม่เห็นอะไร

  • งานยาวภายใต้ rootเสร็จสิ้น: งานที่แยกออกไปรันด้วย sudo และถูกติดตามเป็น root และโปรไฟล์ที่ใช้คีย์เท่านั้นตอบ sudo ด้วย sudoPassword ของตัวเอง

พัฒนาและทดสอบ 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

ยินดีรับ Issues และ Pull Requests ที่ github.com/hypnosis/ssh-mcp-server

สัญญาอนุญาต

MIT — ดู LICENSE