A standard Vercel AI SDK chat app — with CloudSignal MQTT as the transport layer instead of HTTP streaming.
This is the only line that changes:
// Default — HTTP streaming
const { messages, sendMessage } = useChat();
// CloudSignal — MQTT streaming (offline recovery, multi-device, ACL)
const { messages, sendMessage } = useChat({
transport: new CloudSignalChatTransport({
api: '/api/chat',
authEndpoint: '/api/auth/mqtt',
wssUrl: 'wss://connect.cloudsignal.app:18885/',
}),
});Same messages. Same sendMessage. Same UI code. Different infrastructure.
The CloudSignalChatTransport implements the Vercel AI SDK ChatTransport interface. Every feature of the SDK — streaming, error states, abort signals — works as normal. The browser just receives tokens over WebSocket instead of an HTTP response body.
- Offline recovery via retained messages — the broker holds the completed response. Reconnect and the full answer is delivered immediately, no re-request needed.
- Multi-device sync — subscribe from phone and desktop simultaneously; both receive every token.
- No per-message pricing — unlike Ably or Pusher, CloudSignal has no per-message fees.
- ISO standard protocol — MQTT is ISO/IEC 20922. Any MQTT client library works, no vendor lock-in.
- QoS guarantees — use QoS 0 for disposable token stream, QoS 1 for guaranteed delivery of critical messages.
- Broker-level tenant isolation — VerneMQ mountpoints isolate organizations at the broker, not in application code.
- Per-message ACL enforcement — topic-level access control on every publish and subscribe, not just at connection time.
Browser (React) Next.js API Route
| |
| WSS (port 18885) | MQTTS (port 8883)
| @cloudsignal/mqtt-client | @cloudsignal/mqtt-client
| |
+---------> CloudSignal Broker <----------+
The browser connects via WebSocket Secure using @cloudsignal/mqtt-client. The Next.js API route connects via native MQTTS using the same package. Both talk to the same broker, same topics.
useChatcallstransport.sendMessages()— an HTTP POST that triggers the server.- The server calls Claude via AI SDK
streamText()and publishesUIMessageChunkobjects to MQTT as tokens arrive. - The browser's MQTT subscription converts the incoming messages into a
ReadableStreamthat the AI SDK consumes normally. - On disconnect and reconnect, the broker delivers the retained complete response — no data loss, no re-request.
git clone <repo-url>
cd cloudsignal-ai-chat
npm install
cp .env.example .env.local
# Edit .env.local with your keys
npm run devOpen http://localhost:3000 to start chatting.
| Variable | Description |
|---|---|
ANTHROPIC_API_KEY |
Claude API key from console.anthropic.com |
CLOUDSIGNAL_TOKEN_SERVICE_URL |
Token service URL (default: https://auth.cloudsignal.app) |
CLOUDSIGNAL_SECRET_KEY |
Organization secret key from CloudSignal dashboard |
CLOUDSIGNAL_ORG_ID |
Organization UUID from CloudSignal dashboard |
NEXT_PUBLIC_CLOUDSIGNAL_WSS_URL |
WSS endpoint (default: wss://connect.cloudsignal.app:18885/) |
CLOUDSIGNAL_MQTTS_URL |
MQTTS endpoint for server (default: mqtts://connect.cloudsignal.app:8883) |
Copy .env.example to .env.local and fill in your values.
| Topic | QoS | Retained | Purpose |
|---|---|---|---|
chat/{chatId}/stream |
0 | No | UIMessageChunk stream |
chat/{chatId}/complete |
1 | Yes | Full response for offline recovery |
The transport handles the following without any application code:
- Stream timeout (server crash protection — stream is closed after a configurable idle period)
- HTTP error propagation (non-2xx responses are surfaced as AI SDK errors)
- Request ID filtering (prevents interleaved chunks from concurrent requests)
- Stale retained message validation (ignores retained messages from previous sessions)
- Subscription cleanup (unsubscribes and disconnects on abort or completion)
See MQTT AI Chat Security Spec for a detailed comparison of CloudSignal MQTT vs HTTP streaming and proprietary services.
- Next.js 16 with App Router
- React 19
- Vercel AI SDK (
aipackage) foruseChat,streamText, andUIMessageChunk - @anthropic-ai/sdk for Claude
- Tailwind CSS for styling
@cloudsignal/ai-transport— theCloudSignalChatTransportclass that implements the Vercel AI SDKChatTransportinterface over MQTT.@cloudsignal/mqtt-client— shared MQTT client used by both the browser (WSS) and the server (MQTTS).
- In-memory conversation history — chat history is stored in server memory and will be lost on restart. For production, replace with a persistent store (database, Redis, etc.).
- Unauthenticated auth endpoint — the
/api/auth/mqttendpoint has no authentication. For any deployment beyond localhost, add rate limiting or session-based access control.
MIT