# MCP server

Source: https://jointextkit.com/docs/mcp
Index: https://jointextkit.com/llms.txt

Connect TextKit to Claude, Cursor or any MCP client and the agent can send
texts, buy numbers, load contacts, build segments, run broadcasts and set up
automations on your account.

The server is `https://mcp.jointextkit.com`. Sign in to connect, or pass an
API key.

## Connect from Claude

**claude.ai and Claude Desktop:** Settings → Connectors → Add custom
connector, URL `https://mcp.jointextkit.com`. Claude sends you to TextKit
to sign in. Approve the connection, pick test or live data, and you are back
in Claude.

**Claude Code:**

```bash
claude mcp add --transport http textkit https://mcp.jointextkit.com
```

Then run `/mcp` in Claude Code and choose TextKit to sign in.

Approving creates an API key named for the app, listed on the
[API keys](/console/keys) page; revoke it there to disconnect. Connecting the
same app again replaces its key. Only an account admin can approve.

## Connect from ChatGPT

In ChatGPT, open Plugins, select +, then Add custom MCP server, with the URL
`https://mcp.jointextkit.com/chatgpt` and OAuth, and create it as a plugin.
ChatGPT sends you to TextKit to sign in; approve it the same way. This URL
has every tool except Verify and API keys: ChatGPT does not allow one-time
codes.

Step-by-step guides for Lovable, Replit, Bolt, v0, VS Code, Gemini CLI,
Cline and more are on the [integrations](/integrations) page.

## Add to Replit or Cursor

