洛文塞mcp
MCP服务器,用于通过Lovense Cloud API控制Lovense玩具。在家庭服务器上运行,在任何地方工作,让你选择的人工智能进行创造性控制。
使用TypeScript、Bun、Hono和MCP SDK构建。
______________________________________________________________________
运作原理
You (outside, Claude Desktop or any MCP client)
↕ HTTP/SSE — MCP transport
Your home server (NAS, VPS…)
↕ HTTPS — Lovense Server API
Lovense Cloud
↕ Push
Lovense Remote App (your phone, also outside)
↕ Bluetooth
Your toys为什么是云而不是局域网? Lovense Remote应用程序位于您的手机上,在家庭网络之外,与您的服务器不在同一局域网上。因此,Lovense服务器API(云中继)是强制性的。建筑有趣,生活复杂。
为什么是HTTP/SSE而不是stdio? stdio要求MCP服务器和AI客户端在同一台机器上运行。这里的服务器是远程的,因此是HTTP/SSE传输。
______________________________________________________________________
先决条件
- 包子 安装在您的服务器上,您可以使用 我也是。
- A. Lovense开发者账号 带有开发人员令牌
- 您手机上的Lovense Remote应用程序已登录
- 至少一个Lovense玩具 _(这个在你身上)_
- 您的服务器必须可公开访问(端口转发、反向代理等),以便Lovense Cloud可以向其发送回调
______________________________________________________________________
设置
1.Lovense开发者门户
跟随 Lovense官方指南 致:
- 注册应用程序
- 获取您的开发者令牌
- 设置回调URL 到
https://your-server.example.com/callback
回调URL是每个人都会忘记的部分。没有它,您的服务器将永远不会收到Lovense的消息,也无法正常工作。不要跳过这个。
2.安装
git clone https://github.com/Gradleless/lovense-mcp
cd lovense-mcp
bun install3.配置
cp env.example .env看 配置 下面是所有变量。
4.跑步
# Development (watch mode, pretty logs)
bun run dev
# Production
bun run start服务器在启动时记录安装URL:
Setup page: http://localhost:3000/setup?token=your_token5.把玩具配对
在浏览器中打开设置URL,用Lovense Remote应用程序扫描二维码。应用程序将呼叫您的 /callback 端点并注册您的玩具。从这一点开始,服务器会定期接收心跳(大约每10秒一次)来跟踪连接的内容。
二维码将在4小时后过期。访问 /setup 再次得到一个新的。6.连接您的MCP客户端
将任何兼容MCP的客户端(Claude Desktop、Cursor、Zed等)指向 https://your-server/mcp.
注: MCP OAuth身份验证尚未实现。改为在反向代理级别处理身份验证(IP分配列表、VPN等)。
______________________________________________________________________
MCP工具
| 工具 | 说明 |
|---|---|
get_qr | 显示Lovense配对二维码 |
get_toys | 列出连接的玩具和连接状态 |
play_action | 单动:振动、旋转、推力等。 |
stroke_action | stroker玩具(Solace等)的冲程+推力 |
play_preset | 内置Lovense图案(脉冲、波浪、烟花、地震) |
play_pattern | 带有自定义航路点的循环强度循环 |
play_sequence | 多相定时序列(A然后B然后C,非循环) |
stop | 紧急停止——立即停止一切 |
你的AI应该总是打电话 get_toys 首先检查连接性,看看每个玩具实际支持哪些操作。你通常不需要指定它。 向只振动的玩具发送旋转命令会让所有人失望。
______________________________________________________________________
get_qr
生成并显示Lovense配对二维码。在以下情况下使用此功能 get_toys 不归还玩具或 lastSeenAt 为null--应用程序尚未连接。
用户使用手机上的Lovense Remote应用程序扫描二维码以建立连接。扫描后,服务器开始接收心跳,玩具可用。
没有参数。将二维码作为图像返回,如果图像无法显示,则返回回退URL。
二维码将在4小时后过期。呼叫 get_qr 再次换一个新的。______________________________________________________________________
get_toys
返回上次心跳的缓存玩具列表。没有对Lovense的API调用,只有服务器的内存状态。
Output: { toys: [...], lastSeenAt: "ISO date or null" }每个玩具包括一个 features 列出其支持的操作的数组。
如果 lastSeenAt 如果为null或超过30秒,则应用程序被视为离线,任何命令都会失败,并显示明确的错误消息,而不是默默地什么都不做。
______________________________________________________________________
play_action
给定持续时间内的单一操作。
| 参数 | 类型 | 说明 |
|---|---|---|
type | string | 动作类型(见下表) |
strength | integer | 强度(范围取决于动作) |
duration | number | 秒。 0 =不确定,否则≥1 |
toyId | 弦? | 瞄准特定的玩具。为所有人省略。 |
动作类型和范围:
| 动作 | 范围 | 注释 |
|---|---|---|
| 振动 | 0-20 | |
| 旋转 | 0–20 | |
| 推力 | 0-20 | |
| 手指 | 0-20 | |
| 吸力 | 0-20 | |
| 振荡 | 0-20 | |
| 全部 | 0–20 | 同时适用于所有功能 |
| 泵 | 0–3 | 3级 |
| 深度 | 0–3 | 3级 |
______________________________________________________________________
stroke_action
用于支持中风动作的中风玩具(Solace等)。仅在以下情况下使用 get_toys 显示 "Stroke" 在玩具的功能中——否则你只是希望。
| 参数 | 类型 | 说明 |
|---|---|---|
strokeMin | integer | 起始位置(0–100,0=完全缩回) |
strokeMax | integer | 结束位置(0–100,必须≥strokeMin+20) |
thrustingStrength | 整数 | 速度0-20 |
duration | number | 秒。 0 =不确定,否则≥1 |
toyId | 弦? | 瞄准特定的玩具。为所有人省略。 |
振幅引导:非常轻=0-20,轻=0-30,中等=0-50,相当强=0-65,强=0-80,最大=0-100。
对于随时间变化的强度抚摸模式,请使用 play_pattern 相反。
______________________________________________________________________
play_preset
播放内置的Lovense模式。当你不想想想得太多时,快速简单。
| 参数 | 类型 | 说明 |
|---|---|---|
name | 字符串 | pulse / wave / fireworks / earthquake |
duration | number | 秒。 0 =不确定,否则≥1 |
toyId | 弦? | 瞄准特定的玩具。为所有人省略。 |
______________________________________________________________________
play_pattern
播放平滑的循环强度循环。这 actions 数组定义 一个周期 重复为 durationSec 秒(如果为0,则无限期)。服务器以固定的时间间隔(最多50步,每步最少100毫秒)对航路点进行采样,并将它们作为Pattern命令发送到应用程序——应用程序循环遍历它们。
| 参数 | 类型 | 说明 |
|---|---|---|
actions | 阵列 | 循环航路点 { ts, pos },按升序排列 ts |
durationSec | number | 总运行时间(秒)。 0 =无限循环,直到 stop |
toyId | 弦? | 瞄准特定的玩具。为所有人省略。 |
ts:从周期开始算起的时间戳(毫秒)(最大30000=每个周期30秒)pos:强度0–100(0=关闭,50=中等,100=最大)
在构建步骤序列时,服务器在航路点之间进行线性插值。对于急剧过渡,将两个点相距约100ms。
为了实现平滑循环: 同时开始和结束循环 pos 值(通常为0),以便循环无缝重新启动。
示例:
// Slow wave, loop forever
actions: [{ ts: 0, pos: 0 }, { ts: 3000, pos: 100 }, { ts: 6000, pos: 0 }]
durationSec: 0
// Ramp up over 5s then snap off, loop for 2 min
actions: [{ ts: 0, pos: 0 }, { ts: 5000, pos: 80 }, { ts: 5100, pos: 0 }]
durationSec: 120
// Fast pulse (on 500ms / off 500ms), 30s
actions: [{ ts: 0, pos: 100 }, { ts: 500, pos: 100 }, { ts: 600, pos: 0 }, { ts: 1000, pos: 0 }]
durationSec: 30
// Constant medium for 10s
actions: [{ ts: 0, pos: 50 }, { ts: 10000, pos: 50 }]
durationSec: 10______________________________________________________________________
play_sequence
执行定时多阶段步骤序列。立即返回——调度在服务器端运行。使用此(不 play_pattern)何时:
- 阶段不循环(A然后B然后C,完成)
- 您可以在相位之间切换功能类型(例如振动10秒→ 冲刺10秒)
- 您需要同时具有独立强度的多个功能(例如振动:15+旋转:8)
每一步都有一个 duration (秒)和 "Stop" 或一系列同时进行的动作。
| 参数 | 类型 | 说明 |
|---|---|---|
steps | array | 有序列表 { duration, actions } 步骤 |
toyId | 弦? | 瞄准特定的玩具。为所有人省略。 |
退货 { sequenceId, totalDuration }.呼叫 stop 自动取消任何运行序列。
示例:
// Strong 5s → max 10s → pause 30s → medium 30s
[
{ duration: 5, actions: [{ type: "Vibrate", strength: 16 }] },
{ duration: 10, actions: [{ type: "Vibrate", strength: 20 }] },
{ duration: 30, actions: "Stop" },
{ duration: 30, actions: [{ type: "Vibrate", strength: 10 }] },
]
// Vibrate + Rotate simultaneously at different strengths
[{ duration: 10, actions: [{ type: "Vibrate", strength: 15 }, { type: "Rotate", strength: 8 }] }]
// Vibrate phase then switch to Thrusting
[
{ duration: 20, actions: [{ type: "Vibrate", strength: 13 }] },
{ duration: 20, actions: [{ type: "Thrusting", strength: 10 }] },
]
// Medium-amplitude thrust (Stroke toy): Stroke must always be paired with Thrusting
[{ duration: 10, actions: [{ type: "Stroke", min: 0, max: 50 }, { type: "Thrusting", strength: 10 }] }]______________________________________________________________________
stop
立即停止一切。取消任何正在运行的服务器端序列,并向Lovense API发送一个Function stop,因为当您希望它停止时,您就希望它停止。
| 参数 | 类型 | 说明 |
|---|---|---|
toyId | 弦? | 瞄准特定的玩具。为所有人省略。 |
______________________________________________________________________
强度参考
| 描述 | 0–20 | 0–3 | 0–100 |
|---|---|---|---|
| 非常轻 | 3 | 1 | 15 |
| 光线 | 6 | 1 | 30 |
| 中等 | 10 | 2 | 50 |
| 相当强 | 13 | 2 | 65 |
| 强 | 16 | 3 | 80 |
| 最大 | 20 | 3 | 100 |
______________________________________________________________________
配置
| 变量 | 必填 | 默认 | 描述 |
|---|---|---|---|
LOVENSE_TOKEN | ✓ | — | 来自Lovense门户的开发者令牌 |
LOVENSE_UID | ✓ | — | 应用程序的用户标识符 |
LOVENSE_UNAME | ✓ | — | Lovense Remote中显示的显示名称 |
LOVENSE_UTOKEN | ✓ | — | 任意用户令牌(您选择的任何字符串) |
SETUP_TOKEN | ✓ | — | 保护 /setup 页面 |
MCP_PORT | 3000 | 服务器监听的端口 | |
NODE_ENV | production | development 启用漂亮的日志和调试级别 | |
LOG_LEVEL | info | trace / debug / info / warn / error / fatal |
令牌永远不会被记录。甚至不是偶然。
______________________________________________________________________
HTTP端点
| 端点 | 描述 |
|---|---|
GET /mcp | MCP传输(由您的AI客户端使用) |
POST /callback | Lovense心跳接收器 |
GET /setup?token=xxx | 二维码设置页面 |
GET /health | 健康检查→ { ok: true } |
______________________________________________________________________
发展
bun run dev # watch mode, pretty logs, NODE_ENV=development
bun run start # production
bun run typecheck # type check only集 LOG_LEVEL=debug 查看完整的请求/响应正文和AppState转储。 LOG_LEVEL=trace 对于内部构件。
______________________________________________________________________
测试状态
用实际硬件进行诚实测试:
| 功能 | 状态 |
|---|---|
play_action → 振动 | ✅ 作品 |
play_pattern, play_sequence, play_preset | ✅ 工程(仅进行振动测试) |
get_toys, stop, get_qr | ✅ 作品 |
play_action → 旋转、泵送、推力等。 | 🟡 按照规范实施,未经测试 |
stroke_action | 🟡 按照规范实施,未经测试 |
未经测试的工具完全按照 Lovense服务器API文档 应该工作得很好。我只是不拥有整个Lovense目录——我向你保证,我在这里尽了最大的努力。具有真实测试报告的PR真的很受欢迎。
______________________________________________________________________
许可证
麻省理工学院
