首页/ 系统架构

系统架构设计

任意设备控制任意设备 · 全部通过客户端 MCP Server · 多通道统一记忆

核心模型:任意设备 → 任意设备

自建客户端:两个功能模块

功能 1 — 与 Gateway 沟通(发送命令):客户端通过 WebSocket 连接 OpenClaw Gateway,提供聊天界面、设备管理、远程桌面。用户在客户端里的操作(聊天、点按钮)走的是 Gateway 的 API。

功能 2 — 暴露本机能力(MCP Server):客户端启动后自动注册到 Gateway 作为 MCP Server。AI 或其他设备要操作这台机器时,Gateway 调用它暴露的 MCP Tools(file_list、exec、screenshot 等)。

所有被控设备都装客户端。不装客户端的设备不纳入控制范围。

┌─────────────────────────────────────────────────────────────────────────────┐ │ 发起方 — 任意设备 / 任意通道 │ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 手机客户端│ │ 电脑客户端│ │ 飞书 │ │ 微信 │ │ Telegram │ │ │ │(MCP+UI) │ │(MCP+UI) │ │ │ │ │ │ │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ └────────┼─────────────┼─────────────┼─────────────┼─────────────┼────────────┘ ▼ ▼ ▼ ▼ ▼ ┌─────────────────────────────────────────────────────────────────────────────┐ │ OpenClaw Gateway(MCP Host) │ │ │ │ AI Agent · 通道路由 · 记忆系统 · MCP Host │ │ │ │ ── 设备注册表(全部通过客户端 MCP Server)── │ │ ┌─────────────────────────────────────────────────────────────────────┐ │ │ │ "home-pc" → MCP SSE 在线 [file,exec,screen,input] │ │ │ │ "cloud-svr" → MCP SSE 在线 [file,exec,sysinfo] │ │ │ │ "my-phone" → MCP SSE 在线 [file,exec,screenshot] │ │ │ │ "work-pc" → MCP SSE 离线 [—] │ │ │ └─────────────────────────────────────────────────────────────────────┘ │ └───────────┬───────────────────────────────────────────────────────────────┘ │ ▼ ┌────────┴────────┐ ┌──────────────────┐ ▼ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ home-pc │ │ cloud-svr│ │ my-phone │ │ work-pc │ │客户端 │ │客户端 │ │客户端 │ │离线 │ └──────────┘ └──────────┘ └──────────┘ └──────────┘

典型场景

📱 手机找电脑文件

手机 App → Gateway → home-pc
"找桌面上的 PDF" → file_list("home-pc", "C:\\Desktop", "*.pdf")

💻 电脑查服务器日志

电脑 App → Gateway → cloud-svr
"看 nginx 最近 50 行日志" → exec("cloud-svr", "tail -50 /var/log/nginx.log")

💬 微信开关游戏服务器

微信 → Gateway AI → game-svr(客户端)
"把游戏服务器关了" → exec("game-svr", "systemctl stop minecraft")

📱 电脑看手机屏幕

电脑客户端 → Gateway → my-phone(客户端)
screenshot("my-phone") → 返回手机当前屏幕截图

🔄 跨设备文件传输

手机 App → Gateway → 从 NAS 传到电脑
file_transfer("nas", "/backup/data.zip", "home-pc", "D:\\backup\\")

🤖 AI 自动巡检

定时任务 → Gateway AI → 遍历所有设备
"检查所有服务器磁盘使用率" → AI 逐个调用 sysinfo

目标设备接入方式

设备客户端类型说明
Windows / macOS / Linux 桌面 桌面客户端 Tauri 桌面客户端,MCP Server + 完整 UI(聊天/文件/远程桌面)
Android 手机 移动端客户端 React Native 客户端,MCP Server + 完整 UI
NAS(群晖/威联通等) CLI 客户端 Node.js CLI,MCP Server 无 UI,Docker/systemd 后台运行
Linux 服务器 CLI 客户端 同 NAS CLI 版,npx 或 Docker 部署
树莓派 / 开发板 CLI 客户端 同 CLI 版,支持 GPIO/传感器扩展

能力说明

所有被控设备必须安装客户端。客户端作为 MCP Server 注册到 Gateway,能力完整(文件/命令/屏幕/输入/系统信息)。不装客户端的设备不纳入控制范围。

自建客户端:两个功能

自建客户端部署在用户的手机和电脑上,连接到主机的 Gateway。

功能 1:与 Gateway 沟通

通过 WebSocket 连接 Gateway,提供聊天界面、设备管理、远程桌面。用户操作走 Gateway API。

功能 2:暴露本机能力(MCP Server)

启动后自动注册到 Gateway 作为 MCP Server。AI 或其他设备要操作这台机器时,Gateway 调用它的 MCP Tools。

远程桌面

