SSH — policy-gated remote access
ภาพรวม
คำอธิบายจากผู้ทำ (ภาษาอังกฤษตามต้นฉบับ)
Policy-gated, audited SSH for Linux and Windows hosts: roles, approvals, and an audit log.
ใช้ทำอะไรได้
ตัวนี้ยังไม่ได้เรียบเรียงเป็นภาษาไทย ด้านล่างคือข้อเท็จจริงที่เราอ่านจาก registry
- การเชื่อมต่อ: รันบนเครื่อง
- ช่องทาง (transport): stdio
- หมวด: เครื่องมือนักพัฒนา
- ต้องใส่ค่าเหล่านี้: SSH_MCP_PASSWORD, SSH_MCP_PASSPHRASE, SSH_MCP_SUDO_PASSWORD
ติดตั้ง
เลือกโปรแกรม AI ที่คุณใช้ แล้วคัดลอกค่าตั้งไปวาง
ผลตรวจผ่าน 2/2 · ทำงานบนเครื่องคุณ
ขั้นแรก: คุณใช้ AI ตัวไหน
เลือกแอปที่คุณใช้ ขั้นตอนจะขึ้นด้านล่าง
ต่อกับ Claude ได้ แต่ต้องเตรียมก่อน
ต้องมีคีย์ของ SSH — policy-gated remote access (สมัครที่เว็บของผู้ทำ อาจมีค่าใช้จ่าย) · ต้องลง Node.js ในเครื่องก่อน (ทำครั้งเดียว) · ใช้ได้เฉพาะแอป Claude บนคอม (Windows หรือ Mac) ไม่ใช่บนเว็บหรือมือถือ
สมัครและสร้างคีย์ของ SSH — policy-gated remote access
เปิดเว็บของผู้ทำ สมัครบัญชีแล้วสร้างคีย์ (API key) เก็บไว้ ใช้ในขั้นถัดไป อาจมีค่าใช้จ่าย
เปิดไฟล์ตั้งค่าของแอป Claude บนคอม
SettingsDeveloperEdit Config
วางค่าตั้งนี้แล้วบันทึกไฟล์
{ "mcpServers": { "ssh": { "command": "npx", "args": [ "-y", "ssh-mcp" ], "env": { "SSH_MCP_PASSWORD": "ใส่ค่าของคุณ", "SSH_MCP_KEY": "ใส่ค่าของคุณ", "SSH_MCP_PASSPHRASE": "ใส่ค่าของคุณ", "SSH_MCP_SUDO_PASSWORD": "ใส่ค่าของคุณ" } } } }วางคีย์ในช่องของแอปเท่านั้น อย่าวางในแชตหรือส่งให้ใคร
ปิดแอป Claude แล้วเปิดใหม่
ลองเลย
ใช้ SSH — policy-gated remote access บอกหน่อยว่าทำอะไรให้ฉันได้บ้าง แล้วลองทำให้ดูหนึ่งอย่าง✓ ถ้า Claude บอกว่ากำลังใช้ SSH — policy-gated remote access หรือมีชื่อเครื่องมือของ SSH — policy-gated remote access ขึ้นในคำตอบ แปลว่าต่อสำเร็จ
ชื่อเมนูตรวจกับหน้าช่วยเหลือของ Anthropic เมื่อ 11 พ.ย. 2569 · หน้าจอของคุณอาจต่างเล็กน้อยตามรุ่นของแอป
ChatGPT ยังต่อ SSH — policy-gated remote access ไม่ได้
SSH — policy-gated remote access ต้องติดตั้งในเครื่องคุณ แต่ ChatGPT ต่อได้เฉพาะตัวที่ทำงานบนเว็บ
คุณทำแบบนี้แทนได้
ก · ใช้แอปที่ต่อ SSH — policy-gated remote access ได้
- ต้องมีคีย์ของ SSH — policy-gated remote access (สมัครที่เว็บของผู้ทำ อาจมีค่าใช้จ่าย) · ต้องลง Node.js ในเครื่องก่อน (ทำครั้งเดียว) · ใช้ได้เฉพาะแอป Claude บนคอม (Windows หรือ Mac) ไม่ใช่บนเว็บหรือมือถือ
- ต้องมีคีย์ของ SSH — policy-gated remote access (สมัครที่เว็บของผู้ทำ อาจมีค่าใช้จ่าย) · ต้องลง Node.js ในเครื่องก่อน (ทำครั้งเดียว)
- ต้องมีคีย์ของ SSH — policy-gated remote access (สมัครที่เว็บของผู้ทำ อาจมีค่าใช้จ่าย) · ต้องลง Node.js ในเครื่องก่อน (ทำครั้งเดียว)
- ต้องมีคีย์ของ SSH — policy-gated remote access (สมัครที่เว็บของผู้ทำ อาจมีค่าใช้จ่าย) · ต้องลง Node.js ในเครื่องก่อน (ทำครั้งเดียว)
ข · ตัวอื่นในหมวด เครื่องมือนักพัฒนา ที่ต่อกับ ChatGPT ได้
เลือกจากตัวที่ใช้มากในหมวดเดียวกัน เฉพาะตัวที่ต่อด้วยที่อยู่ได้โดยไม่ต้องใส่คีย์
- Sentry✓ ChatGPT
- Front-End Checklist✓ ChatGPT
- Compiler Explorer✓ ChatGPT
ต่อกับ Claude Code ได้ แต่ต้องเตรียมก่อน
ต้องมีคีย์ของ SSH — policy-gated remote access (สมัครที่เว็บของผู้ทำ อาจมีค่าใช้จ่าย) · ต้องลง Node.js ในเครื่องก่อน (ทำครั้งเดียว)
สมัครและสร้างคีย์ของ SSH — policy-gated remote access
เปิดเว็บของผู้ทำ สมัครบัญชีแล้วสร้างคีย์ (API key) เก็บไว้ ใช้ในขั้นถัดไป อาจมีค่าใช้จ่าย
เปิด Terminal
Mac: กด Command+Space พิมพ์ Terminal · Windows: เปิด PowerShell
วางคำสั่งนี้แล้วกด Enter
claude mcp add ssh --env SSH_MCP_PASSWORD='ใส่ค่าของคุณ' --env SSH_MCP_KEY='ใส่ค่าของคุณ' --env SSH_MCP_PASSPHRASE='ใส่ค่าของคุณ' --env SSH_MCP_SUDO_PASSWORD='ใส่ค่าของคุณ' -- npx -y ssh-mcpแก้ “ใส่ค่าของคุณ” เป็นคีย์ของคุณก่อนกด Enter
วางคีย์ในช่องของแอปเท่านั้น อย่าวางในแชตหรือส่งให้ใคร
พิมพ์ /mcp ใน Claude Code
ต้องเห็น SSH — policy-gated remote access ในรายการและขึ้นว่าเชื่อมต่อแล้ว
ลองเลย
ใช้ SSH — policy-gated remote access บอกหน่อยว่าทำอะไรให้ฉันได้บ้าง แล้วลองทำให้ดูหนึ่งอย่าง✓ ถ้า Claude Code บอกว่ากำลังใช้ SSH — policy-gated remote access หรือมีชื่อเครื่องมือของ SSH — policy-gated remote access ขึ้นในคำตอบ แปลว่าต่อสำเร็จ
ชื่อเมนูตรวจกับหน้าช่วยเหลือของ Anthropic เมื่อ 11 พ.ย. 2569 · หน้าจอของคุณอาจต่างเล็กน้อยตามรุ่นของแอป
ต่อกับ Cursor ได้ แต่ต้องเตรียมก่อน
ต้องมีคีย์ของ SSH — policy-gated remote access (สมัครที่เว็บของผู้ทำ อาจมีค่าใช้จ่าย) · ต้องลง Node.js ในเครื่องก่อน (ทำครั้งเดียว)
สมัครและสร้างคีย์ของ SSH — policy-gated remote access
เปิดเว็บของผู้ทำ สมัครบัญชีแล้วสร้างคีย์ (API key) เก็บไว้ ใช้ในขั้นถัดไป อาจมีค่าใช้จ่าย
ใส่คีย์ในช่องที่ว่างไว้
ในค่าตั้งของ SSH — policy-gated remote access ช่อง SSH_MCP_PASSWORD, SSH_MCP_KEY, SSH_MCP_PASSPHRASE, SSH_MCP_SUDO_PASSWORD ยังว่าง ใส่คีย์ของคุณแล้วบันทึก
วางคีย์ในช่องของแอปเท่านั้น อย่าวางในแชตหรือส่งให้ใคร
เปิดแชตของ AI ใน Cursor โหมด Agent
ลองเลย
ใช้ SSH — policy-gated remote access บอกหน่อยว่าทำอะไรให้ฉันได้บ้าง แล้วลองทำให้ดูหนึ่งอย่าง✓ ถ้า Cursor บอกว่ากำลังใช้ SSH — policy-gated remote access หรือมีชื่อเครื่องมือของ SSH — policy-gated remote access ขึ้นในคำตอบ แปลว่าต่อสำเร็จ
ชื่อเมนูตรวจกับหน้าช่วยเหลือของ Cursor เมื่อ 11 พ.ย. 2569 · หน้าจอของคุณอาจต่างเล็กน้อยตามรุ่นของแอป
ต่อกับ VS Code ได้ แต่ต้องเตรียมก่อน
ต้องมีคีย์ของ SSH — policy-gated remote access (สมัครที่เว็บของผู้ทำ อาจมีค่าใช้จ่าย) · ต้องลง Node.js ในเครื่องก่อน (ทำครั้งเดียว)
สมัครและสร้างคีย์ของ SSH — policy-gated remote access
เปิดเว็บของผู้ทำ สมัครบัญชีแล้วสร้างคีย์ (API key) เก็บไว้ ใช้ในขั้นถัดไป อาจมีค่าใช้จ่าย
ใส่คีย์ในช่องที่ว่างไว้
ในค่าตั้งของ SSH — policy-gated remote access ช่อง SSH_MCP_PASSWORD, SSH_MCP_KEY, SSH_MCP_PASSPHRASE, SSH_MCP_SUDO_PASSWORD ยังว่าง ใส่คีย์ของคุณแล้วบันทึก
วางคีย์ในช่องของแอปเท่านั้น อย่าวางในแชตหรือส่งให้ใคร
เปิดแชตของ AI ใน VS Code โหมด Agent
ลองเลย
ใช้ SSH — policy-gated remote access บอกหน่อยว่าทำอะไรให้ฉันได้บ้าง แล้วลองทำให้ดูหนึ่งอย่าง✓ ถ้า VS Code บอกว่ากำลังใช้ SSH — policy-gated remote access หรือมีชื่อเครื่องมือของ SSH — policy-gated remote access ขึ้นในคำตอบ แปลว่าต่อสำเร็จ
ชื่อเมนูตรวจกับหน้าช่วยเหลือของ VS Code เมื่อ 11 พ.ย. 2569 · หน้าจอของคุณอาจต่างเล็กน้อยตามรุ่นของแอป
สำหรับคนเขียนโค้ด: คำสั่ง Terminal และค่าตั้ง JSON
ติดตั้งในเครื่อง
Claude Code
claude mcp add ssh --env SSH_MCP_PASSWORD='ใส่ค่าของคุณ' --env SSH_MCP_KEY='ใส่ค่าของคุณ' --env SSH_MCP_PASSPHRASE='ใส่ค่าของคุณ' --env SSH_MCP_SUDO_PASSWORD='ใส่ค่าของคุณ' -- npx -y ssh-mcpClaude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": [
"-y",
"ssh-mcp"
],
"env": {
"SSH_MCP_PASSWORD": "ใส่ค่าของคุณ",
"SSH_MCP_KEY": "ใส่ค่าของคุณ",
"SSH_MCP_PASSPHRASE": "ใส่ค่าของคุณ",
"SSH_MCP_SUDO_PASSWORD": "ใส่ค่าของคุณ"
}
}
}
}Cursor (~/.cursor/mcp.json)
{
"mcpServers": {
"ssh": {
"command": "npx",
"args": [
"-y",
"ssh-mcp"
],
"env": {
"SSH_MCP_PASSWORD": "ใส่ค่าของคุณ",
"SSH_MCP_KEY": "ใส่ค่าของคุณ",
"SSH_MCP_PASSPHRASE": "ใส่ค่าของคุณ",
"SSH_MCP_SUDO_PASSWORD": "ใส่ค่าของคุณ"
}
}
}
}VS Code (mcp.json)
{
"servers": {
"ssh": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"ssh-mcp"
],
"env": {
"SSH_MCP_PASSWORD": "ใส่ค่าของคุณ",
"SSH_MCP_KEY": "ใส่ค่าของคุณ",
"SSH_MCP_PASSPHRASE": "ใส่ค่าของคุณ",
"SSH_MCP_SUDO_PASSWORD": "ใส่ค่าของคุณ"
}
}
}
}ค่าที่ต้องใส่เอง
SSH_MCP_PASSWORDความลับ envPassword for the configured profile; a per-profile SSH_MCP_ _PASSWORD takes precedence. Credentials are never accepted as CLI arguments.SSH_MCP_KEYenvPath to the private key file to authenticate with — the path, not the key material. A per-profile SSH_MCP_ _KEY takes precedence.SSH_MCP_PASSPHRASEความลับ envPassphrase for an encrypted private key.SSH_MCP_SUDO_PASSWORDความลับ envPassword the sudo tool escalates with, when the policy in force allows the privileged class.
ค่าตั้งนี้สร้างจากข้อมูลใน registry ของผู้ทำ ถ้าไม่ตรงกับ README ให้เชื่อ README
สรุป
- ดาว GitHubi
- 869
- ดาวน์โหลดต่อสัปดาห์i
- 15,721/สัปดาห์
- การเชื่อมต่อ
- รันบนเครื่อง
- ช่องทาง (transport)
- stdio
- รุ่นล่าสุดi
- 2.25.0
- ส่งเข้า registryi
- 10 พ.ย. 2569
- แก้โค้ดล่าสุดi
- 10 พ.ย. 2569
- ผู้ทำ
- tufantunc
- แพ็กเกจ
npm: ssh-mcp- เว็บผู้ทำ
- github.com
- สถานะใน registry
- ใช้งานอยู่
ใช้กับโปรแกรมไหนได้
ดูจากแบบการต่อของ server ตัวนี้ และเอกสารของผู้ทำโปรแกรมแต่ละตัว ตรวจเมื่อ 10 พ.ย. 2569
ติดตั้งบนเครื่องได้ใน
ClaudeGooseLM StudioMsty StudioCherry StudioCursorVS Code + GitHub CopilotVisual StudioWindsurf (Devin Desktop)ZedKiroClineContinueJetBrains AI AssistantClaude CodeCodex CLIGemini CLIOpenCodenodecodeWarpLibreChatRaycast
คู่มือที่เกี่ยวข้อง
ทำอะไรได้บ้าง
รันในเครื่องคุณ รายการเครื่องมือจะขึ้นในแอป AI หลังติดตั้ง
ผลตรวจเบื้องต้นi
เราตรวจจากข้อมูลที่ใครก็เปิดดูได้ ยังไม่ได้อ่านโค้ด ข้อที่ไม่เกี่ยวกับตัวนี้ไม่นับในตัวหาร · ตรวจเมื่อ 11 พ.ย. 2569
- ✓ ผ่าน
ตัวตนผู้ทำตรงกับ repo
ชื่อใน registry ยืนยันด้วยบัญชี GitHub tufantunc ซึ่งเป็นเจ้าของ repo
- ✓ ผ่าน
ยังมีคนดูแล
มีการแก้โค้ดล่าสุด เมื่อวาน
- … ยังไม่ตรวจ
มีสัญญาอนุญาต (license)
ยังไม่ได้อ่านข้อมูล repo จาก GitHub
- – ไม่เกี่ยว
endpoint ตอบ
ตัวนี้รันบนเครื่องคุณ ไม่มี endpoint บนอินเทอร์เน็ต
- – ไม่เกี่ยว
ล็อกอินแบบ OAuth
ตัวนี้รันบนเครื่อง ใช้ค่าที่ตั้งในเครื่องแทน
- … ยังไม่ตรวจ
คำอธิบายเครื่องมือไม่มีคำสั่งแอบแฝง
รันในเครื่องคุณ เราอ่านรายการเครื่องมือได้เฉพาะตัวที่มี endpoint บนอินเทอร์เน็ต
พูดคุย
ถาม แชร์เคล็ดลับ หรือแจ้งว่าใช้ไม่ได้ เรียงตามที่คนกดว่ามีประโยชน์
ยังไม่มีใครโพสต์ ถามหรือแชร์เป็นคนแรกได้เลย
ข้อความในส่วนนี้เขียนโดยผู้ใช้ ไม่ใช่ทีม PopNx
รีวิวจากผู้ใช้
ยังไม่มีรีวิว
เทียบกับตัวอื่นในหมวด เครื่องมือนักพัฒนาi
- ดาวมากกว่า 99% ของอีก 5755 ตัวในหมวดนี้
- ส่งรุ่นใหม่เข้า registry ล่าสุดกว่า 96% ของอีก 5755 ตัวในหมวดนี้
- ผลตรวจเบื้องต้นดีกว่าหรือเท่ากับ 100% ของอีก 5755 ตัวในหมวดนี้
เทียบกับทุก server ที่ยังใช้งานในหมวดนี้ทั้งทะเบียน ดาวนับเฉพาะเมื่อผู้ลงทะเบียนเป็นเจ้าของ repo
คำถามที่พบบ่อย
SSH — policy-gated remote access ปลอดภัยไหม?
จากการตรวจเบื้องต้นของเรา ผ่าน 2 จาก 2 ข้อที่ตรวจได้ เรายังไม่ได้อ่านโค้ด ก่อนใส่กุญแจหรือ token ให้ดูว่า server ขอสิทธิ์อะไร และเลือกกุญแจที่ทำได้เท่าที่จำเป็น
ต้องใช้กุญแจหรือรหัสอะไรบ้าง?
ต้องใส่ค่าเหล่านี้: SSH_MCP_PASSWORD, SSH_MCP_PASSPHRASE, SSH_MCP_SUDO_PASSWORD
ตัวนี้รันบนเครื่องหรือบนคลาวด์?
รันบนเครื่องของคุณ โปรแกรม AI จะเปิด server ขึ้นมาเองเมื่อใช้ ข้อมูลไม่ต้องผ่านเซิร์ฟเวอร์ของผู้ทำ (ยกเว้นตัวที่ไปเรียกบริการออนไลน์ต่อ)
ยังมีคนดูแลอยู่ไหม?
repo บน GitHub มีการแก้โค้ดล่าสุด เมื่อวาน และส่งรุ่นล่าสุด (2.25.0) เข้า registry เมื่อวาน
ใช้กับโปรแกรมไหนได้บ้าง?
โปรแกรมที่รองรับ MCP เช่น Claude Desktop, Claude Code, Cursor และ VS Code ตัวนี้ต้องมี Node.js ในเครื่องด้วย
มีตัวไหนใช้แทนได้บ้าง?
ในหมวดเดียวกันมี REA, Netdata, Front-End Checklist
ตัวที่ใช้แทนได้
server หมวดเดียวกันจากผู้ทำคนอื่น เรียงตามดาว
อ่านการ์ด:↓ ดาวน์โหลดต่อสัปดาห์i★ ดาว GitHubiสามเสา: รีวิว · ผลตรวจ · การใช้งานiอัปเดต = วันที่ส่งรุ่นล่าสุดเข้า registryi
README จากผู้ทำ
เปิดอ่าน README
ส่วนนี้คัดจาก repo ของผู้ทำตามต้นฉบับ PopNx MCP ไม่ได้ตรวจหรือรับรองเนื้อหา ตัด HTML รูปภาพ และสคริปต์ออกแล้ว ลิงก์จะพาออกนอกเว็บ
SSH MCP Server v2
SSH MCP Server is a security-first Model Context Protocol server that gives LLM agents controlled SSH access to remote hosts — with command classification, policy-based authorization, human-in-the-loop approval, and full audit logging.
The risk this server exists to manage. Giving an LLM shell access on a remote host puts private data, untrusted input and network egress in one place — Simon Willison's "lethal trifecta". Prompt injection has no general fix, so ssh-mcp assumes any command may be attacker-influenced: it classifies before executing, authorizes against a role × host-group matrix, gates destructive work behind approval, and records the decision either way. That narrows the blast radius; it does not remove the risk. Two things stay yours: never point it at a root account, and never set `auto` approval on a production profile. SECURITY.md has the full threat model.
Quick Start
1. Install
npm install -g ssh-mcp
2. Configure
Without a config the server still starts, so a client or directory can complete the MCP handshake and read tools/list — but every tool call is refused until you configure it, with a message naming the path below. Nothing runs on a host until this step is done. The one exception is reload-config: write the file, then call it with action: "reload" (or restart the server) to configure a server that is already running — see Reloading.
Create the config file at the path for your platform:
| Platform | Path |
|---|---|
| Linux | ~/.config/ssh-mcp/config.toml (or $XDG_CONFIG_HOME/ssh-mcp/config.toml) |
| macOS | ~/Library/Application Support/ssh-mcp/config.toml |
| Windows | %APPDATA%\ssh-mcp\config.toml |
[defaults]
defaultProfile = "dev" approvalMode = "ask-destructive"
[[profiles]] name = "dev" host = "192.168.1.100" port = 22 user = "deploy" # NOT root! auth = "key" keyRef = "~/.ssh/id_ed25519" role = "admin" approvalPolicy = "auto" # dev is permissive
chmod 700 ~/.config/ssh-mcp && chmod 600 ~/.config/ssh-mcp/config.toml
The config decides which hosts, roles and policy rules this server honours, so it checks that nobody but you can read it — and treats the two platforms differently, because the question has a much clearer answer on one of them.
Linux and macOS: enforced. The mode check above, on the file *and* the directory — which is why chmod 700 is in that command, since mkdir -p under the default umask leaves the directory 0755. The server refuses to start otherwise. "Only the owner" is unambiguous here and chmod is a one-line fix.
Windows: split by what the ACL actually allows. There are no mode bits, so the ACL is read instead — and read exposure and write exposure are not treated alike, because Windows is much clearer about one of them than the other.
| The ACL lets another account… | Default |
|---|---|
| only read the config | reported, and the server starts |
| change the config | refused |
| nothing (no ACL at all) | refused — that is full control for everyone |
| …and if the ACL could not be read | refused, except when icacls is absent or the check timed out |
A config under %APPDATA% inherits access for you, SYSTEM and Administrators and needs nothing done to it. One created elsewhere does not: a file under C:\ inherits *read* for every local account and *modify* for every authenticated one. The message names the two icacls commands that fix it either way.
Read exposure is reported rather than refused because that is where Windows is genuinely muddier than POSIX, and refusing over it blocked a config at the documented location (#138). Write exposure is refused because it is not muddy at all: another account being able to rewrite the file that decides which hosts, roles and approval policy this server honours is an authorization bypass, not a disclosure.
Two flags move the whole thing: --strictConfigAcl refuses everything the check objects to, read-only grants included; --allowUncheckedConfigAcl reports everything and refuses nothing. Neither combination leaves you without an exit, which is the lesson of #138.
Exit statuses
| Status | Meaning |
|---|---|
0 | Clean shutdown |
1 | A defect in the server — printed with a stack trace; please report it |
2 | How it was invoked or configured — printed as a message, no stack |
A supervisor that treats any non-zero status as a failure needs no change. One that matched on 1 to detect a startup problem should match on 2 as well.
Starting with nothing configured is not an exit-2 condition, as of the release that added introspection without a config: the server starts so it can be described, and refuses each tool call instead, except reload-config. A supervisor that used a non-zero exit to catch an unconfigured deployment should watch for starting unconfigured on stderr, or read configured from GET /health when running the HTTP transport.
3. Set credentials via environment variables
export SSH_MCP_PASSWORD="your-password" # if using auth=password
OR use SSH agent (recommended):
export SSH_AUTH_SOCK="$SSH_AUTH_SOCK" # already set if agent running
4. Connect from your MCP client
Claude Code:
claude mcp add --transport stdio ssh-mcp -- ssh-mcp
Claude Desktop / Cursor / Windsurf:
{
"mcpServers": { "ssh-mcp": { "command": "ssh-mcp", "env": { "SSH_MCP_PASSWORD": "your-password" } } } }
Never pass passwords as CLI arguments — they're visible via ps aux. Use env vars, config files, SSH agent, or OS keychain.
Tools (15)
| Tool | Purpose | readOnly | destructive |
|---|---|---|---|
list-connections | Discover available hosts and connection status | ✅ | — |
list-sessions | List active sessions per host | ✅ | — |
open-session | Create a named interactive (stateful) or background session | — | — |
close-session | Close a session. A background session's command is signalled (INT/TERM/KILL) before its channel is dropped | — | ✅ |
read-session-output | Read output from background sessions (e.g., tail -f) | ✅ | — |
read-command | Execute allowlisted read-only commands (ls, cat, grep, ...) | ✅ | — |
run-command | Execute arbitrary commands (destructive/privileged need approval, unless approvalPolicy = "auto") | — | — |
privileged-command | Execute with sudo (needs approval, unless approvalPolicy = "auto") | — | ✅ |
sftp-upload | Upload a file via SFTP (replaces the destination unconditionally) | — | ✅ |
sftp-download | Download a file via SFTP | ✅ | — |
sftp-list | List a remote directory, bounded in entries and bytes | ✅ | — |
sftp-upload-file | Stream a local file to the remote host, never through model context | — | ✅ |
sftp-download-file | Stream a remote file to local disk, never through model context | — | ✅ |
signal-process | Send INT/TERM/KILL to a remote PID | — | ✅ |
reload-config | Show the config file's status, or re-read and apply it without a restart (see Reloading) | — | ✅ |
Streaming file transfer
sftp-upload/sftp-download move file *contents* through the model's context: the text is an argument on the way out and a response on the way back. That is what you want for a config snippet and exactly what you do not want for a 200 MB tarball or anything binary.
The two also differ on what they do to an existing destination, and the approved string now says which is which. sftp-upload replaces unconditionally and spells --overwrite every time, because that is what it always does; sftp-upload-file refuses unless you pass overwrite: true, and only then carries the flag. Since sftp-upload takes its content as an argument rather than naming a local file, its string also carries --bytes= --sha256=<32 hex> — without that, two uploads to the same path are the same string, which means one approval covers both and an auditor cannot tell which set of bytes landed. The digest is 128 bits rather than a short prefix because that claim has to hold against a caller who picks both payloads, not only against an accidental repeat.
[policy].denylist patterns are tested against that whole string and, for every SFTP tool, against the remote path on its own — as given, lexically normalized, and read the way Windows reads it (see "Policy Engine"). A rule written for the path, such as authorized_keys$, therefore does not depend on where the string puts it or on how the file is spelled. A rule anchored on the *whole* string (^sftp:upload /root/.*$) still does: that layout is ours to change, so anchor on the path instead.
sftp-upload-file and sftp-download-file stream between the remote host and local disk instead. Neither the bytes nor a base64 encoding of them ever reaches the model — the response is a byte count and two paths.
The two transfer tools are off until you configure `defaults.transferRoot`, and refuse with an explanation until then. (sftp-list has no local side and needs none of this.) That directory is the whole of their local reach:
[defaults]
transferRoot = "/srv/ssh-mcp-transfers" transferMaxBytes = 268435456 # 256MB per transfer transferTimeoutMs = 300000 # 5min with no bytes moving
Checked on every call, and refused rather than degraded if any of it fails: the directory must be 0700 and owned by the account running this server, with no group- or world-writable parent, and must not overlap the ssh-mcp installation, the config directory, the audit log directory, or ~/.ssh. Caller paths are confined to it, symlinks are refused rather than followed, and a download is staged as a sibling .part file and published atomically, so a failed transfer never leaves a half-written file at the destination.
transferTimeoutMs is an idle budget, not a total one: it bounds one metadata round-trip, or one stretch of the copy with no bytes moving, and is re-armed on progress. A slow but live transfer of a large file survives it; a stalled channel still fails within one window. That is why the byte cap above does not have to be divided by it — a total budget would have made a 256MB cap mean "only if the link sustains 900 KB/s".
Not available on Windows, where the transfer root cannot yet be verified private; the two transfer tools refuse there rather than writing into a directory other accounts may be able to read.
sftp-upload-file takes an optional mode (1–511; setuid, setgid and the sticky bit are refused). Omitted, a new remote file is published 0600; an overwritten one inherits the replaced file's permission bits — its permission bits only, not its setuid or setgid.
What a transfer is authorized for includes