[Add to Replit](https://replit.com/integrations?mcp=eyJkaXNwbGF5TmFtZSI6IlRleHRLaXQiLCJiYXNlVXJsIjoiaHR0cHM6Ly9tY3Auam9pbnRleHRraXQuY29tIiwiaGVhZGVycyI6W119) · [Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=textkit&config=eyJ1cmwiOiJodHRwczovL21jcC5qb2ludGV4dGtpdC5jb20ifQ==)

Both open the app with TextKit filled in; sign in when it asks. In Replit,
Agent can then text from the apps it builds: ask it to create an API key with
`create_api_key` and store it as the secret `TEXTKIT_API_KEY`.

## Connect with an API key

Any MCP client that can send a header:

```json
{
  "mcpServers": {
    "textkit": {
      "url": "https://mcp.jointextkit.com",
      "headers": { "Authorization": "Bearer ssms_sk_test_..." }
    }
  }
}
```

Start with test data: everything runs in the [sandbox](/docs/sandbox) and no
real phone gets a text. Every tool is one API call with your key, so its
scopes, rate limits and send checks apply unchanged. To limit what an agent
can do, give it a key with only the [scopes](/docs/authentication) it needs.

## Things to ask

> Buy a number in area code 512 and text +15005550006 "Your order shipped."

> Import the contacts in this CSV, tag them spring-sale, and tell me how many
> have an opt-in.

> Send everyone tagged vip "Doors open at 9 on Saturday." Do a dry run first
> and show me the count and cost.

> When someone triggers cart_abandoned, wait an hour, and text them a reminder
> unless checkout_completed arrives first.

> How did yesterday's broadcast do? Show delivered, failed, replies and
> opt-outs.

## Bring an audience from any tool

Your people can be anywhere: an analytics tool, a CRM, a store, an email
tool, billing, your own database, a spreadsheet or a file. Ask for them and
the agent works out how to get them.

> Import my users who can get marketing texts.

If you have not said where they are, the agent asks (`plan_import`): where
your people live, which group, what you can sign in to, whether consent was
recorded, and once or kept in sync. Then it offers the ways in, best first:

| Way in | When |
|---|---|
| Tools already in the chat | The agent has that tool's MCP server, a connector, or database access: nothing to set up |
| Integration | Shopify, HubSpot, Salesforce, Mixpanel, Amplitude, synced every 6 hours. You type the credentials into the console link it gives, never into the chat |
| Push | Segment, RudderStack, Hightouch, Census or a cohort webhook posts people as they change |
| Script | A key you keep in your own environment; the agent writes the code |
| Export or CSV | The agent tells you where the export button is, then reads the file or you upload it in the console |

> Bring the "Trial ending this week" cohort from Mixpanel into TextKit and
> text them a reminder about the upgrade offer.

With a source named, the agent then:

1. Reads the cohort with the other tool: phone, name, its id there, any SMS
   consent it recorded, and a few attributes worth merging.
2. Calls `import_contacts` with `dry_run: true` and shows you what will be
   created, updated, skipped or already opted out. Up to 500 per call.
3. Imports them tagged (for example `mixpanel-trial-ending`) and saves a
   segment on that tag.
4. Calls `send_batch` with `dry_run: true`: recipients, cost, and who is
   removed and why. It sends after you approve.

Run it again later to refresh: contacts are matched by phone number, and the
agent removes the tag from people who left the cohort.

**Consent comes from the source, never from the agent.** A cohort is not
permission to text. Marketing goes only to people with an opt-in on file, so
the agent carries over `opt_in` only where the source recorded one (when,
and where it was collected). Without it they can still get transactional
texts. See [opt-out and consent](/docs/opt-out).

## Prompts

Three built-in playbooks show up as commands in clients that support MCP
prompts (in Claude Code: `/mcp__textkit__import_audience`):

| Prompt | Arguments | What it does |
|---|---|---|
| `import_audience` | `source`, `audience`, `tag` (all optional) | Asks where your people are if you have not said, offers every way in, imports with a dry run first, keeps the tag in sync, saves a segment |
| `send_campaign` | `audience`, `goal` | Finds or imports the audience, drafts the text, dry-runs it, sends or schedules after you approve |
| `campaign_report` | `period` | Delivery, replies, opt-outs and spend per batch, the trend, and a follow-up cohort |

## Tools

| Area | Tools |
|---|---|
| Messages | `send_message`, `get_message`, `list_messages`, `delete_message`, `redact_message`, `simulate_inbound`, `list_events` |
| Verification | `send_verification`, `check_verification`, `fallback_verification`, `get_verification` |
| Numbers | `list_numbers`, `get_number`, `search_available_numbers`, `purchase_number`, `bulk_purchase_numbers`, `bulk_update_numbers`, `release_number`, `link_number_to_registration`, `assign_number_to_customer`, `export_numbers`, `lookup_phone` |
| Sender pools | `list_number_pools`, `create_number_pool`, `get_number_pool`, `update_number_pool`, `delete_number_pool`, `clone_number_pool` |
| Contacts | `plan_import`, `import_contacts`, `upsert_contact`, `list_contacts`, `get_contact`, `update_contact`, `delete_contact`, `bulk_update_contacts`, `set_contact_topic` |
| Segments and topics | `query_audience`, `create_segment`, `list_segments`, `get_segment`, `update_segment`, `delete_segment`, `preview_segment`, `list_topics`, `create_topic`, `get_topic`, `update_topic`, `delete_topic`, `get_contact_topics` |
| Consent | `get_consent`, `set_consent`, `list_opt_outs`, `import_opt_outs` |
| Templates | `create_template`, `list_templates`, `get_template`, `update_template`, `delete_template` |
| Broadcasts | `send_batch`, `list_batches`, `get_batch`, `get_batch_results`, `list_batch_recipients`, `pause_batch`, `resume_batch`, `cancel_batch`, `retry_batch` |
| Scheduled and recurring | `list_scheduled_messages`, `get_scheduled_message`, `cancel_scheduled_message`, `create_schedule`, `list_schedules`, `get_schedule`, `update_schedule`, `delete_schedule` |
| Automations | `track_event`, `create_automation`, `list_automations`, `get_automation`, `update_automation`, `delete_automation`, `activate_automation`, `pause_automation`, `list_automation_runs`, `get_automation_run`, `cancel_automation_run` |
| Account | `get_balance`, `get_usage`, `get_spend_limit`, `set_spend_limit`, `get_deliverability`, `list_audit_logs`, `list_registrations`, `get_registration`, `list_registration_submissions`, `list_toll_free_verifications`, `get_toll_free_verification`, `forget_identity` |
| Reports and exports | `export_csv` (messages, deliveries, events, opt-outs, usage, audit log, credit history), `export_consent`, `wait_for_events` |
| Webhooks | `create_webhook`, `list_webhooks`, `get_webhook`, `update_webhook`, `delete_webhook`, `rotate_webhook_secret`, `test_webhook`, `replay_failed_webhooks`, `list_webhook_deliveries`, `replay_event` |
| Customers (platforms) | `create_customer`, `list_customers`, `get_customer`, `update_customer`, `delete_customer`, `get_customer_usage` |

Tools that send, delete or turn something on are marked `destructiveHint`,
read-only ones `readOnlyHint`, so your client can ask before running them.
Each tool is one call to the [API](/docs/api) and takes the same inputs, so a
new field or list filter there shows up in the tool too. A failed call
returns the API's error object with `isError: true`. Filing a 10DLC
registration or toll-free verification (they carry a business attestation
and fees) and fetching the webhook signing secret stay in the console and
the API.

## Cohorts

Ask about your audience in plain words and the agent turns it into segment
rules: "who replied in the last 7 days", "who got Friday's broadcast and
didn't answer", "who started checkout but never bought". `query_audience`
answers with the counts and the first contacts without saving anything;
`create_segment` saves the cohort so `send_batch` can text it. See
[segments](/docs/contacts#segments) for every rule.

## Protocol

Streamable HTTP, stateless JSON (no sessions or SSE), protocol version
`2025-03-26`. `initialize`, `tools/list` and `prompts/list` work without a
key; `tools/call` needs one. Discovery: [/.well-known/mcp.json](/.well-known/mcp.json).
