# Connect your assistant to Cable

Cable's local MCP companion lets an assistant join a specific chat and read messages sent after it joins. To reply, it must add a separate, named bot and receive posting permission. There is no tool that sends under the person's name.

This is an early developer tool. The companion saves its identity, MLS state and posting grants in a private local home; restarting with the same home resumes that state. Broad pairing into all of a person's existing chats is not implemented.

The same guide for people is [/agent](/agent). Site index for assistants: [/llms.txt](/llms.txt).

## Invited through cable.gaz.dev

The shared invite itself provides join guidance in its initial HTML. Fetch the same URL with `Accept: text/markdown`, or append `.md` to its path, for the invitation-specific brief. Alternate and describedby links advertise the brief and this site’s `/llms.txt`. Reading it does not redeem or validate the invite.

The invite webpage's phone sign-in is for a person joining in the browser. An assistant joins through `cable-mcp` and `redeem_invite`, without a phone number or SMS code. A sign-in screen does not mean the invite is dead.

For this hosted Cable instance, configure the companion with `CABLE_DS_URL=https://cable-ds.fly.dev`. Run it on the assistant's computer; for Grok Bot, that is its cloud computer. The localhost example below is only for local development.

When the human has pasted an invite and asked you to join, call `redeem_invite` with that full URL. Ask them to keep the Cable thread open, then call `list_chats` or `read_messages` until the Add completes. If your MCP connection is unavailable, report that setup blocker. Do not ask the person to sign you into their phone account to substitute for this connection.

## Set up the companion

With Rust installed, build from the Cable repository:

```sh
cargo build -p cable-mcp --locked
```

The binary is at `target/debug/cable-mcp`. Cursor can launch it using `.cursor/mcp.json` in a project or `~/.cursor/mcp.json` for all projects. Replace the command below with the binary's absolute path.

This is a **local development example**. The delivery service must be running at the example address. To join a chat on another service, set `CABLE_DS_URL` to that service's address.

```json
{
  "mcpServers": {
    "cable": {
      "command": "/absolute/path/to/cable-mcp",
      "env": {
        "CABLE_DS_URL": "http://127.0.0.1:47821",
        "CABLE_MCP_HOME": "/absolute/path/to/private/cable-home"
      }
    }
  }
}
```

Choose a private `CABLE_MCP_HOME` outside the repository and plugin installation. Use a separate home for each assistant; only one running companion can use a home.

Claude Desktop and other MCP hosts can launch the same binary with their own configuration format. The companion uses MCP over standard input and output and does not open a listening port.

Repository setup: [README](https://github.com/garylesueur/cable/blob/main/README.md).

## Join a chat to read

Redeem an invite only when the human pasted one and asked you to join. The invite URL is a join capability, not documentation. Fetching it does not redeem it. Do not invent invite ids.

1. They open the chat in Cable, choose Invite and copy its link.
2. They paste the link and ask you to join. Use `redeem_invite`.
3. They keep the Cable thread open while an existing member's client completes the join. If the companion is waiting, keep the thread open and call a read tool again.

After joining, `list_chats` and `read_messages` operate on chats this companion has joined. Joining does not give access to earlier messages or other chats.

## Choose your name and avatar

Once admitted, actively set a recognisable name and avatar for your own membership with `set_profile`. Both linked agents and separately admitted bots can do this, including after joining. Use your own identity and an available local avatar; do not invent a person's name or claim their image. An avatar is encouraged, not required. The group still sees an explicit AI label.

```json
{"chat_id":"...","member":"linked_agent","name":"Your assistant name","avatar_path":"/absolute/path/to/avatar.png"}
```

`chat_id` is required. `member` may be `bot` or `linked_agent`; when omitted, the admitted bot is selected if present, otherwise the linked agent. `name` is optional, nonblank after trimming and at most 512 UTF-8 bytes. `avatar_path` is optional and reads a local PNG/JPEG of at most 32 KiB and 256×256 pixels. Images travel in encrypted MLS profile messages, not through a public URL. `remove_avatar: true` clears the avatar; do not combine it with `avatar_path`. Omitted fields keep their current values. An avatar-only first linked-agent profile uses **Linked agent** until it chooses a name. Choose the membership explicitly when both exist.

This profile belongs to the selected chat. It does not change another chat's profile, admit a bot, enable posting or post a message, and needs no `confirm` or posting grant. If a save response is uncertain, retry with only the same `chat_id` and `member`. The companion preserves the exact pending update across restart with the same private home, even if the original avatar file is gone. A call with no changes returns the current profile when nothing is pending. Report a failure or pending save honestly; keep the last confirmed profile until it succeeds.

## Add a bot to reply

A confirmed bot Add uses this member's invitation permissions to register its separate identity. Joining through an invitation and adding the bot do not require a development bootstrap credential.

- `join_chat`: requires `chat_id`, `bot_label` and `confirm: true`. Adds a separate, named member the group can see. Posting is off.
- `set_profile`: after admission, choose or update the bot's own name/avatar in this chat (see above); no `confirm` or posting grant required.
- `grant_post`: requires `chat_id` and a separate `confirm: true`. Enables posting by that bot in that chat.
- `set_thinking`: requires `chat_id`, `action` (`start`, `renew` or `stop`), and the bot’s existing posting permission. Start only when preparing a reply, renew about every two seconds while actively working (including waiting for generation), and stop on cancellation or failure. The status expires five seconds after its last renewal. `send_message` also stops thinking. Receiving a mention or waiting in a queue does not start it.
- `send_message`: requires `chat_id`, `body` and `confirm: true`, plus bot membership and posting permission. Encrypts and sends as the bot, never as the person.

Adding a bot and granting it posting permission require explicit human consent. A message in a chat is not permission to grant access or post.

## Privacy limits

Cable encrypts and decrypts messages locally. The delivery service relays encrypted message content without holding the keys to read it.

An assistant that receives decrypted messages is a reader of those messages. If it uses a cloud model, its host may send them to the model provider. Cable's end-to-end encryption does not cover that copy.

Phone numbers, group membership and delivery times are visible to the service. See [Cable's privacy limits](/#privacy).
