运维这行,最近多了一个尴尬的新场景:你想让 AI 帮你上服务器干活——查负载、看日志、改配置、重启服务——但真把 SSH 交给它,又总觉得心里没底。
不底在哪?三件事:
- 重连风暴:很多「AI + SSH」的接法是每执行一条命令就
ssh user@host '...'起一个新进程。十条命令十次握手,既慢,在服务器侧的审计里还像一次小型暴力探测。 - 凭据裸奔:为了让 AI 能连,密码 / 私钥路径常常直接塞进提示词或配置,模型上下文里、日志里、中转里到处都是。
- 黑盒执行:AI 直接对着公网端口发命令,谁来挡住跨域脚本、DNS 重绑定、被注入的「顺手
rm -rf」?
我在做 Conch 时,想把这三件事按运维的标准重做一遍。它是一个 SSH / ADB 客户端:r-shell 一个二进制就能管理连接、跑远程命令、开交互式 shell、走 SFTP 传文件、打系统快照;同时内置一个 MCP 服务器,让 AI 助手通过「一条常驻 SSH 会话」来操作服务器。还有一个桌面应用——Flutter 写界面、Rust 写内核,带标签页终端、命令块、实时监控。
这篇不堆功能,而是讲清楚一件运维人会关心的事:怎么让 AI 真正能上手干运维,同时把连接、凭据、执行边界牢牢攥在自己手里。 文中细节都对应仓库里可跑的实现。

它解决了什么运维痛点
先把痛点摆出来,再看 Conch 怎么逐个回应:
| AI 做运维时的痛点 | Conch 的回应 |
|---|---|
每条命令一次 ssh,重连风暴、又慢又像攻击 | 常驻会话:ssh_session_open 开一次,后续 ssh_exec 复用同一条 socket,不重连 |
| 密码 / 私钥塞进提示词、配置、日志,到处裸奔 | 凭据只进不出:列表只返回 has_password / has_private_key_path 布尔值,绝不回吐明文 |
| AI 直连公网端口,跨域 / DNS 重绑定无人拦 | MCP 只绑 127.0.0.1,中间件强校验 Host / Origin,非回环一律 403 |
| 首次连陌生主机,中间人也照连不误 | 主机密钥 TOFU(首次信任)按 known_hosts 校验,变更即中止 |
| 配置文件全局可读,等于把跳板机摊开 | workspace.json 在 Unix 上 0600 / 目录 0700,仅属主可读写 |
| 装一堆依赖(OpenSSL/libssh)才能编出来 | 纯 Rust 的 russh,不依赖 OpenSSL,Windows 也能出零依赖包 |
下面把这些「回应」背后的设计拆开讲。
一句话设计哲学:连接归 Conch,AI 只借一条会话
很多「AI 运维」的做法,是把一台主机的 SSH 能力整个交给模型:凭据给它、端口给它、命令它说了算。这等于把跳板机的钥匙复制了一把塞进一个你无法完全控制、还可能被提示词注入的黑盒。
Conch 反过来:连接和凭据由 Conch 持有,AI 只是借用一条已经建立好的会话去执行只读 / 受控的操作。
- 连接归 Conch:TCP、SSH 握手、公钥认证、主机密钥校验、会话生命周期,全在 Rust 内核里,确定、可复现。
- AI 借会话:模型通过 MCP 工具说「在
session_id上跑这条命令」「读这个文件」,它看不到也拿不到底层凭据。 - 边界归本机:MCP 只在
localhost上服务,且强校验来源,杜绝从浏览器 / 跨域 / 重绑定域名摸进来。
这条原则会贯穿后面每一节。
技术选型:为什么是 Flutter + Rust,且不依赖 OpenSSL
三个关键决策:
- 界面用 Flutter:跨平台、动画顺滑,标签页终端 / 命令块 / 实时图表都好做;桌面三端一套代码。
- 内核用 Rust:SSH、SFTP、并发监控是又要正确又要扛得住的活儿,Rust 的所有权和类型系统能把「会话状态、凭据边界」这些不变量编译进类型里。SSH 栈用纯 Rust 的
russh,砍掉 OpenSSL / libssh 的系统依赖——这对「在 Windows 上出一个双击即用、零依赖的运维客户端」太重要了。 - 二者同进程:桌面端通过
flutter_rust_bridge直接调用 Rust 内核(FFI 生成绑定),不开子进程、不起额外的本地服务。CLI 版r-shell则把同一套core直接编进单一二进制。
桌面端和命令行版共用同一个 core:同样的连接管理、同样的 SSH 实现、同样的 MCP 服务器。你在 GUI 里存的连接,CLI 和 MCP 都认;反之亦然。
架构分层
┌───────────────────────────┐
Flutter 桌面 UI ──┤ flutter_rust_bridge (FFI) ├──┐
└───────────────────────────┘ │
▼
r-shell CLI ─────────────────────────────▶ core(共享内核)
├── native_backend SSH/SFTP、连接管理器(常驻会话)
├── storage workspace.json(连接持久化,0600)
├── model SavedConnection / 脱敏 sanitized()
└── mcp Streamable HTTP + 工具路由 + 来源校验
conch/
├── cli/ # r-shell:CLI + MCP 服务器(Rust)
├── core/ # 共享的 SSH / MCP 核心库
├── desktop/ # 桌面应用(Flutter 界面 + Rust 内核)
├── packaging/ # macOS .dmg 与 Windows 安装器脚本
└── .github/ # CI:测试与发布构建
无论你从桌面端点「启动 MCP」,还是命令行跑 r-shell mcp,起来的都是 core/src/mcp.rs 里同一个服务器,监听 http://127.0.0.1:9123/mcp。
核心:一条常驻 SSH 会话,才是 AI 运维该有的样子
这是 Conch 对运维最实在的价值。MCP 内核里有一个长生命周期的连接管理器(NativeConnectionManager),按 session_id 持有一条条活着的 SSH 连接:
ssh_session_open开一次会话(用已存连接的 id/名称,或临时 host/user),返回session_id;- 之后的
ssh_exec/ssh_read_file/ssh_write_file/ssh_list_dir全部复用这条连接,不再重新握手; - 同一会话可以反复用,直到你显式
ssh_session_close。
为什么较真这件事?因为「每条命令重连一次」在运维语境里有三宗罪:慢(每次都付 TCP + SSH + 认证的钱)、吵(服务器审计里一串短连接像探测)、状态丢失(上一条命令的工作目录、环境都没了)。常驻会话把这些一次性解决——开一次,干一串活。
MCP 暴露的会话与连接工具:
| 工具 | 作用 |
|---|---|
ssh_session_open | 打开 / 复用一条常驻 SSH 会话,返回 session_id |
ssh_exec | 在会话上执行命令(复用连接,不重连) |
ssh_read_file | 读远程文件(UTF-8,二进制自动转 base64) |
ssh_write_file | 创建 / 覆盖远程文件(文本或 base64) |
ssh_list_dir | 列远程目录(Linux 主机) |
ssh_sessions_list / ssh_session_close | 列出 / 关闭活动会话 |
r_shell_ssh_connections_list | 列出已保存连接(凭据已脱敏) |
r_shell_ssh_connection_create / _update / _delete | 管理已保存连接 |

