mirror of
https://github.com/AletheiaVox/signal_bridge_remote.git
synced 2026-10-07 03:18:17 +08:00
docs: OAuth connector setup, governor config, feature_index; add changelog
- claude.ai connector section now documents the OAuth login flow as the primary path, with the authless single-user fallback as Option C. - Project structure, requirements, and .env docs updated for the OAuth + governor modules; pointer to .env.example for the governor knobs. - Tools table covers the extended output types, the escalate hold contract, and feature_index for multi-motor devices. - Safety Features section documents the governor. - CHANGELOG.md records v1.1 and the v1.0 baseline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
77
CHANGELOG.md
Normal file
77
CHANGELOG.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## v1.1 — 2026-07-07
|
||||||
|
|
||||||
|
This release brings the remote server up to date with everything that
|
||||||
|
shipped in the [Android edition](https://github.com/AletheiaVox/signal_bridge_android)
|
||||||
|
since March, plus fixes found while porting. If you run a server from an
|
||||||
|
older clone, rebuild the Docker image (`docker-compose build --no-cache`)
|
||||||
|
and update your relay client — both sides changed.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- **OAuth 2.0 support.** Full flow for claude.ai custom connectors:
|
||||||
|
discovery metadata, dynamic client registration, a login page at
|
||||||
|
`/oauth/authorize`, and a token endpoint. Each user signs in with their
|
||||||
|
own account — no more sharing one token or relying on the single-phone
|
||||||
|
fallback. The fallback still works for single-user servers and can be
|
||||||
|
disabled with `SB_REQUIRE_MCP_AUTH=true`.
|
||||||
|
- **Safety governor.** Server-side heat model (intensity × time) that
|
||||||
|
forces a cooldown when a session runs hot for too long. Server defaults
|
||||||
|
via `SB_GOVERNOR_*` env vars, per-user overrides via
|
||||||
|
`GET`/`POST /safety/config`, current state surfaced in `list_devices`
|
||||||
|
and piggybacked on heartbeat pings.
|
||||||
|
- **`feature_index` on every output and pattern tool.** Multi-motor
|
||||||
|
devices (Lovense Edge, Dolce, …) can now have each motor driven
|
||||||
|
independently. Implemented in both relay clients; a bad index returns a
|
||||||
|
helpful error listing the valid ones.
|
||||||
|
- **`CHANGELOG.md`, `.env.example`, `.gitignore`, `.gitattributes`.**
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- **Neutral engineering terminology** in tool schemas and
|
||||||
|
`devices.json`, matching the Android edition. Content filters on some
|
||||||
|
LLM platforms refused tools whose schemas contained explicit anatomical
|
||||||
|
language; the reworded schemas work across providers. `list_devices`
|
||||||
|
now also shows what each output channel does.
|
||||||
|
- Duplicate same-model devices get suffixed short names (`lush`,
|
||||||
|
`lush_2`) instead of silently replacing each other.
|
||||||
|
- Relay clients no longer push an unsolicited device list after
|
||||||
|
authenticating; the server requests a scan on connect and the scan
|
||||||
|
response covers it.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **MCP protocol compliance:** JSON-RPC notifications (e.g.
|
||||||
|
`notifications/initialized`) now get the bare `202` the spec requires
|
||||||
|
instead of a malformed error, and `initialize` echoes the client's
|
||||||
|
`protocolVersion` when supported. Fixes connection failures with strict
|
||||||
|
clients.
|
||||||
|
- **OAuth token endpoint** 500'd when a client POSTed the token request
|
||||||
|
as `multipart/form-data` (missing `python-multipart` dependency).
|
||||||
|
- **`governor_enabled`** now round-trips as a real JSON boolean; strict
|
||||||
|
clients (the Android app) previously couldn't re-enable the governor
|
||||||
|
after disabling it.
|
||||||
|
- **Patterns with `duration=0` silently did nothing.** They now run
|
||||||
|
until an explicit stop, matching plain commands.
|
||||||
|
- **`escalate` hold contract:** `hold_seconds` ≤ 0 holds at peak until
|
||||||
|
stopped, > 0 auto-stops after the hold — and an error mid-ramp can no
|
||||||
|
longer leave the device running at the last intensity it reached.
|
||||||
|
- **Pattern collisions:** starting a pattern cancels the previous
|
||||||
|
pattern on that device (they used to fight over the actuator), and a
|
||||||
|
direct command now supersedes a running pattern instead of being
|
||||||
|
overwritten by it.
|
||||||
|
- **Stale auto-stops:** a `duration` auto-stop from an earlier command
|
||||||
|
could fire minutes later and silently kill output a newer command had
|
||||||
|
started. Auto-stops are now tracked per channel and cancelled when
|
||||||
|
something newer takes over.
|
||||||
|
- Pattern timing now uses a monotonic clock; an NTP wall-clock jump
|
||||||
|
could stretch, truncate, or instantly end a pattern.
|
||||||
|
- Repo hygiene: removed accidentally committed compiled bytecode
|
||||||
|
(`__pycache__`) and a stray deploy tarball.
|
||||||
|
|
||||||
|
## v1.0 — 2026-03-14
|
||||||
|
|
||||||
|
Initial public release: FastAPI relay server (MCP over HTTPS, JWT auth,
|
||||||
|
rate limiting, dead man's switch), Windows/desktop relay client, and the
|
||||||
|
Termux relay for Android.
|
||||||
41
README.md
41
README.md
@@ -90,15 +90,19 @@ On your local machine, create the project directory and prepare files. The proje
|
|||||||
signal-bridge-remote/
|
signal-bridge-remote/
|
||||||
├── Dockerfile
|
├── Dockerfile
|
||||||
├── docker-compose.yml
|
├── docker-compose.yml
|
||||||
├── .env
|
├── .env (copy .env.example and fill in)
|
||||||
├── requirements-server.txt
|
├── requirements-server.txt
|
||||||
|
├── requirements-phone.txt
|
||||||
├── server/
|
├── server/
|
||||||
│ ├── __init__.py
|
│ ├── __init__.py
|
||||||
│ ├── app.py
|
│ ├── app.py
|
||||||
│ ├── auth.py
|
│ ├── auth.py
|
||||||
│ ├── config.py
|
│ ├── config.py
|
||||||
|
│ ├── governor.py
|
||||||
│ ├── models.py
|
│ ├── models.py
|
||||||
│ ├── mcp_tools.py
|
│ ├── mcp_tools.py
|
||||||
|
│ ├── oauth.py
|
||||||
|
│ ├── oauth_routes.py
|
||||||
│ ├── relay_hub.py
|
│ ├── relay_hub.py
|
||||||
│ ├── safety.py
|
│ ├── safety.py
|
||||||
│ └── session_registry.py
|
│ └── session_registry.py
|
||||||
@@ -147,6 +151,7 @@ websockets>=12.0
|
|||||||
bcrypt>=4.1.0
|
bcrypt>=4.1.0
|
||||||
PyJWT>=2.8.0
|
PyJWT>=2.8.0
|
||||||
python-dotenv>=1.0.0
|
python-dotenv>=1.0.0
|
||||||
|
python-multipart>=0.0.9
|
||||||
```
|
```
|
||||||
|
|
||||||
**.env:**
|
**.env:**
|
||||||
@@ -158,12 +163,20 @@ SB_HOST=0.0.0.0
|
|||||||
SB_PORT=8420
|
SB_PORT=8420
|
||||||
SB_REGISTRATION_OPEN=true
|
SB_REGISTRATION_OPEN=true
|
||||||
SB_TOKEN_EXPIRY_HOURS=720
|
SB_TOKEN_EXPIRY_HOURS=720
|
||||||
|
# true = every MCP request must be authenticated (multi-user servers).
|
||||||
|
# false = single-user convenience: unauthenticated MCP requests go to the
|
||||||
|
# sole connected phone.
|
||||||
|
SB_REQUIRE_MCP_AUTH=false
|
||||||
SB_HEARTBEAT_INTERVAL=2.0
|
SB_HEARTBEAT_INTERVAL=2.0
|
||||||
SB_HEARTBEAT_TIMEOUT=6.0
|
SB_HEARTBEAT_TIMEOUT=6.0
|
||||||
SB_BAN_THRESHOLD=20
|
SB_BAN_THRESHOLD=20
|
||||||
SB_BAN_DURATION_MINUTES=30
|
SB_BAN_DURATION_MINUTES=30
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See [.env.example](.env.example) for the full list, including the safety
|
||||||
|
governor's tuning knobs (`SB_GOVERNOR_*` — heat/cooldown rates for the
|
||||||
|
session intensity limiter).
|
||||||
|
|
||||||
Upload to your VPS:
|
Upload to your VPS:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -290,17 +303,21 @@ Add this MCP server config:
|
|||||||
|
|
||||||
Restart Claude Desktop. You should see Signal Bridge in your available tools.
|
Restart Claude Desktop. You should see Signal Bridge in your available tools.
|
||||||
|
|
||||||
### Option B: claude.ai Custom Connector (authless)
|
### Option B: claude.ai Custom Connector (OAuth)
|
||||||
|
|
||||||
Claude.ai supports custom MCP connectors without authentication, using a fallback mechanism: when only one phone is connected, all MCP requests are routed to that phone automatically.
|
The server implements the full OAuth 2.0 flow that claude.ai custom connectors expect (discovery metadata, dynamic client registration, authorize + token endpoints). Each user logs in with their own Signal Bridge account, so this works properly on multi-user servers.
|
||||||
|
|
||||||
1. Go to claude.ai Settings (or click the connector icon in the chat)
|
1. Go to claude.ai Settings (or click the connector icon in the chat)
|
||||||
2. Choose "Add custom connector" (or "Add MCP server")
|
2. Choose "Add custom connector" (or "Add MCP server")
|
||||||
3. Enter your server URL: `https://signal-bridge.duckdns.org/mcp`
|
3. Enter your server URL: `https://signal-bridge.duckdns.org/mcp`
|
||||||
4. Leave authentication as "None"
|
4. Save — claude.ai will open your server's login page
|
||||||
5. Save
|
5. Sign in with the username and password you registered in step 1.4
|
||||||
|
|
||||||
**Important**: The authless fallback only works when exactly one phone/relay client is connected to the server. If no phones are connected, claude.ai will show a connection error. Start your relay client first, then connect from claude.ai.
|
### Option C: claude.ai without login (single-user fallback)
|
||||||
|
|
||||||
|
If you skip the OAuth login, the server falls back to routing unauthenticated MCP requests to the sole connected phone — convenient for a private single-user server.
|
||||||
|
|
||||||
|
**Important**: The authless fallback only works when exactly one phone/relay client is connected to the server (and is disabled entirely when `SB_REQUIRE_MCP_AUTH=true`). If no phones are connected, claude.ai will show a connection error. Start your relay client first, then connect from claude.ai.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -466,18 +483,19 @@ Once connected, Claude has access to these tools:
|
|||||||
|
|
||||||
| Tool | Description |
|
| Tool | Description |
|
||||||
|------|-------------|
|
|------|-------------|
|
||||||
| `list_devices` | Show connected devices and their capabilities |
|
| `list_devices` | Show connected devices, their output channels, and governor state |
|
||||||
| `scan_devices` | Rescan for new or reconnected Bluetooth devices |
|
| `scan_devices` | Rescan for new or reconnected Bluetooth devices |
|
||||||
| `vibrate` | Send vibration (intensity 0.0–1.0, optional duration in seconds) |
|
| `vibrate` | Send vibration (intensity 0.0–1.0, optional duration in seconds) |
|
||||||
| `rotate` | Rotation or sonic output (device-dependent) |
|
| `rotate` | Rotational/high-frequency actuator output (device-dependent) |
|
||||||
| `oscillate` | Thrusting/oscillation output |
|
| `oscillate` | Linear reciprocating output |
|
||||||
|
| `constrict` / `temperature` / `led` / `position` / `spray` | Extended outputs for devices that support them |
|
||||||
| `pulse` | Rhythmic on/off pattern |
|
| `pulse` | Rhythmic on/off pattern |
|
||||||
| `wave` | Smooth sine-wave intensity modulation |
|
| `wave` | Smooth sine-wave intensity modulation |
|
||||||
| `escalate` | Gradual ramp from 0 to peak, with optional hold |
|
| `escalate` | Gradual ramp to peak; `hold_seconds` > 0 auto-stops after holding, 0 holds until stopped |
|
||||||
| `stop` | Immediately stop all output (also cancels patterns) |
|
| `stop` | Immediately stop all output (also cancels patterns) |
|
||||||
| `read_battery` | Read device battery level |
|
| `read_battery` | Read device battery level |
|
||||||
|
|
||||||
All output tools accept `device` (name or "all"), `intensity` (0.0–1.0), and `duration` (seconds, 0 = until stopped). Pattern tools also accept `output_type` to modulate rotation or oscillation instead of vibration.
|
All output tools accept `device` (name or "all"), `intensity` (0.0–1.0), and `duration` (seconds, 0 = until stopped). Pattern tools also accept `output_type` to modulate rotation or oscillation instead of vibration. Multi-motor devices (e.g. Lovense Edge, Dolce) additionally take `feature_index` to drive one motor independently — omit it to drive all matching motors together.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -486,6 +504,7 @@ All output tools accept `device` (name or "all"), `intensity` (0.0–1.0), and `
|
|||||||
Signal Bridge has several safety mechanisms built in:
|
Signal Bridge has several safety mechanisms built in:
|
||||||
|
|
||||||
- **Dead Man's Switch**: The server pings the relay client every 2 seconds. If 3 pings go unanswered (6 seconds), the server sends an emergency stop to all devices and disconnects the session. Your devices will never be left running if the connection drops.
|
- **Dead Man's Switch**: The server pings the relay client every 2 seconds. If 3 pings go unanswered (6 seconds), the server sends an emergency stop to all devices and disconnects the session. Your devices will never be left running if the connection drops.
|
||||||
|
- **Safety Governor**: A server-side heat model (intensity × time) that forces a cooldown when a session runs too hot for too long. Tunable server-wide via `SB_GOVERNOR_*` env vars and per-user via `GET`/`POST /safety/config`; current heat is shown in `list_devices` and can be disabled per user.
|
||||||
- **Auto-stop on Duration**: Commands with a `duration` parameter automatically stop after the specified time.
|
- **Auto-stop on Duration**: Commands with a `duration` parameter automatically stop after the specified time.
|
||||||
- **Fallback Stop**: If a stop command references a device name that doesn't exist, ALL devices are stopped as a safety fallback.
|
- **Fallback Stop**: If a stop command references a device name that doesn't exist, ALL devices are stopped as a safety fallback.
|
||||||
- **Rate Limiting**: Prevents command flooding (120 commands/minute default).
|
- **Rate Limiting**: Prevents command flooding (120 commands/minute default).
|
||||||
|
|||||||
Reference in New Issue
Block a user