> ## Documentation Index
> Fetch the complete documentation index at: https://developers.heymarket.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect AI tools with the Heymarket MCP server

> Connect Claude, Cursor, and other AI clients to Heymarket over the Model Context Protocol (MCP) to manage contacts, send messages, triage conversations, and run supervised broadcast campaigns.

The Model Context Protocol (MCP) lets AI tools and agents connect to Heymarket in a secure, standardized way. Heymarket hosts a remote MCP server, so a connected client can read your inboxes, search contacts and messages, send messages, triage conversations, and draft broadcast campaigns on behalf of an authenticated team member.

<Note>
  The Heymarket MCP server is in beta. Endpoints, tools, and authentication may change. Try it on a non-critical team first and share feedback with Heymarket.
</Note>

<Update label="August 2026" description="Outbound outreach and triage release">
  The tool surface grew from 12 to 34 tools. New in this release:

  * **Supervised broadcasts** - draft a campaign to a list, review the recipient count, and submit it for human approval before anything sends
  * **Contact lists** - create and manage the lists broadcasts send to
  * **Templates and team members** - discover message templates and look up teammates
  * **Triage and search** - list and count conversations across inboxes, full-text search over message bodies, and a conversation activity timeline
  * **Richer contact search** - filter by tags, custom fields, lists, opt-out status, and assigned user
  * **Token creation opened to members** - any team member (not just admins) can now create a Personal Access Token
</Update>

## What you can do

Once a client is connected, you can ask it to:

* **Browse inboxes** - list the inboxes you belong to and look up inbox details
* **Manage contacts** - create, retrieve, update, delete, and search contacts, including by tag, custom field, list, opt-out status, or assigned user
* **Send messages** - send a message to a contact through an inbox
* **Read and search history** - pull a conversation's message history or full-text search message bodies across your inboxes
* **Triage conversations** - list conversations longest-waiting first, count them by assignee, inbox, or status, and see a conversation's assignment history
* **Work conversations** - assign a conversation to a team member or transfer it to another inbox
* **Run broadcasts with approval** - build an audience list, draft a broadcast, and submit it for a human admin to approve before it sends

The MCP server exposes Heymarket actions only. The AI model itself lives in your client (Claude Desktop, Cursor, and so on), not in Heymarket.

## Endpoint and transport

Connect your client to the Heymarket MCP server at:

```text theme={null}
https://mcp.heymarket.com/mcp
```