让运维敢把 SSH 交出去的安全模型
常驻会话好用,但「好用」不能以「失控」为代价。Conch 的 MCP 有一组面向运维的安全边界,写在 core/src/mcp.rs 里,并带单测:
1. 只在 localhost 服务,且强校验来源
服务器只 bind 到 127.0.0.1。但只绑回环还不够——一个恶意网页,或一个解析到 127.0.0.1 的攻击者域名(DNS 重绑定),仍可能从你浏览器里发起请求。所以中间件 validate_local_origin 同时要求:
Host头必须是回环(127.0.0.1/localhost/[::1])。这正是挡 DNS 重绑定的关键:浏览器会把攻击者域名写进Host,对不上就403。- 若带
Origin,必须是回环Origin;跨站、以及那个臭名昭著的null(沙箱 iframe /file://)一律拒绝。非浏览器的 MCP 客户端没有Origin,放行。
// 任一不满足即 403:防跨域 + 防 DNS 重绑定
if !host_is_loopback(host) { return StatusCode::FORBIDDEN; }
if let Some(origin) = origin { if !origin_is_loopback(origin) { return 403; } }
2. 凭据只进不出——AI 永远看不到密码和私钥
这条是运维的底线。任何返回连接信息的接口,走的都是 SavedConnection::sanitized():密码、私钥路径、口令一律不返回,只暴露 has_password / has_private_key_path 这种布尔值。
也就是说,哪怕 AI 把 r_shell_ssh_connections_list 翻烂,它能知道「这台用公钥认证」,但拿不到那把私钥在哪、更别说内容。凭据从 GUI / CLI 进入 workspace.json,在 MCP 这一侧只出脱敏视图。
3. 主机密钥 TOFU,变更即中止
连接按 ~/.ssh/known_hosts 做首次信任(TOFU):第一次记录主机密钥,之后必须一致。一旦对不上(典型的中间人 / 主机被换),直接中止连接,而不是默默连上去。只有你显式传 --insecure 才跳过——那是留给一次性测试机的,不是日常运维姿势。
4. 连接配置仅属主可读
workspace.json(存着你所有跳板信息)在 Unix 上以 0600 创建,目录 0700。跳板机配置不该是「同机器上任何进程都能 cat」的东西。
这些不是文档里的口号:来源校验、回环判定、base64 往返等都有对应单测;凭据脱敏是连接序列化的默认路径,不是可选项。
接入 Cursor / Claude:一段配置的事
MCP 服务器走 Streamable HTTP,把客户端指向本机端点即可。以 Cursor 为例,写进 ~/.cursor/mcp.json:
{
"mcpServers": {
"conch": {
"url": "http://127.0.0.1:9123/mcp"
}
}
}
Claude Desktop 等客户端同理,把这个 URL 作为 Streamable HTTP 服务器添加后重启。然后在桌面端点亮 MCP(或命令行 r-shell mcp),AI 就能用上面那套工具去干活了。会话只活在内存里,生命周期跟着 MCP 服务进程——关掉就清干净。
实测:让 AI 通过 MCP 真连一台 Windows 取系统数据
光说不练假把式。下面是一段真实链路:不是我手敲 ssh,而是 AI 通过 Conch 的 MCP,让 Conch 去连一台局域网里的 Windows 11,然后取运维盘点数据。全程复用同一条会话。
握手与开会话(initialize → tools/list 拿到 12 个工具 → ssh_session_open):
ssh_session_open -> reused = false | session = ssh-1782117733340
host=192.168.0.112 user=shanh port=22 (publickey)
随后在同一条会话上连发数条命令(每次 reused = true,证明没有重连)。这台默认 shell 是 PowerShell,于是用 Get-CimInstance 取数,并设 chcp 65001 + [Console]::OutputEncoding=UTF8 解决中文乱码:
### 系统概况
OS | Microsoft Windows 11 专业工作站版 10.0.29591
架构 | 64 位
主机 | SHANHAIMAGEGOJO
用户 | WORKGROUP\shanh
CPU | Intel(R) Core(TM) i7-9700 @ 3.00GHz (8 逻辑核)
内存 | 15.9 GB
开机 | 2026-06-16 14:38 已运行 174.4 小时
### 磁盘
C: 61.8/118.1 GB 空闲 D: 157.6/180.7 F: 130.8/149.4 G: 86.9/135.7
### IPv4 网卡
WLAN : 192.168.0.112 ← 真实局域网地址
Meta : 198.18.0.1 ← Clash/Mihomo TUN 虚拟网卡
### 内存占用 Top5
Memory Compression 470MB · svchost 398 · explorer 395 · MsMpEng 347 · WeChatAppEx 328
整个过程:AI 只是调 MCP 工具,真正连服务器、跑命令、取数据的是 Conch;凭据没有进过模型上下文;一条会话从头复用到尾;干完一句 ssh_session_close 收场,内存里不留连接。这就是「AI 借会话干运维」该有的样子。

同一套能力对 Linux 主机更顺手:
ssh_list_dir依赖 GNUls、系统快照依赖/proc,在 Linux 上开箱即用;Windows 则用ssh_exec跑 PowerShell 取数同样顺。
顺带一提:它本身也是个能打的运维客户端
抛开 AI,Conch 桌面端就是个趁手的日常工具:
- 命令块终端:每条命令和它的输出各成一块,带退出码、耗时,工作目录在块之间保持——翻历史、定位「哪条命令挂了」一目了然。
- 实时监控:CPU / 内存 / 磁盘 / 网络实时走势图,连上去就能看。
- SFTP:拖拽上传下载。
- 多标签:一屏管多台。

适用与不适用
- 适合:想让 AI(Cursor / Claude)安全地参与日常运维——盘点、查日志、改配置、看监控,又不愿把密码私钥喂给模型;喜欢「一条会话干一串活」而不是重连风暴;需要一个 macOS / Linux / Windows 通吃、零依赖好分发的 SSH 客户端。
- 暂不适合:把 AI 当「无人值守全自动运维」的预期——Conch 的定位是给 AI 一条受控、可观测、可随时切断的会话,关键变更仍建议人来确认;
ls/ 系统快照面向 Linux,Windows 上请用ssh_exec取数。 - 平台:macOS / Linux / Windows。桌面端运行时已打包,Windows 安装器 / 便携版双击即用,macOS 解压拖进「应用程序」即可。
开源与下载
Conch 已开源(MIT),由 极数本源(apizero.cn)· MageGojo 出品:
- 源码:github.com/MageGojo/conch
- 下载(桌面端 / CLI):Releases
- 中文文档:仓库内
README.zh-CN.md
桌面端构建已把运行时一并打包:Windows 出 Conch-windows-x64-setup.exe(安装器,VC++ 运行时内置)和便携版 .zip;macOS 出 Conch-macos.zip。命令行 r-shell 随项目单独提供(macOS DMG / Windows 安装器)。因为是没买付费证书的开源软件,首次打开时 macOS 右键「打开」、Windows 选「更多信息 → 仍要运行」即可。
写在最后
「让 AI 上服务器干运维」和「不把跳板机交出去」并不矛盾——只要你把连接和凭据留在自己内核里,只借给 AI 一条受控、脱敏、绑死在 localhost 的会话。Conch 想证明的就是这件事:AI 可以很好用,但它该是个借会话的执行者,而不是握着钥匙的主人。
如果你也在折腾 AI 运维、或者在纠结「到底该给模型多大的服务器权限」,希望这套「连接归 Conch、AI 借会话、边界归本机」的思路能给你一点参考。觉得有用就去仓库点个 star,聊聊你的运维场景,我会持续更新。
⚠️ 免责声明:本项目仅供学习与合法运维使用。SSH / 命令执行 / 文件读写均会对远程主机产生实际影响,使用者应自行确认操作对象与命令内容,并对重要数据做好备份。请仅在你拥有合法授权的主机上使用;使用本工具产生的一切后果由使用者自行承担。


1120

被折叠的 条评论
为什么被折叠?