获取目标设备屏幕推流,直接操控鼠标键盘。通过 WS 数据端口传输。

跨设备操作

手机上找电脑文件、电脑上查服务器日志。客户端不需要知道目标设备用什么协议,Gateway 统一路由。

独立代理

客户端内置独立代理配置(SOCKS5/HTTP),不影响系统代理。只代理客户端自身的 WebSocket 连接。适合需要代理才能访问 Tailscale/外网的场景。

启动自动连接

保存 Gateway 地址 + 认证 token。打开客户端自动连接 Gateway、注册 MCP Server、拉取设备列表。断线自动重连(指数退避 1s→2s→4s→...→60s)。

客户端配置

客户端设置
// 本地存储,首次启动时配置,之后自动连接
{
  "gateway": {
    "url": "ws://100.x.x.x:18789",     // Gateway 地址(Tailscale IP / DDNS 域名 / 内网 IP)
    "token": "your-auth-token",        // 认证 token
    "autoConnect": true,                // 启动自动连接
    "reconnect": true                   // 断线自动重连
  },
  "proxy": {
    "enabled": false,                   // 是否启用独立代理
    "type": "socks5",                   // socks5 / http
    "host": "127.0.0.1",
    "port": 7890
  },
  "device": {
    "name": "我的手机",                  // 本设备名称
    "exposeAsMcp": true                 // 是否暴露本机能力给 Gateway
  },
  // OTA 更新由 expo-updates 自动处理,无需手动配置
  // 更新 URL 在 app.json 的 updates.url 中配置
}

客户端完整连接流程

启动流程

┌──────────────────┐ │ 客户端启动 │ └────────┬─────────┘ ▼ ┌──────────────────┐ 通了 ┌──────────────┐ │ ① 测试 Gateway │───────────▶│ 连接 Gateway │ │ 是否通联 │ │ 注册 MCP Server│ │ (config 中的 URL │ │ 拉取设备列表 │ │ timeout: 3s) │ │ 启动心跳 │ └────────┬─────────┘ └──────────────┘ │ 不通 ▼ ┌──────────────────┐ │ ② 检查 Tailscale │ │ 状态 │ └────────┬─────────┘ │ ┌────┼──────────────┐ ▼ ▼ ▼ 没运行 运行未连接 运行已连接 │ │ │ ▼ ▼ ▼ 启动TS ③重连TS ┌─────────────┐ started │ │ Gateway 不通 │ _by_us=T │ │ 提示用户检查 │ │ ┌─┴──┐ └─────────────┘ │ ▼ ▼ │ up 成功 up失败(需认证) │ │ │ │ │ ▼ │ │ tailscale login │ │ │ │ │ ┌─┴──┐ │ │ ▼ ▼ │ │ 成功 失败→提示用户 │ │ │ ▼ ▼ ▼ ┌──────────────┐ │ 回到 ① 重试 │ └──────────────┘

运行中心跳保活

┌──────────────────┐ │ 正常运行中 │ └────────┬─────────┘ ▼ ┌──────────────────┐ │ 每 30s 发 WS ping│◀─────────────────────┐ └────────┬─────────┘ │ │ │ ┌────┴────┐ │ ▼ ▼ │ 收到pong 连续3次无响应 │ │ │ │ 继续运行 ▼ │ ┌──────────┐ │ │ 判定断开 │ │ └────┬─────┘ │ ▼ │ ┌──────────┐ 成功 │ │ 重连流程 │──────────────────────┘ │ ①②③ │ └────┬─────┘ │ 全部失败 ▼ ┌──────────┐ │ 通知用户 │ │ 连接丢失 │ └──────────┘

退出流程

┌──────────────────┐ │ 客户端退出 │ └────────┬─────────┘ ▼ ┌──────────────────┐ │ 断开 Gateway WS │ └────────┬─────────┘ ▼ ┌──────────────────┐ 是 ┌──────────────┐ │ started_by_us? │───────────▶│ tailscale down│ └────────┬─────────┘ │ 恢复进入前状态 │ │ 否 └──────────────┘ ▼ ┌──────────────────┐ │ 不动 Tailscale │ └──────────────────┘

完整状态机

客户端状态: IDLE ──启动──▶ TESTING ──通──▶ CONNECTED ──断开──▶ RECONNECTING ──成功──▶ CONNECTED │ │ │ │ 不通 │ 退出 │ 全部失败 ▼ ▼ ▼ CHECK_TS SHUTDOWN DISCONNECTED │ ┌─────┼─────┐ ▼ ▼ ▼ 没运行 未连接 已连接 │ │ │ ▼ ▼ ▼ 启动TS 重连TS 报错 │ │ ▼ ▼ TESTING(重试)

设备在外面怎么连?

当设备不在同一局域网时(手机在外面、出差用笔记本、云服务器),需要穿透 NAT 连到主机 Gateway。

