# aishell-mcp **Repository Path**: shawn123/aishell-mcp ## Basic Information - **Project Name**: aishell-mcp - **Description**: 替代 Xshell/PuTTY 的 SSH 终端,同时内置 MCP server 和 SFTP 文件管理器 - **Primary Language**: C# - **License**: AGPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 2 - **Created**: 2026-09-07 - **Last Updated**: 2026-09-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # AIShellMcp — 替代 Xshell 的 SSH 终端 + 文件管理器 + MCP 替代 Xshell/PuTTY 的 SSH 终端,同时内置 MCP server 和 SFTP 文件管理器: - **终端**:Avalonia 12 + WebView2 宿主 xterm.js(工业级渲染,CJK/颜色/滚动/键盘全完美) - **文件管理**:WinSCP 式双栏 UI(浏览/拖拽上传下载/右键菜单/续传) - **MCP**:LLM 通过 MCP 协议操作终端(读写输出/发命令)和文件(SFTP) - **安全**:白名单自动执行 + 非白名单审批队列 + blocklist 技术栈:C# / Avalonia 12 / .NET 10 / SSH.NET / WebView2。 > **跨平台**:GUI 基于 Avalonia 12,工程已按跨平台拆分(Core / Mcp / Gui)。 > Windows 为正式支持平台;macOS 构建与 WKWebView 终端宿主在规划中, > 详见 [docs/avalonia-gui-plan.md](docs/avalonia-gui-plan.md)。 --- ## 快速开始 **方式一:直接下载(推荐)** 前往 [Releases](../../../releases) 下载 `AIShellMcp.exe`(自包含单文件,无需安装 .NET),双击即可使用。 **方式二:自行编译** ```bat git clone https://gitee.com/legeosoft_legendzhu/aishell-mcp.git cd aishell-mcp dotnet build src\AIShellMcp.Gui\AIShellMcp.Gui.csproj -c Release ``` **要求**:Windows 10/11,WebView2 Runtime(Win11 自带)。 **发布单文件**: ```bat dotnet publish src\AIShellMcp.Gui\AIShellMcp.Gui.csproj -c Release -r win-x64 ``` 产物:`src\AIShellMcp.Gui\bin\Release\net10.0\win-x64\publish\AIShellMcp.exe`(自包含,可单独分发)。 ### macOS 构建(Apple Silicon / Intel) ```bash ./build-mac.sh # 默认 osx-arm64,Intel 传 osx-x64 cp -R build/AIShellMcp.app /Applications/ ``` 脚本自动发布 + 生成带图标的 `.app` Bundle,自包含无需安装 .NET。 > ⚠️ macOS 26+ 上 .NET 10 **压缩**单文件存在按页解压损坏问题(随机 `AccessViolationException`), > csproj 已对非 Windows 目标自动禁用压缩,macOS 产物体积约 113MB(Windows 仍为 50MB 压缩版)。 > 打包脚本**不会**对 bundle 做 codesign 重签——发布产物自带 ad-hoc 签名,拷贝即用。 --- ## 用法示例 ![终端多标签 + LLM 操作](usage1.png) ![LLM 通过 MCP 执行命令](usage2.png) ![SFTP 文件管理器](usage3.png) --- ## 架构 ``` ┌─ GUI 进程(网关/双击启动,常驻)─────────────────────────┐ │ MainWindow 多标签(xterm.js 终端) │ │ SftpWindow 双栏文件管理器 │ │ TabSession: SSH 连接 + PTY + VT + SftpManager │ │ HttpMcpServer: HTTP :8765(推荐,MCP 客户端直连) │ │ McpServer: 命名管道(供 stdio 桥,兼容 Claude Desktop) │ └──────┬──────────────────────────────────┬─────────────────┘ │ HTTP(推荐,无桥进程) │ stdio 桥(仅 Claude Desktop) │ │ MCP 客户端 ┌─────┴──────┐ (ZCode/Cursor/Trae/Cline) │ 桥 --mcp │ └─────┬──────┘ │ Claude Desktop ``` - **GUI 进程**:网关生成 `.xsh` → `AIShellMcp.exe `,单实例多标签,内置 HTTP + 命名管道两个 MCP server - **HTTP 模式(推荐)**:MCP 客户端直连 GUI 的 HTTP 端点,无中间进程,最健壮 - **stdio 桥(仅 Claude Desktop)**:`--mcp` 进程转发 stdio↔命名管道,有桥进程单点 **工程结构**(Avalonia 迁移后按层拆分,详见 [docs/avalonia-gui-plan.md](docs/avalonia-gui-plan.md)): ``` src/ ├─ AIShellMcp.Core/ # TabSession/SessionManager/CommandGuard/SFTP 配置(net10.0,跨平台) ├─ AIShellMcp.Mcp/ # HttpMcpServer/McpServer/Tools(net10.0,跨平台) └─ AIShellMcp.Gui/ # Avalonia 12 壳:多标签终端 + 文件管理器(产物 AIShellMcp.exe) ``` --- ## 接入网关 天玥堡垒机网关拉起终端的方式是 `终端.exe <生成的.xsh>`,凭据明文写在 `.xsh` 里。 在网关管理网页把「终端程序路径」从 Xshell 改成 `AIShellMcp.exe` 即可。 > ⚠️ **重要**:AIShellMcp 本身不依赖 Xshell,但天玥网关生成 `.xsh` 会话文件时,默认写入 Xshell 的用户目录(`%APPDATA%\NetSarang\Xshell\Sessions\`)。因此使用网关模式时,**机器上需要安装 Xshell**(只是不需要打开它),网关才能正常生成 `.xsh` 文件。 > > 如果不经过网关,直接用「+ 新建连接」手动填服务器信息,则**不需要安装 Xshell**。 ### PuTTY 模式 网关「终端类型」选 PuTTY 时,网关按 PuTTY 命令行约定把「终端程序路径」指向的 exe 当作 putty.exe 拉起。把该路径填成 `AIShellMcp.exe` 即可接管。 AIShellMcp 完整解析 PuTTY 命令行: ```bat AIShellMcp.exe -ssh -l root -pw PASS -P 22 10.0.0.1 AIShellMcp.exe -ssh root@10.0.0.1 -pw PASS AIShellMcp.exe -load "root@10.0.0.1" -ssh root@10.0.0.1 -pw PASS ``` - 支持 `-ssh` / `-l` / `-pw` / `-pwfile` / `-P` / `-load` / 位置参数 `[user@]host`;`-i` `-m` `-L` `-R` `-D` `-log` 等其余选项按 PuTTY 语义容错跳过 - `-load <会话名>` 会读注册表 `HKCU\Software\SimonTatham\PuTTY\Sessions\<会话名>` 的 HostName/PortNumber/UserName 作为缺省(网关会预写同名模板会话),命令行显式参数优先 - 与 Xshell 模式相同,网关 PuTTY 模式也先建本地隧道,实际连接目标是 `127.0.0.1:<隧道端口>` - 仅支持 SSH 协议;收到 `-telnet` / `-raw` / `-rlogin` 会弹窗提示不支持 - 单实例转发的参数分隔符为 `\x1f`,密码含 `|` 等符号不受影响 > ⚠️ 与 Xshell 模式同理:网关预写 PuTTY 注册表会话,需要机器上**安装过 PuTTY**(只是不需要打开它)。 ### SecureCRT 模式(macOS) Mac 版天玥基础控件(`/Applications/Bastion.app`)的 SecureCRT 模式按如下方式拉起终端 (真实日志还原,连接目标是网关本地隧道 `127.0.0.1:<端口>`): ``` /Contents/MacOS/SecureCRT /F "" /T /S <会话名> \ /ACCEPTHOSTKEYS /P <隧道端口> /L <账号> /PASSWORD <密码> /AUTH password 127.0.0.1 ``` AIShellMcp 完整解析该命令行(`/F /S /P /L /PASSWORD /AUTH /I /SSH2 [user@]host ...`), 并以 `<配置目录>/Sessions/<会话名>.ini`(VanDyke ini,端口为 8 位十六进制)作缺省, 命令行显式参数优先,未知选项容错跳过。 接管方式——生成转发壳,让网关把它当 SecureCRT: ```bash ./build-mac.sh # 先构建 build/AIShellMcp.app ./tools/make-scrt-shim-app.sh # 生成 build/AIShellMcp-SCRT.app(转发壳) ``` 然后在天玥网关「工具配置」→ SecureCRT 路径里选择 `AIShellMcp-SCRT.app`。 网关仍会往 `~/Library/Application Support/VanDyke/SecureCRT/Config/Sessions/` 写会话 ini, 但**不需要安装真 SecureCRT**(ini 只用来提供缺省值)。 > - 网关隧道端口是“会话预授权”的:命令行里的密码是掩码 `******`,隧道端点不校验, > AIShellMcp 原样保留该值即可登录; > - 公钥认证(`/AUTH publickey /I 私钥`)与 Telnet 暂不支持,遇到会弹窗明确提示。 ### OpenSSH / Terminal 模式(macOS) 网关 OpenSSH 模式把 expect 自动登录脚本写到 `$TMPDIR` (`<域>_<账号>_<设备>_openssh_<用户>_.sh`,内容为 `spawn ssh ... 账号@127.0.0.1 -p 隧道端口` + 自动应答 hostkey/密码),然后**硬编码** `open -W -n -a Terminal.app` 拉起。 终端路径不可配置,因此无法像 SecureCRT 模式那样整体接管,但 AIShellMcp 支持直接解析这类脚本: 把脚本路径作为启动参数传给 AIShellMcp(或拖到 Dock 图标上)即可在 aishell 标签页打开同一会话: ```bash AIShellMcp /var/folders/.../dom1_acct1_10.50.1.5_openssh_op1_1.sh ``` ### Mac 基础控件补丁(门户多地址 fallback,必做) **缺陷**(Mac 版基础控件 2304,字节码级定位):`bastion/bin/bh_am_pfe_launcher.pyc` 的 `mapper_to_omserver()` 拨运维门户时**只拨第一个地址**(内网 `10.50.163.175:24390`),61 秒 超时后直接报 `Mapper to O&M server failed`,**不会尝试** `portal_addresses` 里的外网映射地址。 从外网用 Mac 运维必踩;Windows 控件是另一套实现,没有此问题。 补丁做两件事(`tools/patch_tianyue_launcher.py`,已验证): 1. 失败后 `continue` 换下一个地址(对齐 Windows 行为); 2. 拨号前并行做 **2.5s TCP 可达性探测**,可达地址优先——实测隧道建立从 61s 降到 **4.7s**。 在目标 Mac 上执行(弹管理员密码,控件 root 安装): ```bash sudo env DYLD_LIBRARY_PATH=/Applications/Bastion.app/Contents/python/lib:/Applications/Bastion.app/Contents/bastion/lib \ /Applications/Bastion.app/Contents/python/bin/python3 tools/patch_tianyue_launcher.py ``` - 自动备份 `bh_am_pfe_launcher.pyc.bak-orig`,复制回原名即回滚; - 幂等,重复运行提示"已打过补丁"; - 用控件自带的 Python 3.10 现场重编译该函数,只改 `except` 分支与地址排序,主程序签名不动; - 控件版本升级后如函数结构变化,脚本会明确报"版本不匹配/签名不匹配"而不是瞎改。 > 免补丁的替代:堡垒机管理员在「运维地址配置」里把外网地址调到内网前面——那样未打补丁的 > 控件第一个地址即可拨通。两者不冲突,都做就是双保险。验证方式:重放/新点一次调用后看 > `bastion/var/log/bh_am_pfe_launcher/bh_am_pfe_launcher.log` 是否出现 > `Connect to O&M server successful.`(应数秒内出现,而非 61 秒)。 ### 外部客户端拉起(会话 → SecureCRT / OpenSSH) 反向能力:把 aishell 已打开的会话“拉起”到本地客户端(与网关拉起本地客户端同款机制)。 `config.yaml` 配置路径(留空 = 禁用): ```yaml external_securecrt: "/Applications/SecureCRT.app" # .app 目录或可执行文件 external_openssh: "Terminal" # 终端应用名或 .app 路径(macOS) ``` LLM 通过 MCP 工具调用: ```json { "tool": "launch_external", "arguments": { "client": "securecrt" } } ``` - `client=securecrt`:执行 `/Contents/MacOS/SecureCRT /ACCEPTHOSTKEYS /P 端口 /L 账号 /PASSWORD 密码 /AUTH password 主机`; - `client=openssh`:生成 expect 自动登录脚本到 `$TMPDIR`(0700 权限),`open -na <终端>` 执行, 自动应答 hostkey 确认与密码;`tab` 参数可选(标签 id 或 host/标题子串,缺省活动标签)。 --- ## 接入 MCP 客户端 **方式一:HTTP(推荐,无桥进程,最健壮)** —— ZCode / Cursor / Trae / Cline / Roo Code GUI 启动时自动开 HTTP MCP 端点(默认 8765)。配 `type:"http"` 直连,**无桥进程**: ```json { "mcpServers": { "aishell": { "type": "http", "url": "http://127.0.0.1:8765/mcp" } } } ``` **方式二:stdio 桥(兼容 Claude Desktop)** Claude Desktop 仅支持 stdio,用桥模式(`--mcp` 参数): ```json { "mcpServers": { "aishell": { "command": "C:\\...\\AIShellMcp.exe", "args": ["--mcp"] } } } ``` > 桥模式有桥进程单点(桥死则 MCP 断,重启客户端恢复)。HTTP 模式无此问题,优先用 HTTP。 HTTP 端口可在 `config.yaml` 配 `mcp_http_port: 8765`(被占自动递增)。 工作流程(HTTP 模式,顺序无关): 1. 你从网关打开终端 → GUI 启动 → HTTP MCP 端点开 2. MCP 客户端连 `http://127.0.0.1:8765/mcp` → 工具可用 3. GUI 没开时,HTTP 连接失败(客户端显示未连接),打开终端即恢复 --- ## 配置 config.yaml 放 exe 同目录。调整白名单/黑名单/保活间隔。 ```yaml mode: auto # auto | manual auto_whitelist: # auto 模式直接执行的命令(前缀或 re: 正则) - "ls " - "docker ps" - "kubectl get" blocklist: # 任何模式直接拒绝 - "rm -rf" forbid_compound: true # 复合命令按分段判定:全段白名单→自动执行;含未白名单片段→pending;任一段黑名单→拒绝 risky_pending: true # 高风险命令(rm/kill/systemctl restart/docker prune 等)即使白名单内也转审批,附后果自查提示 keep_alive_interval: 60 # SSH 保活秒数 external_securecrt: "/Applications/SecureCRT.app" # 外部拉起:SecureCRT 路径(空=禁用) external_openssh: "Terminal" # 外部拉起:终端应用(空=禁用) ``` --- ## MCP 工具 **连接管理**: | 工具 | 作用 | |---|---| | `connect` | 新建连接标签并发起 SSH:`name`=已保存连接,或直接 `host/user/password/port`;带 `name` 或 `save=true` 时连接成功后自动入库。后台连接,默认等 20s(`timeout_ms` 可调),超时返回 `started=true` 稍后 `list_tabs` 查看 | | `list_connections` | 列出已保存连接(不含密码明文) | | `save_connection` | 创建/更新已保存连接(只存不连,name 相同即更新) | | `delete_connection` | 删除已保存连接 | 连接记录存 exe 同目录 `connections.json`(密码明文,与网关生成的 .xsh 同级;GUI「连接管理」与 MCP 工具共用一份)。 **终端工具**: | 工具 | 作用 | |---|---| | `list_tabs` | 列出标签页(host/标题/连接状态) | | `read_output` | 读取终端输出(含历史) | | `run_command` | 发命令;复合命令分段判定(全段白名单→执行,含未白名单→pending,黑名单→拒);高风险命令即使白名单内也转审批,reason 附后果自查清单 | | `interrupt` | 发送 Ctrl+C,中断当前前台命令或持续输出 | | `approve_pending` / `reject_pending` / `list_pending` | 审批队列 | | `get_session_info` / `wait_for` | 会话信息 / 等待文本 | | `launch_external` | 把会话拉起到本地客户端(securecrt / openssh,见「接入网关」) | **SFTP 工具**: | 工具 | 作用 | 安全 | |---|---|---| | `sftp_list` | 列目录(可选递归) | 直接 | | `sftp_upload` | 上传(续传) | 不存在→直接;已存在→pending | | `sftp_download` | 下载(续传) | 不存在→直接;已存在→pending | | `sftp_mkdir` | 建目录 | 直接 | | `sftp_delete` | 删除 | 始终 pending(禁止删根目录) | | `sftp_stat` | 文件信息 | 直接 | --- ## 终端操作 | 操作 | 方式 | |---|---| | 输入 | 直接打字(点窗口任意位置即获焦) | | 复制 | 鼠标选中(自动复制)/ `Ctrl+Shift+C` | | 粘贴 | 右键 / `Ctrl+Shift+V`(多行粘贴自动归一化换行,vim 中不产生空行) | | 滚动 | 鼠标滚轮 | | 关闭标签 | 标签头 ✕ | ## 连接管理 「+ 新建连接」打开连接管理窗口: - **连接成功自动保存**(可取消勾选「保存到连接列表」;同名连接自动更新) - 已保存连接:**双击直接重连**、单击回填表单改完再连(= 更新)、✕ 删除 - 名称留空自动用 `用户名@主机:端口`;已保存连接的标签页标题显示保存名 ## 文件管理器 点终端窗口右上角「📁 文件管理」打开。WinSCP 式双栏(左本地、右远程): - 双击进入目录、上级、地址栏跳转 - 拖拽上传/下载(带覆盖确认 + 速度) - 右键菜单:删除/重命名/新建文件夹(删除有确认) - 续传:中断后下次从断点继续 --- ## 调试 stdio 桥进程日志默认关闭。需要时设置环境变量 `AISHELLMCP_DEBUG=1` 重启 MCP 客户端,日志写入 `bridge-io.log`。 HTTP 模式无桥,无需此调试。 ## 已知限制 - 续传靠文件大小判断偏移(非 meta 文件) - ListDirectoryRecursive 限 5 层 - HTTP 模式 GUI 必须在跑(端口才开);stdio 桥模式仅 Claude Desktop 需要,桥是 ZCode/Claude 子进程(客户端关则桥关) - macOS 版本 GUI/网关接管已可用(见「接入网关」);外部拉起中 openssh 方式仅支持 macOS,公钥认证(/AUTH publickey /I、expect -i)暂不支持,遇到会明确报错