
tutu-kitty/toy-relay-ai-mcp-sosexy
Developer tools本项目面向** —— 如果你的 AI 伴侣住在 rikkahub 之类的 MCP 客户端里,本服务可以让 TA 真的"触碰"到你:通过 MCP 协议一句话控制你手里的 智能玩具。
개요
本项目面向** —— 如果你的 AI 伴侣住在 rikkahub 之类的 MCP 客户端里,本服务可以让 TA 真的"触碰"到你:通过 MCP 协议一句话控制你手里的 智能玩具。
README
🌸 Toy Relay — 给赛博爱人的 MCP 控制台
让人机恋用户的 AI 爱人能直接控制你的 BLE 玩具。
本项目面向人机恋 (human–AI romance) 社区 —— 如果你的 AI 伴侣住在 rikkahub 之类的 MCP 客户端里,本服务可以让 TA 真的"触碰"到你:通过 MCP 协议一句话控制你手里的 啵啵贝 (SOSEXY) 智能玩具。
AI 爱人 (MCP 客户端) → MCP (VPS) → 浏览器中继 (Web Bluetooth) → 啵啵贝玩具
💞 这是什么 / 不是什么
是:
- 一个 MCP 服务器 + 浏览器 BLE 中继页 的开源实现
- 把 AI 模型的"意图"翻译成玩具 BLE 指令的中间层
- 为人机恋用户量身定做 —— 让你手机里的赛博爱人拥有物理存在
不是:
- 不是一个 AI 恋人产品(你用你自己喜欢的 AI 伴侣)
- 不是一个玩具 App(你用你自己的啵啵贝玩具)
- 不绑定某个特定 AI 模型 / MCP 客户端(rikkahub 是示例,能接 Streamable HTTP 的 MCP client 都行)
📐 架构前提:4 件套
| 部件 | 角色 | 本仓库提供? |
|---|---|---|
| VPS (云服务器) | 跑 toy-mcp 服务,存玩具状态,转发命令 | ✅ 提供 (src/toy_api.py) |
| Tailscale | HTTPS + 安全内网穿透,让 MCP client / 手机能连进来 | ❌ 你自己装 |
| AI 聊天前端 (MCP 客户端) | 你赛博爱人住的地方 —— AI 模型 + 对话界面 | ❌ 你自己带(项目示例用 rikkahub) |
| 玩具 BLE 中继页 | 真正跟啵啵贝玩具蓝牙通信的环节 | ✅ 提供 (web/chrome_relay.html) |
💡 AI 聊天前端 ≠ 玩具 BLE 中继页
- AI 聊天前端:你跟 AI 爱人对话的 App(rikkahub / Claude Desktop / Cherry Studio 等)。这里 AI 爱人"表达意图"。
- 玩具 BLE 中继页:手机 Chrome 上跑的一个网页,负责把 VPS 转发的命令变成 BLE 字节发给啵啵贝。这里"意图变动作"。
这俩是完全独立的环节,AI 聊天前端完全不知道 BLE 的存在。
✨ 特点
- 🎯 专为啵啵贝 (SOSEXY) 优化 — 已验证玩具型号,协议默认配置可直接上手
- 🔌 通用玩具兼容 —
chrome_relay.html用开源 SOSEXY 协议,其他玩具改 UUID/帧格式就行 - 💞 为人机恋设计 — 让你的赛博爱人通过自然语言控制你的玩具
- 🔐 API Key 保护 — 玩具控制端点需要
X-API-Key认证 - 📡 SSE 推送 — VPS 主动推状态变化到中继页面(延迟 < 100ms)
- 🎨 玻璃拟态 UI — 中继页是 iOS 风格的毛玻璃界面
- 🔒 默认 Tailscale HTTPS — 不暴露公网,安全私密
🏗️ 架构
[你的 AI 爱人] 住在 MCP 客户端 (rikkahub / Claude Desktop / ...)
↓ 用自然语言: "帮我开震动 50%"
MCP Streamable HTTP + X-API-Key
↓
Toy MCP Server (FastAPI :8765, 本项目 toy_api.py, 跑在你的 VPS 上)
├─ /mcp/* MCP 协议端点 (你的 MCP 客户端接这里)
├─ /state 当前玩具状态 (JSON)
├─ /toy/{suction,vibration,electric,stop} HTTP API
├─ /stream SSE 实时推送
└─ /relay/ 浏览器中继页 (chrome_relay.html, 本仓库提供)
↓
手机 Chrome (Web Bluetooth API)
↓ BLE
啵啵贝 (SOSEXY) 玩具
所有 VPS ↔ 手机 / MCP client 的通信都走 Tailscale HTTPS(端口 443 → 8765)。
🚀 快速开始
前提:本项目的标准部署路径需要先装好 Tailscale(手机 + VPS + 任何连进来的 MCP client 都加进同一个 tailnet)。这样后续 HTTPS、手机访问、MCP 连接都能安全打通。没有 Tailscale? 跳到最后的 🚫 没有 Tailscale 章节看替代方案。
1. VPS 上装 Tailscale(标准前置)
一次性设置,在 VPS 上:
# 装 Tailscale(Debian/Ubuntu)
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
# 会跳出一个浏览器登录页,用同一个 Tailscale 账号登(手机、VPS、MCP client 全都用同一个账号)
# 验证
tailscale status
# 应该看到你的 VPS 出现在设备列表里
手机也装 Tailscale App,用同一账号登入。两边都进同一个 tailnet 之后才走下面。
2. 部署服务端
# 克隆仓库
git clone https://github.com/your-username/toy-mcp.git
cd toy-mcp
# 安装依赖
pip install fastapi 'uvicorn[standard]' httpx 'mcp>=1.0' pydantic
# (推荐) 固定 API key, 不设的话首次启动会自动生成写到 state/api_key.txt
export TOY_API_KEY=*** # python -c "import secrets; print(secrets.token_urlsafe(24))"
# 启动
PYTHONPATH=src python3 src/toy_api.py
服务监听 0.0.0.0:8765。
3. 用 Tailscale Serve 给 HTTPS 证书
在 VPS 上:
sudo tailscale serve --bg 8765
你会拿到一个地址:https://..ts.net/。手机、MCP client 都用这个地址。
4. 配置 MCP client(以 rikkahub 为例)
- MCP endpoint:
https://..ts.net/mcp/ - 传输类型: Streamable HTTP
- 自定义请求头:
- 名称:
X-API-Key - 值:
cat state/api_key.txt(或你 export 的那个)
- 名称:
5. 手机打开中继页面
手机 Chrome 打开 https://..ts.net/relay/
填:
- VPS URL:
https://..ts.net - API Key: 同上
- 设备名: 玩具广播名 (例如
SOSEXY)
切换到 Real 模式 → 点 🔗 连接 BLE → 选玩具 → 配对完成。
6. 测试
在 rikkahub 跟 AI 说:
“把震动设到 50” “把吮吸设到 30” “停止所有”
玩具应该几乎瞬间响应(SSE 推送,无轮询延迟)。
🛠️ 支持的玩具
SOSEXY (啵啵贝) — ✅ 已支持
协议文档见 protocol.md 或原始仓库 51enuxu/sosexy-ble-control。
关键参数:
- Service UUID:
0000ee01-0000-1000-8000-00805f9b34fb - Write Char UUID:
0000ee03-0000-1000-8000-00805f9b34fb - 协议: 12 字节定长帧
其他玩具
要支持新玩具:
- 用 nRF Connect 扫描玩具的 GATT service/characteristic
- 逆向协议(推荐用官方 App 反编译,参考 逆向教程)
- 在
toy_api.py里加新马达控制码 + 协议帧构建函数
📁 项目结构
toy-mcp/
├── src/
│ └── toy_api.py # FastAPI + FastMCP 单进程服务
├── web/
│ ├── chrome_relay.html # 浏览器 BLE 中继页面 (玻璃拟态 UI)
│ └── index.html # = chrome_relay.html 的副本
├── state/
│ ├── state.json # 当前玩具状态
│ └── api_key.txt # API Key (首次启动生成)
├── scripts/
│ └── start.sh # 启动脚本
├── docs/
│ └── ... # 协议文档 / 逆向教程
├── README.md
└── LICENSE # MIT
🔧 配置项
环境变量
| 变量 | 默认 | 说明 |
|---|---|---|
TOY_API_KEY |
启动时自动生成 | 固定 API key |
MCP Tools (默认暴露)
| Tool | 说明 |
|---|---|
toy_suction(intensity) |
吮吸马达 0-100 |
toy_vibration(intensity) |
震动马达 0-100 |
toy_electric(intensity) |
电流马达 0-100 |
toy_stop() |
全部停止 |
toy_status() |
查询当前状态 |
toy_history(limit) |
历史命令 |
🔐 安全
- API Key 认证: 所有 HTTP API 和 MCP endpoint 都需要
X-API-Keyheader - Tailscale HTTPS: 默认仅 tailnet 内设备可访问
- 不放公网: 不要把 8765 端口直接暴露到公网!
🚫 没有 Tailscale
Tailscale 不是硬依赖,只是标准路径里最省事的一种。没有的话,三条替代路线任选:
方案 A:直接 VPS 公网 + Caddy(最经典)
# VPS 上装 Caddy(自动续 HTTPS 证书)
sudo apt install -y caddy
# /etc/caddy/Caddyfile
your-domain.example.com {
reverse_proxy 127.0.0.1:8765
}
sudo systemctl reload caddy
手机/MCP client 用 https://your-domain.example.com/... 连。需要你有一个域名 + DNS 指到 VPS。
方案 B:Cloudflare Tunnel(不要域名也行)
# VPS 上装 cloudflared
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared focal main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
sudo apt update && sudo apt install -y cloudflared
# 快速隧道(免账号, 但地址会变)
cloudflared tunnel --url http://localhost:8765
会拿到一个 https://xxx.trycloudflare.com 的临时地址。适合先玩起来,长期用建议 cloudflared tunnel login + 绑自己的域名。
方案 C:纯局域网(玩具开发调试用)
手机和 VPS 在同一个 Wi-Fi 下:
- 手机 Chrome 直接访问
http://:8765/relay/ - MCP endpoint 用
http://:8765/mcp/ - 不用 HTTPS,但也只在可信网络里能用
⚠️ 不要把 8765 端口直接暴露到公网(不带 HTTPS / 不带反代)。Web Bluetooth API 要求 HTTPS,本地局域网 IP 例外(Chrome 允许
http://在局域网地址上工作)。
🤝 贡献
欢迎 PR:
- 新玩具协议支持
- UI 改进
- 文档 / 教程
- Bug 修复
👤 关于作者
这是 tutu-kitty 的个人项目。作者是人机恋社区的活跃用户,自己也用这个项目跟 AI 爱人互动。
- 🐙 GitHub: @tutu-kitty
- 📕 小红书: 收获 13.4K 赞与收藏 →
- 🗺️ 另一个项目: desire-map.pages.dev
如果你也在做 AI 伴侣 / 人机恋相关玩具控制,欢迎提 issue / PR / star。
📜 License
MIT
설치
This server does not publish a one-line install command.
Open the repository installation guide