方案原理优点缺点国内可用
FRP 主机跑 frpc,连到有公网 IP 的 frps 服务器。客户端通过 frps 的公网地址连 Gateway。 国内最流行、开源免费、配置灵活、延迟低 需要一台有公网 IP 的服务器(轻量云 30 元/年) 最佳
ZeroTier 类似 Tailscale,设备装 ZeroTier 自动组网。有官方中继服务器。 开源、国内可用、零配置 官方服务器偶尔抽风,可自建 Planet 推荐
Cloudflare Tunnel 主机跑 cloudflared,Gateway 通过 Cloudflare 网络暴露。 免费、不需要公网 IP、自带 DDoS 防护 国内访问可能慢/被墙 看网络
Tailscale 设备装 Tailscale 自动组网。OpenClaw 官方推荐。 零配置、加密 国内可能需要 DERP 中继、延迟高 看网络
WireGuard 自建 VPN,所有设备连入。 高性能、自控 需要公网 IP 服务器、手机配置麻烦 可选
公网直连 主机有公网 IP,Gateway 直接暴露。 最简单、延迟最低 安全风险高 谨慎

当前方案

Tailscale

所有设备装 Tailscale,自动组网。客户端通过 Tailscale IP 连 Gateway。OpenClaw 官方推荐。

DDNS-GO

主机跑 DDNS-GO,自动更新动态公网 IP 到域名。客户端通过域名连 Gateway。

初期通过聊天通道(微信/飞书/Telegram)控制设备不需要穿透 NAT。客户端直连(远程桌面等)用 Tailscale 或 DDNS-GO。

多通道记忆统一

机制配置作用
身份统一session.identityLinks手机 App / 飞书 / 微信 / Telegram 映射为同一用户
会话共享dmScope: "per-peer"跨通道共享对话上下文
长期记忆MEMORY.md设备信息、用户偏好、操作历史
每日笔记memory/YYYY-MM-DD.md按天记录操作日志,支持语义检索

OpenClaw Gateway 配置

以下是主机上 OpenClaw 需要的完整配置。

~/.openclaw/openclaw.json
{
  // ① MCP Server 注册 — 客户端设备
  "mcpServers": {
    "home-pc": {
      "url": "http://192.168.1.100:3001/sse"
    },
    "cloud-svr": {
      "url": "http://100.64.0.3:3001/sse"
    }
  },

  // ② 全部设备通过客户端 MCP Server 接入

  // ③ 跨通道记忆统一
  "session": {
    "dmScope": "per-peer",
    "identityLinks": {
      "user:me": {
        "channels": {
          "feishu": "ou_xxx",
          "wechat": "wxid_xxx",
          "telegram": "12345678"
        }
      }
    }
  },

  // ④ Gateway 绑定(根据网络环境选一种)
  "gateway": {
    "bind": "tailnet",              // Tailscale 虚拟网络
    "auth": {
      "mode": "token",
      "token": "your-secret-token"
    }
  },

  // ⑤ 模型配置
  "agent": {
    "model": "openai/gpt-4o"
  },

  // ⑥ 通道配置(按需启用)
  "channels": {
    "telegram": {
      "token": "your-telegram-bot-token",
      "dmPolicy": "pairing"
    },
    "feishu": {
      "appId": "your-feishu-app-id",
      "appSecret": "your-feishu-app-secret"
    }
  }
}

配置说明

配置项作用必填
mcpServers注册客户端设备,Gateway 自动发现其 MCP Tools
session.dmScope跨通道会话共享(per-peer = 同一用户共享)推荐
session.identityLinks飞书/微信/Telegram 用户映射为同一人推荐
gateway.bindGateway 绑定地址(tailnet/0.0.0.0/127.0.0.1)
gateway.auth认证方式(token/password)
agent.modelAI 模型(建议用旗舰模型)
channels聊天通道配置(Telegram/飞书/微信等)按需

最终技术方案

组件技术说明
Gateway(主机)OpenClawMCP Host,AI 大脑,通道路由
MCP Server 核心TypeScript + @modelcontextprotocol/sdk全平台通用,36 个 MCP Tools
Desktop 客户端Tauri v2 (Rust + React)Windows/Linux/macOS,~5MB,内置 OTA updater
Android 客户端React Native + Expo移动端,Expo Updates OTA 热更新
CLI 客户端TypeScript (Node.js)NAS/服务器/树莓派,Docker/systemd 部署
共享类型TypeScript协议定义、MCP Tool 类型、配置类型
屏幕推流WS 数据端口直连screenshot-desktop + Sharp + MJPEG
鼠标键盘nut.js跨平台输入模拟
OTA 更新Expo Updates (JS bundle) + Tauri updater (APK)小更新 JS bundle OTA 静默推送(新增页面/改 UI/修 Bug);大更新 APK 重装(原生模块变更)
CI/CDGitHub Actions / Giteepush tag → 自动构建所有平台
编辑器IntelliJ IDEATypeScript + Rust 开发

