# MCP tools

> The fifteen tools BlueBot's MCP server offers an assistant, what each one does, the inputs it takes and the API key scope it needs.

Your assistant picks tools by their descriptions, so you rarely name one. You say "did the text to Marcus get delivered?" and it calls `get_message`. This page is for when you want to know exactly what it can do, choose a key's scopes, or work out why a tool answered the way it did.

## Which scope each tool needs

A tool runs only when the key or sign-in has its scope. With a read-only key, the five `messages:send` tools and `create_contact` refuse, and everything else works.

| Scope            | Tools                                                                                                        |
| ---------------- | ------------------------------------------------------------------------------------------------------------ |
| `messages:send`  | `send_text`, `schedule_text`, `cancel_text`, `send_template`, `enroll_in_sequence`                           |
| `messages:read`  | `list_conversations`, `get_conversation`, `list_messages`, `get_message`, `list_templates`, `lookup_service` |
| `contacts:read`  | `search_contacts`                                                                                            |
| `contacts:write` | `create_contact`                                                                                             |
| `account:read`   | `get_device_status`, `get_analytics`                                                                         |

No tool needs `webhooks:manage`. [API keys and scopes](https://usebluebot.com/docs/concepts/api-keys)

## How the tools behave

**They're the API underneath.** Each tool calls the same code as the REST API, so a text sent with `send_text` is the same message `POST /v1/messages` makes: the same [states](https://usebluebot.com/docs/concepts/message-states), the same [holds](https://usebluebot.com/docs/concepts/holds), the same [sending rules](https://usebluebot.com/docs/concepts/sending-rules). It has `source: "mcp"`, and it fires the same webhooks.

**A held text is still a sent request.** When quiet hours, a daily limit or an offline Mac keeps a text from going now, the tool answers with the message `queued` and a `hold` saying why and until when. The assistant should tell you that, not try again. Sending again would only queue a second copy.

**Numbers can be written any common way.** Give a number however you'd say it: `(555) 555-0123`, `555.555.0123` or `+1 555 555 0123`. A number without a country code is taken as a US number. Answers always write numbers in E.164, `+15555550123`. An email address works for somebody on iMessage.

**Conversations include what you typed by hand.** `get_conversation` and `list_messages` read every text your Mac saw, including ones you sent from your iPhone or the Messages app, as long as BlueBot copies that chat. [Receiving texts](https://usebluebot.com/docs/sending/receiving)

**Templates and sequences come from the dashboard.** `list_templates`, `send_template` and `enroll_in_sequence` use the templates and sequences you made in **Templates** and **Sequences**. An assistant can't make or change them.

**Lookups are best guesses.** `lookup_service` answers from your own Messages history: if your newest chat with somebody was iMessage, they're probably on iMessage. With no history it says it doesn't know. [Lookups](https://usebluebot.com/docs/sending/lookups)

## When a tool refuses

A refused tool call comes back as an error the assistant reads to you. The codes are the API's:

| Code                 | It means                                                                                       |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| `insufficient_scope` | The key or sign-in doesn't have the scope this tool needs.                                     |
| `invalid_request`    | An input is wrong: a number that isn't one, a time without a zone, text over 2,000 characters. |
| `not_found`          | No text, contact, template or sequence with that id on your account.                           |
| `conflict`           | The record is past the point where this works, such as canceling a text that already went.     |
| `plan_lapsed`        | Your plan isn't active. Texts wait until it is.                                                |
| `account_held`       | BlueBot paused sending on your account. Write to support.                                      |
| `rate_limited`       | Too many calls in a minute. The assistant should wait and try again.                           |

[Errors](https://usebluebot.com/docs/errors) has every code.

## Every tool

### `send_text`

Sends a text from your number now. The answer is the message with its state; a text that can’t go yet comes back `queued` with a `hold` saying why. Needs the `messages:send` scope.

| Input      | Type       | Required   | What it is                                                                 |
| ---------- | ---------- | ---------- | -------------------------------------------------------------------------- |
| `to`       | `string`   | Yes        | A phone number in any format (US assumed) or an email address on iMessage. |
| `text`     | `string`   | Yes        | The words, up to 2,000 characters.                                         |
| `files`    | `string[]` | No         | File ids from an upload, sent after the words.                             |
| `service`  | \`"auto"   | "imessage" | "sms"\`                                                                    | No | How to send; `auto` uses whatever the newest chat with that person used. |
| `metadata` | `object`   | No         | String keys and values kept on the text and echoed on its webhooks.        |

Try: _Text Ana at +1 555 555 0123: “Running 10 minutes late, sorry!”_

### `schedule_text`

Schedules a text for a time. It stays editable and cancelable until then. Needs the `messages:send` scope.

| Input      | Type     | Required | What it is                                                                 |
| ---------- | -------- | -------- | -------------------------------------------------------------------------- |
| `to`       | `string` | Yes      | A phone number in any format (US assumed) or an email address on iMessage. |
| `text`     | `string` | Yes      | The words.                                                                 |
| `send_at`  | `string` | Yes      | ISO 8601 time with a zone.                                                 |
| `metadata` | `object` | No       | String keys and values kept on the text and echoed on its webhooks.        |

Try: _Remind Marcus tomorrow at 9 AM that his inspection is at 11._

### `cancel_text`

Cancels a scheduled or queued text. Needs the `messages:send` scope.

| Input | Type     | Required | What it is               |
| ----- | -------- | -------- | ------------------------ |
| `id`  | `string` | Yes      | The message id, `msg_…`. |

Try: _Cancel the reminder you scheduled for Marcus._

### `list_conversations`

Recent conversations, newest first, with the last text in each and whether it waits on you. Needs the `messages:read` scope.

| Input           | Type      | Required | What it is                                      |
| --------------- | --------- | -------- | ----------------------------------------------- |
| `limit`         | `integer` | No       | 1 to 50, default 20.                            |
| `waiting_on_me` | `boolean` | No       | Only conversations where the last text came in. |

Try: _Who’s waiting on a reply from me?_

### `get_conversation`

The texts with one person or group, oldest to newest, including ones typed by hand on the Mac or iPhone. Needs the `messages:read` scope.

| Input     | Type      | Required | What it is                                       |
| --------- | --------- | -------- | ------------------------------------------------ |
| `person`  | `string`  | No       | A phone number or email. Give this or `chat_id`. |
| `chat_id` | `string`  | No       | A group chat id.                                 |
| `limit`   | `integer` | No       | How many texts, 1 to 100, default 30.            |

Try: _What did Ana and I agree on last week?_

### `list_messages`

Texts in and out, filtered by person, direction, state or time. Needs the `messages:read` scope.

| Input       | Type      | Required | What it is                                          |
| ----------- | --------- | -------- | --------------------------------------------------- |
| `person`    | `string`  | No       | A phone number or email.                            |
| `direction` | \`"in"    | "out"\`  | No                                                  | Only received or only sent texts. |
| `state`     | `string`  | No       | A message state, such as `failed` or `unconfirmed`. |
| `since`     | `string`  | No       | ISO 8601 time.                                      |
| `limit`     | `integer` | No       | 1 to 100, default 25.                               |

Try: _Did any texts fail today?_

### `get_message`

One text with its state, hold and metadata. Needs the `messages:read` scope.

| Input | Type     | Required | What it is               |
| ----- | -------- | -------- | ------------------------ |
| `id`  | `string` | Yes      | The message id, `msg_…`. |

Try: _Did the text to Marcus get delivered?_

### `search_contacts`

Contacts by name, number, email or tag. Needs the `contacts:read` scope.

| Input   | Type      | Required | What it is                             |
| ------- | --------- | -------- | -------------------------------------- |
| `query` | `string`  | No       | Words in a name, a number or an email. |
| `tag`   | `string`  | No       | Only contacts with this tag.           |
| `limit` | `integer` | No       | 1 to 50, default 20.                   |

Try: _Find everyone tagged “buyer”._

### `create_contact`

Makes a contact, or updates the one with that number or email. Needs the `contacts:write` scope.

| Input        | Type       | Required | What it is             |
| ------------ | ---------- | -------- | ---------------------- |
| `handle`     | `string`   | Yes      | Phone number or email. |
| `first_name` | `string`   | No       | First name.            |
| `last_name`  | `string`   | No       | Last name.             |
| `tags`       | `string[]` | No       | Tags to add.           |

Try: _Save +1 555 555 0177 as Priya Shah, tag her “seller”._

### `get_device_status`

Whether your Mac is online, its checks, today’s counts against your limits, and how many texts are held. Needs the `account:read` scope.

It takes no inputs.

Try: _Is my Mac online? Why are texts waiting?_

### `list_templates`

Your saved texts and the variables each one takes. Needs the `messages:read` scope.

It takes no inputs.

Try: _What templates do I have?_

### `send_template`

Fills a template’s variables and sends it, now or at `send_at`. Needs the `messages:send` scope.

| Input         | Type     | Required | What it is                                                                 |
| ------------- | -------- | -------- | -------------------------------------------------------------------------- |
| `template_id` | `string` | Yes      | The template id, `tpl_…`.                                                  |
| `to`          | `string` | Yes      | A phone number in any format (US assumed) or an email address on iMessage. |
| `variables`   | `object` | No       | Values for the template’s `{{variables}}`; contact fields fill the rest.   |
| `send_at`     | `string` | No       | ISO 8601 time to send it later.                                            |

Try: _Send Ana the showing reminder for 3 PM._

### `enroll_in_sequence`

Starts a person on a sequence of follow-ups that stops when they reply or text STOP. Needs the `messages:send` scope.

| Input         | Type     | Required | What it is                                                                 |
| ------------- | -------- | -------- | -------------------------------------------------------------------------- |
| `sequence_id` | `string` | Yes      | The sequence id, `seq_…`.                                                  |
| `to`          | `string` | Yes      | A phone number in any format (US assumed) or an email address on iMessage. |
| `variables`   | `object` | No       | Values for the sequence’s templates.                                       |

Try: _Put Priya on the new-listing follow-up._

### `get_analytics`

The Analytics page’s numbers for a period: sent, delivered, read, replied, failed and stopped, and your median time to reply. Needs the `account:read` scope.

| Input  | Type      | Required | What it is                                                                                  |
| ------ | --------- | -------- | ------------------------------------------------------------------------------------------- |
| `days` | `integer` | No       | How many days, today included, counted from midnight in your time zone: 1 to 90, default 7. |

Try: _How many people replied this week, and how fast did I answer?_

### `lookup_service`

BlueBot’s best guess from your own Messages history, with its basis: `history` or `none`. Needs the `messages:read` scope.

| Input    | Type     | Required | What it is               |
| -------- | -------- | -------- | ------------------------ |
| `number` | `string` | Yes      | A phone number or email. |

Try: _Is +1 555 555 0188 on iMessage?_

## Next

- [Example prompts](https://usebluebot.com/docs/mcp/prompts): What to ask for each job.
- [OAuth or an API key](https://usebluebot.com/docs/mcp/auth): Sign-in, scopes and revoking.
