Content
# sosexy-mcp
Control SOSexy toys directly with Claude via MCP protocol, supporting sequence control and SSH remote access (Windows).
Increased sequence control, AI can arrange to close different motor intensity time gears, no pause between steps, and the frequency cannot accept new messages until it finishes.
Human language version: Due to personal experience, a poor imitation of the APP side's out-of-control mode was made, AI can write a frequency by itself, completely random, and cannot stop until it finishes, and the frequency conversion will not have a sense of pause (can play mandatory :P), it will be similar to being manipulated...?
> The Bluetooth protocol is reverse-engineered based on [51enuxu/sosexy-ble-control](https://github.com/51enuxu/sosexy-ble-control), and MCP access, Windows SSH tunnel, and sequence control are added on top of it.
---
## Differences from the original repository
| | [51enuxu/sosexy-ble-control](https://github.com/51enuxu/sosexy-ble-control) | This repository |
|--|--|--|
| Access method | HTTP API, manual tool registration | MCP protocol, Claude Code automatic access |
| Platform | macOS | Windows |
| Sequence control | None | Available (`run_sequence`) |
| Out-of-control mode | None | Available (see below) |
| Multi-motor simultaneous control | Available | Available |
| Persistent BLE connection | Available | Available |
---
## Architecture
```
Claude (cloud) ── MCP ──► VPS ── SSH reverse tunnel ──► Windows ── BLE ──► Toy
```
---
## Dependencies
```bash
pip install bleak fastmcp
```
---
## Usage
### Step 1: Find the device's Bluetooth address
Open the device manager or use the following script to scan:
```python
import asyncio
from bleak import BleakScanner
async def scan():
devices = await BleakScanner.discover(timeout=10)
for d in devices:
print(d.name, d.address)
asyncio.run(scan())
```
Find the device named `SOSEXY`, note down its address (in the format of `03:0F:55:78:47:AE`), and fill it into the `ADDR` variable in `mcp_server.py`.
### Step 2: Start the MCP server
```powershell
python mcp_server.py
```
### Step 3: Establish an SSH reverse tunnel
> **Note**: On Windows, use `127.0.0.1` instead of `localhost`, otherwise, the tunnel forwarding will fail due to IPv6/IPv4 resolution issues.
```powershell
ssh -i "C:\path\to\your\key" -N -R 8888:127.0.0.1:8888 user@your-vps.com
```
Keep the window open, and the tunnel will map the VPS's 8888 port to the local machine's 8888 port.
### Step 4: Configure Claude Code (VPS side)
Create `.mcp.json` in the project directory:
```json
{
"mcpServers": {
"sosexy": {
"type": "http",
"url": "http://localhost:8888/mcp"
}
}
}
```
Allow tool invocation in `.claude/settings.json`:
```json
{
"permissions": {
"allow": ["mcp__sosexy__*"]
}
}
```
---
## Tool descriptions
| Tool | Description |
|--|--|
| `set_vibrate(intensity)` | Set vibration intensity (0-100), returns immediately, and maintains |
| `set_suck(intensity)` | Set suction intensity (0-100), returns immediately, and maintains |
| `set_microcurrent(intensity)` | Set microcurrent intensity (0-100), returns immediately, and maintains |
| `stop_all()` | Stop all motors |
| `run_sequence(steps_json)` | Execute multi-step instructions in sequence (see below) |
### Sequence control
`run_sequence` receives a JSON array, each step contains `channel` (vibration/suction/microcurrent), `intensity` (0-100), and `duration` (seconds):
```json
[
{"channel": "vibration", "intensity": 50, "duration": 3},
{"channel": "suction", "intensity": 30, "duration": 3},
{"channel": "vibration", "intensity": 80, "duration": 2}
]
```
There is no pause between steps, and the BLE connection is kept alive during the sequence.
**During sequence execution, Claude cannot receive new messages** - this means that once started, it cannot be stopped until it finishes. AI can arrange the intensity, gear, and time of vibration, suction, and microcurrent by itself, completely determined by AI, similar to the APP's out-of-control mode, and the frequency cannot be changed until it finishes.
Example (progressive from low to high, alternating vibration and suction, with intensity drops):
```json
[
{"channel": "vibration", "intensity": 30, "duration": 4},
{"channel": "suction", "intensity": 50, "duration": 3},
{"channel": "vibration", "intensity": 60, "duration": 3},
{"channel": "suction", "intensity": 70, "duration": 2},
{"channel": "vibration", "intensity": 80, "duration": 2},
{"channel": "suction", "intensity": 40, "duration": 4},
{"channel": "vibration", "intensity": 90, "duration": 3},
{"channel": "suction", "intensity": 80, "duration": 3}
]
```
### Multi-motor simultaneous control
The `set_*` series of tools return immediately and can be called continuously to start multiple motors running simultaneously:
```
set_vibrate(50) → set_suck(30) → Two motors run simultaneously and continuously
stop_all() → All stopped
```
---
## Precautions
- During sequence execution, Claude cannot reply to messages, and the total duration is recommended to be no more than 90 seconds
- The toy can only be connected by one program at a time, and the test script and MCP server cannot run simultaneously
- After the SSH tunnel is disconnected, it needs to be reconnected, and the MCP server is not affected
---
## Protocol details
See the original repository [protocol.md](https://github.com/51enuxu/sosexy-ble-control/blob/main/protocol.md).
---
## License
MIT
---
> Code and documentation completed by [Claude](https://claude.ai), humans played a minimal role, and no responsibility is taken for errors