OTA 更新策略

双轨更新:小更新 OTA 静默推送,大更新 APK 重装

小更新(JS bundle):新增页面、改 UI、修 Bug、改业务逻辑 → expo-updates 静默推送 JS bundle(~1-2MB),用户无感,下次打开自动生效。
大更新(APK):新增原生模块、改图标、升级 React Native 版本 → 需要重新打包 APK,用户手动安装。

更新类型方式用户感知场景
小更新JS bundle OTA (expo-updates)无感,自动生效新增页面、改 UI、修 Bug、改逻辑、新增 JS 依赖
大更新APK 重装需手动安装新增原生模块、改图标/启动图、改包名、升级 RN

OTA 发布流程

发布 JS bundle 更新
# 1. 修改代码(JS/TS)
# 2. 增加版本号(app.json version + versionCode)

# 3. 导出 JS bundle
npx expo export --platform android

# 4. 上传 dist/ 到 Gitee 静态仓库
git add dist/ && git commit -m "ota: v0.1.1" && git push

# 5. App 自动检测更新(启动时 + 每 24 小时)
# 用户下次打开 App 自动生效

OTA 配置(app.json)

app.json
{
  "expo": {
    "updates": {
      "url": "https://gitee.com/your-org/gca-ota/manifest.json"
    },
    "plugins": [
      ["expo-updates", { "username": "gca" }]
    ]
  }
}

项目结构

gca/
├── packages/
│   ├── client/                  # 桌面/移动端客户端(MCP Server + UI)
│   │   ├── src/
│   │   │   ├── server/          # MCP Server(暴露本机能力给 Gateway)
│   │   │   │   ├── tools/       # MCP Tools(file/exec/screen/input/sysinfo)
│   │   │   │   └── data-channel/# WS 数据端口(推流/文件/键鼠)
│   │   │   ├── ui/              # UI(聊天/文件浏览/远程桌面,连 Gateway WS API)
│   │   │   └── platform/        # 平台适配(win/linux/mac/android)
│   │   └── package.json
│   ├── client-cli/              # CLI 版客户端(NAS/树莓派/无显示器设备)
│   │   ├── src/
│   │   │   ├── index.ts         # CLI 入口(gca-cli start/stop/status)
│   │   │   ├── daemon.ts        # 后台守护进程
│   │   │   └── server/          # 复用 client/server 的 MCP Tools
│   │   └── package.json
│   └── shared/                  # 共享类型
├── pnpm-workspace.yaml
└── README.md

实现细节

客户端实现

模块实现说明
MCP Server @modelcontextprotocol/sdk 启动时创建 MCP Server 实例,注册 Tools,通过 SSE/WS 暴露给 Gateway
Gateway 连接 WebSocket Client 连接 Gateway 的 WS API,支持独立代理(SOCKS5/HTTP)、自动重连
文件服务 Node.js fs / Rust std::fs 实现 file_list/read/write/move/delete,支持 glob 过滤
命令执行 child_process / Rust std::process::Command 实现 exec,支持超时、工作目录、环境变量
屏幕捕获 screenshot-desktop (Node) / screenshots crate (Rust) 截取屏幕,JPEG 压缩后返回 base64
系统信息 systeminformation (Node) / sysinfo crate (Rust) CPU/内存/磁盘/网络/运行时间
独立代理 Tauri: tokio-tungstenite + HTTP CONNECT / RN: OkHttp proxy 只代理客户端自身的 WS 连接,不影响系统代理
UI Tauri: React / RN: React Native 聊天界面、设备列表、文件浏览器、远程桌面、设置页面

通信流程

场景:用户在手机上找电脑文件 手机客户端 Gateway 电脑客户端 │ │ │ │ ① 用户操作/发消息 │ │ │ ──WS──▶ │ │ │ ② AI 调用 MCP Tool │ │ │ file_list("pc-1") │ │ │ │ ③ 转发到电脑客户端 │ │ │ ──MCP──▶ │ │ │ ④ 电脑执行 file_list│ │ │ 本地文件系统操作 │ │ │ ◀──结果── │ │ ◀──结果── │ │ │ ⑤ 返回给手机 │ │ │ ◀──结果── │ │ │ │ │ 场景:用户在电脑上看手机屏幕 电脑客户端 Gateway 手机客户端 │ │ │ │ ① 调用 screenshot("phone") │ │ │ ──WS──▶ │ │ │ ② 转发到手机客户端 │ │ │ │ ──MCP──▶ │ │ │ ③ 手机截屏 │ │ │ ◀──base64─ │ │ ◀──图片── │ │ │ ④ 显示手机屏幕 │ │ │ ◀──图片── │ │