From 9dafd12104b366ad73bfe0076eba4032f8eb9b9d Mon Sep 17 00:00:00 2001 From: Aletheia Date: Tue, 7 Jul 2026 20:20:57 +0200 Subject: [PATCH] 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 --- CHANGELOG.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 41 ++++++++++++++++++++-------- 2 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..287e227 --- /dev/null +++ b/CHANGELOG.md @@ -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. diff --git a/README.md b/README.md index 4592c70..0d5d06a 100644 --- a/README.md +++ b/README.md @@ -90,15 +90,19 @@ On your local machine, create the project directory and prepare files. The proje signal-bridge-remote/ ├── Dockerfile ├── docker-compose.yml -├── .env +├── .env (copy .env.example and fill in) ├── requirements-server.txt +├── requirements-phone.txt ├── server/ │ ├── __init__.py │ ├── app.py │ ├── auth.py │ ├── config.py +│ ├── governor.py │ ├── models.py │ ├── mcp_tools.py +│ ├── oauth.py +│ ├── oauth_routes.py │ ├── relay_hub.py │ ├── safety.py │ └── session_registry.py @@ -147,6 +151,7 @@ websockets>=12.0 bcrypt>=4.1.0 PyJWT>=2.8.0 python-dotenv>=1.0.0 +python-multipart>=0.0.9 ``` **.env:** @@ -158,12 +163,20 @@ SB_HOST=0.0.0.0 SB_PORT=8420 SB_REGISTRATION_OPEN=true 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_TIMEOUT=6.0 SB_BAN_THRESHOLD=20 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: ```bash @@ -290,17 +303,21 @@ Add this MCP server config: 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) 2. Choose "Add custom connector" (or "Add MCP server") 3. Enter your server URL: `https://signal-bridge.duckdns.org/mcp` -4. Leave authentication as "None" -5. Save +4. Save — claude.ai will open your server's login page +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 | |------|-------------| -| `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 | | `vibrate` | Send vibration (intensity 0.0–1.0, optional duration in seconds) | -| `rotate` | Rotation or sonic output (device-dependent) | -| `oscillate` | Thrusting/oscillation output | +| `rotate` | Rotational/high-frequency actuator output (device-dependent) | +| `oscillate` | Linear reciprocating output | +| `constrict` / `temperature` / `led` / `position` / `spray` | Extended outputs for devices that support them | | `pulse` | Rhythmic on/off pattern | | `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) | | `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: - **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. - **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).