The server uses the **Streamable HTTP** transport and speaks JSON-RPC over HTTP. Clients that support remote MCP servers can connect to this URL directly. Clients that speak only stdio (such as Claude Desktop) connect through the open-source [`mcp-remote`](https://www.npmjs.com/package/mcp-remote) bridge, which runs the remote server as a local command.

## Authentication

The MCP server authenticates each request with a **Personal Access Token (PAT)**. A PAT is a long-lived credential scoped to one team member and one team. Every MCP request sends it as a bearer token:

```text theme={null}
Authorization: Bearer hm_pat_your_token
```

### Create a Personal Access Token

You create a PAT from your profile in the Heymarket app. Any team member with a role of **member** or higher can create one; contacts and guests cannot.

<Steps>
  <Step title="Open your profile">
    Log in to [Heymarket](https://app.heymarket.com), click your avatar in the bottom-left to open the account dropdown, and select **Profile**.
  </Step>

  <Step title="Scroll to Personal Access Tokens">
    On your profile page, scroll down past **About** and **Two-Factor Authentication** to the **Personal Access Tokens** section. Any existing tokens are listed here with their name, team, masked token value, creation date, and last-used timestamp.
  </Step>

  <Step title="Click Generate token">
    Click the **Generate token** button in the top-right of that section.
  </Step>

  <Step title="Fill in the token details">
    In the **Generate personal access token** modal:

    * **Token name** - enter something descriptive, such as `Claude Desktop on laptop`, so you recognize its purpose later.
    * **Team** - select the team the token should be scoped to. Each token is tied to exactly one team, and teams you already hold a token for are disabled in the dropdown — you can only hold one active token per team.
  </Step>

  <Step title="Generate and copy the token">
    Click **Generate token**. A **Token created** confirmation appears showing the token name, team, and the full token value starting with `hm_pat_`. Click **Copy** right away — the full value is not shown again after you close the dialog.
  </Step>

  <Step title="Store it and close">
    Paste the token somewhere secure — a password manager, or directly into the `HEYMARKET_PAT` value of your MCP client configuration (covered in [Connect a client](#connect-a-client)) — then click **Done**.
  </Step>
</Steps>

<Warning>
  The full token is shown only when you create it. Heymarket stores it hashed and cannot show it again. Store it only in your MCP client configuration, and treat it like a password.
</Warning>

### Token scope and limits

* **One team per token.** A PAT grants access to the single team it was created in, using your role and inbox access in that team.
* **Member access required.** You need a role of member or higher to create a token and use the tools. Contacts and guests cannot access team data through MCP. A token acts at your role: `approve_broadcast` additionally requires an admin or owner role.
* **One active token per team member.** Each member can hold one active PAT per team. To replace a token, revoke the old one first, then create a new one.
* **No expiry.** A PAT stays valid until you revoke it. Revoke it from the **Personal Access Tokens** section of your profile if a device is lost or a team member leaves. Revocation takes effect on the next request.

## Connect a client

Add the Heymarket server to your client's MCP configuration, then restart the client. Replace `hm_pat_REPLACE_WITH_YOUR_TOKEN` with the token you created.

Clients that run the `mcp-remote` bridge need [Node.js](https://nodejs.org) 18 or later so they can invoke `npx`.

<Tabs>
  <Tab title="Claude Desktop">
    Open your `claude_desktop_config.json` file:

    | OS      | Path                                                              |
    | ------- | ----------------------------------------------------------------- |
    | macOS   | `~/Library/Application Support/Claude/claude_desktop_config.json` |
    | Windows | `%APPDATA%\Claude\claude_desktop_config.json`                     |
    | Linux   | `~/.config/Claude/claude_desktop_config.json`                     |

    Add the `heymarket` server, then fully quit and reopen Claude Desktop:

    ```json theme={null}
    {
      "mcpServers": {
        "heymarket": {
          "command": "npx",
          "args": [
            "-y",
            "mcp-remote",
            "https://mcp.heymarket.com/mcp",
            "--header",
            "Authorization: Bearer ${HEYMARKET_PAT}"
          ],
          "env": {
            "HEYMARKET_PAT": "hm_pat_REPLACE_WITH_YOUR_TOKEN"
          }
        }
      }
    }
    ```

    Keep the token in `env` rather than inline in `args` so it does not appear in process listings. After restarting, open a new chat and look for the tools indicator listing the Heymarket tools.
  </Tab>

  <Tab title="Claude Code">
    Claude Code connects to remote MCP servers over HTTP, so it does not need the bridge. Add the server with one command:

    ```bash theme={null}
    claude mcp add --transport http heymarket https://mcp.heymarket.com/mcp \
      --header "Authorization: Bearer hm_pat_REPLACE_WITH_YOUR_TOKEN"
    ```

    Verify the connection:

    ```bash theme={null}
    claude mcp list
    ```
  </Tab>

  <Tab title="Cursor">
    Add the server to your Cursor MCP configuration at `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (per project), then reload Cursor:

    ```json theme={null}
    {
      "mcpServers": {
        "heymarket": {
          "url": "https://mcp.heymarket.com/mcp",
          "headers": {
            "Authorization": "Bearer hm_pat_REPLACE_WITH_YOUR_TOKEN"
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Other clients">
    Any MCP client that supports a stdio command can connect through the `mcp-remote` bridge. Use the same shape as the Claude Desktop config:

    ```json theme={null}
    {
      "mcpServers": {
        "heymarket": {
          "command": "npx",
          "args": [
            "-y",
            "mcp-remote",
            "https://mcp.heymarket.com/mcp",
            "--header",
            "Authorization: Bearer ${HEYMARKET_PAT}"
          ],
          "env": {
            "HEYMARKET_PAT": "hm_pat_REPLACE_WITH_YOUR_TOKEN"
          }
        }
      }
    }
    ```

    Clients that support remote HTTP MCP servers directly can connect to `https://mcp.heymarket.com/mcp` and send the `Authorization: Bearer` header without the bridge.
  </Tab>
</Tabs>

## Available tools

The server advertises 34 tools. Your client discovers them automatically after it connects. All tools require a role of member or higher; `approve_broadcast` requires admin or owner.

### Inboxes

| Tool           | What it does                                                                   | Writes data |
| -------------- | ------------------------------------------------------------------------------ | ----------- |
| `list_inboxes` | List the inboxes you are a member of. Membership-scoped, not team-wide.        | No          |
| `get_inbox`    | Fetch details for one inbox, including whether it is currently in quiet hours. | No          |

### Conversations

| Tool                        | What it does                                                                                                                                                               | Writes data |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `list_conversations`        | List conversations for triage, longest-waiting first, in one inbox or across every inbox you belong to. Filter by assignee, contact, status, needs-reply, and time window. | No          |
| `count_conversations`       | Count conversations in one aggregate query, grouped by assigned user, inbox, or status, with the same filters as `list_conversations`.                                     | No          |
| `get_conversation`          | Fetch details for a conversation.                                                                                                                                          | No          |
| `get_conversation_activity` | Timeline of a conversation's assignment, unassignment, and inbox-transfer events.                                                                                          | No          |
| `assign_conversation`       | Assign a conversation to a team member.                                                                                                                                    | Yes         |
| `transfer_conversation`     | Transfer a conversation to another inbox.                                                                                                                                  | Yes         |

### Messages

| Tool                  | What it does                                                                                                                                   | Writes data |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `send_message`        | Send a message to a contact through an inbox.                                                                                                  | Yes         |
| `get_message_history` | Get one conversation's messages, by conversation ID or by inbox plus the contact's phone or email, with time-window filters and cursor paging. | No          |
| `search_messages`     | Full-text search over message bodies across the inboxes you belong to, scoped by inbox and time window.                                        | No          |

### Contacts

| Tool                 | What it does                                                                                                                          | Writes data |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `create_contact`     | Create a contact with a communication channel.                                                                                        | Yes         |
| `get_contact`        | Retrieve a contact's full record: channels, tags, notes, and custom field values.                                                     | No          |
| `update_contact`     | Update a contact's standard fields. Omitted fields keep their stored values.                                                          | Yes         |
| `delete_contact`     | Delete a contact.                                                                                                                     | Yes         |
| `search_contacts`    | Search contacts by free text (name, phone, or exact email), or filter by tag, custom fields, list, opt-out status, and assigned user. | No          |
| `list_custom_fields` | List the team's custom contact field definitions, for use in `search_contacts` filters.                                               | No          |
| `list_tags`          | List the team's contact tags, for use in `search_contacts` filters.                                                                   | No          |

### Lists

| Tool                        | What it does                                                                                                 | Writes data |
| --------------------------- | ------------------------------------------------------------------------------------------------------------ | ----------- |
| `list_lists`                | List the contact lists you can use, with member counts.                                                      | No          |
| `get_list`                  | Get a list by ID or name: live member count and whether an active campaign uses it.                          | No          |
| `create_list`               | Create a new, empty contact list.                                                                            | Yes         |
| `add_contacts_to_list`      | Add up to 500 contacts to a list per call.                                                                   | Yes         |
| `remove_contacts_from_list` | Remove up to 500 contacts from a list per call.                                                              | Yes         |
| `rename_list`               | Rename a contact list.                                                                                       | Yes         |
| `delete_list`               | Delete a contact list. Refuses when an active campaign uses the list; contacts themselves are never deleted. | Yes         |

### Templates and team members

| Tool             | What it does                                                                               | Writes data |
| ---------------- | ------------------------------------------------------------------------------------------ | ----------- |
| `list_templates` | List the team's message templates.                                                         | No          |
| `get_template`   | Get a template's full content by ID or name.                                               | No          |
| `list_users`     | List the team's members with their roles, to discover assignees for `assign_conversation`. | No          |

### Broadcasts

| Tool                | What it does                                                                                                                        | Writes data |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ----------- |
| `create_broadcast`  | Create a draft broadcast to a list. Nothing is sent; returns the opt-out-filtered recipient count and a message preview for review. | Yes         |
| `get_broadcast`     | Get a broadcast's status and recipient count.                                                                                       | No          |
| `list_broadcasts`   | List the team's broadcasts, newest first, filtered by status, inbox, or creation time.                                              | No          |
| `send_broadcast`    | Submit a draft for sending. The broadcast moves to pending approval; it does not send until a human approves.                       | Yes         |
| `approve_broadcast` | Approve a pending broadcast so it actually sends. Admin or owner only.                                                              | Yes         |
| `cancel_broadcast`  | Cancel a pending or scheduled broadcast, returning it to draft.                                                                     | Yes         |

<Note>
  Tools that write data run only with your approval. Most MCP clients ask before invoking a tool that sends a message or changes a contact, list, or conversation, unless you allow that tool for the session.
</Note>

## How broadcasts stay supervised

Every broadcast sent through MCP requires human approval — an AI agent cannot mass-message on its own. The flow has three gates:

<Steps>
  <Step title="Draft">
    `create_broadcast` creates a draft and sends nothing. It returns the recipient count with opted-out contacts already filtered, sample recipients, and a preview of the message so a person can review what would go out.
  </Step>

  <Step title="Confirm the count">
    `send_broadcast` requires `expected_recipient_count` to match the count shown on the draft. If the live count has changed — for example, contacts opted out since drafting — the call is rejected with the new count, forcing a fresh review. On success the broadcast moves to **pending approval**; still nothing sends.
  </Step>

  <Step title="Human approval">
    A team **admin or owner** approves the pending broadcast with `approve_broadcast` (or rejects it with `cancel_broadcast`, which returns it to draft). Only after approval does the broadcast send.
  </Step>
</Steps>

Retries are safe throughout: `create_broadcast` and `create_list` accept an optional `idempotency_key`, and resubmitting or re-approving an already-processed broadcast returns success with `idempotent_replay: true` instead of acting twice.

## Prompts

The server also publishes two MCP prompts — guided workflows your client can offer alongside the tools:

* **`launch_campaign`** - walks the client through building an audience, composing a message, creating a draft broadcast, reviewing the filtered recipient count with you, and submitting it for approval
* **`review_pending_broadcast`** - renders a pre-send review of a broadcast awaiting approval: recipients, message, and the exact approval step. Run it before approving.

## Rate limits

Repeated authentication failures are throttled. After about 30 failed attempts in a minute, the server returns HTTP `429 Too Many Requests`. This usually means the token is wrong or revoked, rather than that you are sending too many valid requests. Fix the token, then wait for the throttle window to pass before retrying.

## Security best practices

* Store the token only in your MCP client configuration. Do not commit it to source control or paste it into shared documents.
* A PAT acts as your account's access for the team it was created in, at your role. Anyone with the token can act as you in that team.
* Revoke a token immediately from the **Personal Access Tokens** section of your profile when a device is lost, a team member leaves, or you suspect the token leaked. Revocation takes effect on the next request.
* Rotate a token by revoking the old one and creating a new one. There is no separate refresh step.

## Troubleshooting

<AccordionGroup>
  <Accordion title="The client does not show the Heymarket tools">
    Confirm the configuration file is valid JSON and points to `https://mcp.heymarket.com/mcp`. Most clients read MCP configuration only at startup, so fully quit and reopen the client after editing it. In Claude Desktop, check **Settings > Developer** for MCP server startup errors.
  </Accordion>

  <Accordion title="Requests return 401 Unauthorized">
    The token is missing, malformed, or revoked. Confirm the `Authorization` header is `Bearer hm_pat_...` with no extra spaces or line breaks, and that the token has not been revoked. If you are unsure, create a new token and update your client configuration.
  </Accordion>

  <Accordion title="Requests return 429 Too Many Requests">
    Too many authentication attempts failed in a short window. This is almost always a bad or revoked token. Stop retrying with the failing token, fix it, then wait for the throttle window to pass before trying again.
  </Accordion>

  <Accordion title="Creating a token is blocked">
    Creating a Personal Access Token requires a role of member or higher — contacts and guests cannot create one — and each member can hold only one active token per team. If creation is blocked, revoke your existing token for that team first, or ask a team admin to grant the needed role.
  </Accordion>
</AccordionGroup>
