Reference
CLI, MCP and AI agents
Everything here runs through one small program, mb. Install it and sign in once; an AI agent then uses the same mb. An agent reaches it through mb mcp, which serves the same commands as tools, so there is nothing else to install.
Let an AI agent use Miss Blue
Paste this into Claude Code, Codex, Cursor, or any agent that can run commands. It installs mb and the Miss Blue skill, signs in once you approve in your browser, asks you which project to use, and connects itself. It does not send anything until you ask. Your project’s Developers page has the same prompt with the project already filled in.
Set up Miss Blue for me. It sends iMessages from my business numbers through a command line called mb.
1. Run `mb --version`. If mb is missing, install it:
macOS or Linux: curl -fsSL https://github.com/danest/missblue-cli/releases/latest/download/install.sh | sh
Windows (PowerShell): irm https://github.com/danest/missblue-cli/releases/latest/download/install.ps1 | iex
2. Install the Miss Blue skill so you know how to use mb: run `mb skill install` (if you are Codex, run `mb skill install --codex`). Read the SKILL.md it installs and follow its rules.
3. Run `mb login`. It opens my browser and waits, for up to 10 minutes, until I approve. Show me the code it prints.
4. Run `mb workspaces` and `mb projects --workspace <id>`, ask me which project to use, then run `mb use <project id>`.
5. If you can add MCP servers, add one named missblue that runs `mb mcp --project <project id>`. In Claude Code: `claude mcp add --scope user missblue -- mb mcp --project <project id>`. In Codex: `codex mcp add missblue -- mb mcp --project <project id>`. If you can't, skip this: the mb commands work either way.
6. Run `mb whoami` and tell me who I am signed in as and which project is selected. Do not send any messages until I ask.The Miss Blue skill
A skill is a SKILL.md file an agent reads when a task matches it. The Miss Blue skill tells the agent how to use mb: check who it is signed in as first, the commands for common tasks, and the rules it must follow, such as confirming before messaging more than one person and never pasting a key into the chat. Its command list comes from mb itself, so it always matches the version you have.
| Run | Installs to | Read by |
|---|---|---|
| mb skill install | ~/.claude/skills/missblue/SKILL.md | Claude Code, Cursor and OpenCode |
| mb skill install --codex | ~/.agents/skills/missblue/SKILL.md | Codex, Cursor and OpenCode |
Add --repo to put it in the current directory instead, to commit it for a team. Running it again after an update refreshes the file, unless you have edited it; then it leaves your copy alone until you add --force. mb skill prints it, and every release publishes it at https://github.com/danest/missblue-cli/releases/latest/download/SKILL.md for an agent that cannot run mb yet.
Setting it up by hand
Install mb and sign in as described below, install the skill, then add Miss Blue to your agent with the one command or file for it. Signed in, the agent gets mb mcp --project <project-id>, which keeps it in that project whatever your default is later. With a project key instead, the key goes in the agent’s environment and there is no project to name.
If an agent reports that it cannot find mb, replace "mb" with the full path that `command -v mb` prints (on Windows, `where.exe mb`).
Claude Code
Run in a terminal. --scope user makes it available in every project; leave it out to add it to the current project only.
Signed in with mb login
claude mcp add --transport stdio --scope user missblue -- mb mcp --project <project-id>With an API key
claude mcp add --transport stdio --scope user --env MISS_BLUE_API_KEY=mb_live_… missblue -- mb mcpEverything after -- is the command Claude Code runs, so the flags that follow it belong to mb.
Format from Claude Code’s documentation.
Codex
Run in a terminal. It writes ~/.codex/config.toml, which the Codex CLI, its IDE extension and the ChatGPT desktop app share.
Signed in with mb login
codex mcp add missblue -- mb mcp --project <project-id>With an API key
codex mcp add missblue --env MISS_BLUE_API_KEY=mb_live_… -- mb mcpFormat from Codex’s documentation.
OpenCode
Add to ~/.config/opencode/opencode.json for every project, or opencode.json in one project's root.
Signed in with mb login
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"missblue": {
"type": "local",
"command": ["mb", "mcp", "--project", "<project-id>"],
"enabled": true
}
}
}With an API key
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"missblue": {
"type": "local",
"command": ["mb", "mcp"],
"enabled": true,
"environment": {
"MISS_BLUE_API_KEY": "mb_live_…"
}
}
}
}Format from OpenCode’s documentation.
Cursor
Add to ~/.cursor/mcp.json for every project, or .cursor/mcp.json in one project.
Signed in with mb login
{
"mcpServers": {
"missblue": {
"command": "mb",
"args": ["mcp", "--project", "<project-id>"]
}
}
}With an API key
{
"mcpServers": {
"missblue": {
"command": "mb",
"args": ["mcp"],
"env": {
"MISS_BLUE_API_KEY": "mb_live_…"
}
}
}
}Format from Cursor’s documentation.
Claude Desktop
Settings → Developer → Edit Config opens claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\). Quit and reopen Claude afterwards.
Signed in with mb login
{
"mcpServers": {
"missblue": {
"command": "/full/path/to/mb",
"args": ["mcp", "--project", "<project-id>"]
}
}
}With an API key
{
"mcpServers": {
"missblue": {
"command": "/full/path/to/mb",
"args": ["mcp"],
"env": {
"MISS_BLUE_API_KEY": "mb_live_…"
}
}
}
}Claude Desktop does not read your shell's PATH. Replace /full/path/to/mb with what `command -v mb` prints (on Windows, `where.exe mb`).
Format from Claude Desktop’s documentation.
VS Code
For GitHub Copilot's agent mode. Add to .vscode/mcp.json in a project, or run “MCP: Open User Configuration” for every project.
Signed in with mb login
{
"servers": {
"missblue": {
"type": "stdio",
"command": "mb",
"args": ["mcp", "--project", "<project-id>"]
}
}
}With an API key
{
"inputs": [
{
"type": "promptString",
"id": "missblue-key",
"description": "Miss Blue API key",
"password": true
}
],
"servers": {
"missblue": {
"type": "stdio",
"command": "mb",
"args": ["mcp"],
"env": {
"MISS_BLUE_API_KEY": "${input:missblue-key}"
}
}
}
}Format from VS Code’s documentation.
Gemini CLI
Add to ~/.gemini/settings.json for every project, or .gemini/settings.json in one project.
Signed in with mb login
{
"mcpServers": {
"missblue": {
"command": "mb",
"args": ["mcp", "--project", "<project-id>"]
}
}
}With an API key
{
"mcpServers": {
"missblue": {
"command": "mb",
"args": ["mcp"],
"env": {
"MISS_BLUE_API_KEY": "mb_live_…"
}
}
}
}Format from Gemini CLI’s documentation.
A failed tool call comes back as a result marked isError, not a transport error, so the agent can read what went wrong and try something else. An agent holding a key reaches that project and nothing more.
Install
The same for every use. One command:
curl -fsSL https://github.com/danest/missblue-cli/releases/latest/download/install.sh | shThis puts mb in ~/.local/bin (or /usr/local/bin when that is writable), after checking the download against its published SHA-256 checksum. If that folder is not on your PATH yet, the installer prints the line to add. Run it again to update. Then check it:
mb --versionBuilds are published for macOS (Apple Silicon and Intel), Linux (x86_64 and arm64) and Windows (x86_64). To install by hand, download the archive for your platform from the latest release and put mb somewhere on your PATH.
Sign in and choose a project
The same for a person and for an agent on your machine.
mb loginmb login prints a short code and opens the console. You approve it there, in a browser you are already signed into, and the token is delivered to the terminal that asked. Nothing goes through a clipboard.
Your code is WDJB-MJHT
Open https://missblue.dev/device
and enter it. This code is good for 10 minutes.When you approve, you choose what it may reach: everything you can, or any combination of organizations and projects. Naming an organization covers the projects inside it, including ones added later. The choice is enforced on every request the sign-in makes: a token granted one project is refused the rest of your account, whatever your role is.
Then mb asks which project to work in. If the sign-in reaches more than one, it lists your organizations, then that organization’s projects, and you pick by number. With exactly one project it is chosen for you. That becomes the default for every command after it.
mb use # choose the default project again from the list
mb use <project-id> # or set it directly
mb whoami # who you are, and the project you are working inAny single command can work somewhere else with --project <project-id>, and MISS_BLUE_PROJECT does the same for a whole shell. A project’s id is in its console URL and on its Developers page.
The token is saved to ~/.config/miss-blue/credentials.json with mode 0600. mb logout deletes the local copy. It does not yet revoke the sign-in on the server, so a token that leaked stays valid until it expires; ask us and we will revoke it. If you are handing a machine a credential you may want back in a hurry, scope it narrowly.
On a machine with no browser, such as a server over ssh, pass --no-browser and open the printed URL somewhere else.
Use it from a terminal
After installing and signing in:
mb whoami
mb send --to +15555550100 --text "Your table is confirmed for 7pm"
mb send --to +15555550100 --file receipt.png
mb threads
mb lookup +15555550100
mb problems --only failedWith one number, send uses it. With several it stops and names them rather than guessing, because a reply on the wrong line is worse than a command you have to repeat.
Who has been answering
mb workspaces
mb projects --workspace <workspace-id>
mb activity --project <project-id> --days 7
mb member-activity --project <project-id> --user <user-id>These need a signed-in person, not a key: how much each person sent is not a question for something with nobody behind it. You see what you could already read: a project you are in, and within it anybody’s work on its numbers. A shared line’s traffic appears on the organization’s own report, counting only your people. The other business on the same number is never shown.
The basics
Add someone, tag them, message them and see what happened. The same commands work signed in or with a project key, and an agent gets them as tools.
Add a contact to Apple Contacts
mb contact-add --handle +15555550100 --first-name Ada --last-name Lovelace
mb contact --handle +15555550100Saves them to this project's contacts and queues them for Apple Contacts on your numbers, so Messages shows their name instead of the number. mb contact shows each number as queued, then synced. Add --no-sync to keep them in Miss Blue only, and --field product=Hoodie (once per field) for details your messages can fill in as {{ contact.custom.product }}.
Tag them
mb tag --tag vip --handles +15555550100Tags pick people for announcements and automations. If an automation starts on this tag, tagging messages them, so mb asks for --confirm first.
Send them a message
mb send --to +15555550100 --text "Hi Ada, your order is ready" --wait delivered--wait delivered holds until their phone confirms it, for up to a minute (--timeout 5m waits longer). Without --wait, mb returns as soon as the message is accepted.
See it delivered and read
mb message --id <message-id>
mb message --id <message-id> --wait read --timeout 10mIts delivery shows when it was sent, delivered and read. Read only appears if they have read receipts turned on, so it may never come.
Read their reply
mb threads
mb thread --chat-id <chat-id>threads lists conversations, newest first, and the send's answer carries the chat_id too. thread prints every message in the conversation, their replies included.
Announcements, scheduled messages and automations
Everything the console’s campaign tools do, mb does too, signed in or with a project key, and an agent gets the same commands as tools. The rules are the console’s: people who opted out are left out, people who have never messaged your number are paced, and a project’s first announcement is read by a person at Miss Blue before it goes out.
Announce to a list
mb announce --text "We open at nine from Monday" --list "Spring customers"
mb announce-send --id <announcement-id> --confirmThe first command sends nothing. It prints how many people it reaches, how many have never messaged your number (those go out at up to 50 a day) and who is left out because they opted out. Nothing goes until the second command, with --confirm.
Schedule a message for their morning
mb schedule --to +15555550100 --text "See you at ten" --at 2026-10-02T09:00:00-05:00 --time-zone America/ChicagoGive the time with the recipient's UTC offset, so nine means nine where they are.
Welcome new customers, then follow up
mb automation-create --name Welcome --tag new-customer --text "Welcome aboard!" --wait 2d --follow-up "Any questions so far?"
mb automation-on --id <automation-id>
mb tag --tag new-customer --handles +15555550100Created switched off. With no --from it sends from Auto, so each person gets the best of your numbers. A reply ends their run, and the follow-up only goes to people who have not answered the welcome; --stop-on-reply false and --follow-up-if change that. Once it is on, tagging somebody messages them, so mb asks for --confirm first.
Lists and tags: mb lists, mb list-create, mb list-add, mb tags, mb tag. What is queued or running: mb announcements, mb scheduled, mb automation-runs, and for one person, mb automation-status --handle: which automations they are in, how the last ones ended, and which would start for them. The skill tells an agent to show you the preview and get your yes before any announcement, never to automate messages to people who have not opted in, and to schedule for the recipient’s local time.
Change one thing about an automation without restating the rest: mb automation-update --id <id> --stop-on-reply false keeps it going after a reply, and --from auto or --from <number-id> moves it between Auto and one number. If a number it was pinned to leaves your project, it moves to another of your numbers, or is switched off when there is none, and mb automation shows a note saying which.
Business hours
mb automation-create --name Welcome --tag new-customer --text "Welcome aboard!" \
--hours 08:00-18:00 --days mon-fri
mb automation-update --id <id> --time-zone America/Chicago
mb automation-update --id <id> --any-time--hours keeps an automation to business hours: Eastern time unless you pass --time-zone, every day unless you pass --days (mon-fri, mon,wed,fri, weekends). A tag added at 11 PM still starts the automation then; its message waits for 8 AM. An update changes only the part you name, and --any-time clears the hours.
How an automation is doing
mb automation-stats --id <id> # the last 30 days, step by step
mb automation-stats --id <id> --all
mb automation-replies --id <id> --step 4 # who answered step 4, and what they saidautomation-stats gives each step’s sent, delivered, read (opened), replied and opted out, with reply and opt-out rates, and how people’s runs ended. Read only counts people with read receipts on, so it is at least that many. automation-replies lists every reply, newest first, with the message it answered and a link to the conversation.
A/B/C tests
mb automation-create --name Tour --tag toured --text "Thanks for coming by!" \
--text-b "Want a second look?" --weights 50,50 --wait 1d \
--follow-up "Still thinking it over?" --follow-up-b "Happy to set up another visit."
mb automation-stats --id <id> # each version, and a verdict
mb variant-use --automation <id> --step 1 --letter B # everybody new gets B
mb variant-weights --automation <id> --step 1 --weights 70,30
mb announce --text "Open house Saturday." --text-b "Come see it Saturday?" \
--list Leads --test-first 20% --pick-after 4h--text is version A; --text-b and --text-c add versions, split by --weights or evenly. Each person keeps their version for the follow-up. automation-stats puts the versions side by side and says whether one is ahead, or how many more people it needs first. variant-use sends one version to everybody who reaches that step from now on. variant-weights changes the split on the first step with versions, for people given a version from now on; later steps follow it. An announcement with --test-first tries the versions on that share of the list, then sends the rest the one with the best reply rate.
Run it on a server or in CI
Nobody can approve a sign-in there, so use a project key instead of mb login. A key comes from a project’s Developers page, under API keys, and belongs to that one project. Install mb as above, then:
export MISS_BLUE_API_KEY=mb_live_…
mb whoami
mb send --to +15555550100 --text "Your order has shipped"MISS_BLUE_API_KEY wins over a saved sign-in. Keep it in your CI or server secrets, never in a file you commit.
Every command
The same list in both places. A CLI command and an MCP tool of the same name do the same thing and take the same arguments: --allow-duplicate on the command line is allow_duplicate to an agent.
| whoami | What this key is, and which project it holds. |
| numbers | The numbers this project holds. |
| send | Send an iMessage.
|
| threads | Conversations, most recent first. |
| thread | Every message in one conversation.
|
| messages | Recent messages across this project's numbers. |
| message | One message, including when it was sent, delivered and read, and the Mac build that handled it.
|
| workspaces | The businesses you belong to. |
| projects | The projects in a workspace.
|
| activity | Who has been answering a project's numbers, and how much.
|
| member-activity | One person: what they sent, who to, and the messages.
|
| problems | Sends that failed, or are still waiting for a Mac.
|
| lookup | Whether iMessage is known to reach a handle. Answered from your own traffic, not from Apple.
|
| typing | Show or hide the typing bubble in a conversation.
|
| read | Tell the customer their message was seen. Only when a human has looked.
|
| react | Add or remove a tapback on a message.
|
| unsend | Unsend a message, inside Apple's two-minute window.
|
| edit | Change what a sent message says, inside Apple's fifteen-minute window.
|
| label | Name a number, so threads say which line they arrived on.
|
| contacts | Names this project has given handles. Shared by everyone on it. |
| name | Name a handle, or rename one. contact-add does the same and says what it queued for Apple Contacts.
|
| contact-add | Add a contact, or rename one, and queue them for Apple Contacts on this project's numbers, so Messages shows their name. Prints what was queued and how to check. --field sets their custom fields for messages to use.
|
| contact | One contact, and whether Apple Contacts on each of this project's numbers has them yet: queued, synced or failed.
|
| contact-sync | Put a saved contact in Apple Contacts again, on each of this project's numbers or one of them, and wait for each to answer. For a number that did not take it.
|
| forget | Remove a name from the project's book.
|
| webhooks | The endpoints this project sends events to. |
| webhook-add | Register where events should go.
|
| webhook-rm | Stop sending to an endpoint.
|
| deliveries | What we tried to send an endpoint, and what came back.
|
| announcements | Announcements (blasts) in this project, with how each is going. |
| announce | Draft an announcement (one message to many people) and preview it. Sends nothing. Show the user the preview (how many people, how many are first contacts and how long their pacing takes, who is left out) and the exact text before `announce-send`.
|
| announce-send | Send a drafted announcement. Prints the preview again. Only after the user has seen the preview and the text and explicitly said yes: pass confirm. Without it nothing is sent.
|
| announce-cancel | Cancel an announcement. One already sending stops; what went out stays out.
|
| scheduled | Messages scheduled for later, and what became of them. |
| schedule | Schedule one message for later. Pick a time that suits the recipient where they are.
|
| schedule-cancel | Cancel a scheduled message that has not gone yet.
|
| automations | Automations in this project: what starts each, its steps, and whether it is on. |
| automation | One automation, and what switching it on would do: who it reaches now and how long first contacts take.
|
| automation-create | Create an automation, switched off. A keyword reply, or a message when somebody joins a list or gets a tag, then a wait, then a follow-up only if they did not reply. A list or tag automation sends from Auto unless given a number. --hours keeps it to business hours. Only for people who asked to hear from this business.
|
| automation-update | Change an automation. Pass only what changes: --name, --from, --stop-on-reply, --allow-repeat or the hours flags alone keep its trigger and steps; a trigger flag replaces the trigger; --text and the follow-up flags replace the steps; --file replaces the whole thing. People partway through keep their step number.
|
| automation-on | Switch an automation on. Show the user what it will send and who it reaches first. With include_existing it also messages everybody already on the list or tag, which needs confirm after the user says yes.
|
| automation-off | Switch an automation off. Everybody partway through it stops.
|
| automation-delete | Delete an automation and everything partway through it. Ask the user first.
|
| automation-runs | Who is in an automation and how far they got, or which automations are messaging one person.
|
| automation-stats | How an automation is doing, step by step: sent, delivered, read (opened), replied and opted out, with reply and opt-out rates, and how people's runs ended. Read only counts people with read receipts on, so it is at least that many.
|
| automation-replies | Which texts got the replies: who answered an automation, what they said and when, the message they answered, and a link to the conversation. Newest first.
|
| automation-stop | Take one person out of one automation. Everybody else carries on.
|
| lists | Lists in this project, and how many people are on each. |
| list-create | Make a list.
|
| list-members | Who is on a list, newest first.
|
| list-add | Add people to a list. If an automation starts on this list, each new person is messaged, so that needs confirm after the user says yes.
|
| list-remove | Take somebody off a list. An automation they are in carries on.
|
| tags | Tags in this project, and how many people carry each. |
| tag | Tag people. If an automation starts on this tag, each newly tagged person is messaged, so that needs confirm after the user says yes.
|
| untag | Take a tag off somebody.
|
| mcp | Serve every command above as MCP tools over stdio. |
| skill | Print the Miss Blue skill. mb skill install installs it; see the skill. |
* required. Signing in and choosing a project (login, logout, use) are above.