How to connect Claude Code or Cursor to an iMessage number with MCP
To connect Claude Code to an iMessage number, run claude mcp add --transport http zerosettle https://portal.zerosettle.io/mcp and sign in with your phone number; there is no token to paste, because ZeroSettle's MCP server uses OAuth 2.1. The ZeroSettle connector is a setup tool: it signs you up, mints your server's API key, registers and tests your webhook, and sends a test message to your own number, while the server it builds owns the customer conversation. Claude on web, desktop and mobile, Cursor and Grok are documented too.
Key takeaways
- What it is: a remote MCP server at
https://portal.zerosettle.io/mcp(Streamable HTTP, OAuth 2.1 with dynamic client registration and PKCE). You sign in with your phone number. - Documented clients: Claude Code, Claude on web, desktop and mobile, Cursor, and Grok (the xAI Responses API or grok.com). ZeroSettle documents no ChatGPT connector; there you paste the docs' setup prompt instead.
- What it is for: getting a number, wiring your server to it, and checking the wiring against your own number. It is not a way to message customers.
- Price: Pro is $49/month for one number, paid through a Stripe Checkout link the agent hands you. Growth is from $599/mo, through a signup link from ZeroSettle.
- Main limit: on Pro, 5 new contacts a day per number, for every caller, the connector included. Messages with people who message you first are unlimited.
What does the ZeroSettle connector do?
The ZeroSettle connector lets an AI coding agent get you an iMessage number, build the server that will use it, and test that server against your own number; it is not a way to message customers. ZeroSettle is an iMessage API: a real phone number on real iMessage, running on Apple hardware we operate for you, that your code texts customers from and hears back on through a bearer token and signed webhooks.
The server the agent builds receives on a webhook and replies with POST /api/imessage/send; the connector's own send and read tools exist only to test it.
| Group | Tools | Used for |
|---|---|---|
| Setup | get_line, sign_up, set_profile, send_test_message, subscribe, read_docs, create_api_key, set_webhook, clear_webhook, test_webhook | Sign-up, the docs, the API key, the webhook |
| Verification | send_imessage, list_conversations, list_messages, show_typing | Testing against your own number |
| Hosted agent | get_agent, set_agent, start_conversation; for the agent's files and MCP servers, list_agent_connectors, add_agent_file, add_mcp_server, update_mcp_server, remove_agent_connector | Running the number with no server |
get_line, sign_up, set_profile, send_test_message, subscribe and read_docs work before you pay; the rest need an active subscription. A failure, including a 402 or a sign-up that finds no free number, comes back as a tool result marked as an error rather than an HTTP error, so the agent can read it and tell you.
How to add the connector to Claude Code, Claude, Cursor or Grok
Every documented client points at https://portal.zerosettle.io/mcp, and all but the xAI API sign you in with OAuth. Under the MCP authorization spec, a client finds the sign-in server from the MCP server itself and must use PKCE; ZeroSettle also supports the dynamic client registration the spec recommends, so the URL alone is enough.
| Client | Where you add it | Sign-in |
|---|---|---|
| Claude Code | claude mcp add, then /mcp | Your phone number, in the browser |
| Claude (web, desktop, mobile) | Customize → Connectors → Add custom connector | Choose Sign in now, then your phone number |
| Cursor | The Add to Cursor link, or .cursor/mcp.json | OAuth, found from the URL |
| Grok on the xAI API | An mcp tool in a Responses API request | Static API token |
| grok.com | Connectors → New Connector → Custom | Sign in |
| ChatGPT | No documented connector | Paste the docs' setup prompt, with an API token |
Anthropic's help center says Claude's Free plan allows one custom connector; on Team and Enterprise an owner adds it in Organization settings first, then each member connects. For ChatGPT or any agent with a shell, paste the setup prompt from the ZeroSettle iMessage API docs with an API token from the console, or start from one line: "implement the ZeroSettle iMessage API according to https://portal.zerosettle.io/docs.md".
Claude Code
claude mcp add --transport http zerosettle https://portal.zerosettle.io/mcp
Then run /mcp, pick zerosettle and choose Authenticate. Adding --scope project to the command writes the server to a .mcp.json your team can commit; Claude Code asks each teammate to approve a project-scoped server before using it.
Cursor
Use the Add to Cursor link in ZeroSettle's connect-your-AI-agent docs, or put this in .cursor/mcp.json (one project) or ~/.cursor/mcp.json (every project). Cursor finds the OAuth flow from the URL, so the file holds no token.
{
"mcpServers": {
"zerosettle-imessage": { "url": "https://portal.zerosettle.io/mcp" }
}
}
Grok and the xAI API
An app that embeds Grok passes the connector as an mcp tool in a request to xAI's Responses API, with a static token minted in the ZeroSettle console and read from the environment. On grok.com, use Connectors → New Connector → Custom and sign in.
import os
zerosettle_tool = { # goes in the tools list of a https://api.x.ai/v1/responses request
"type": "mcp",
"server_url": "https://portal.zerosettle.io/mcp",
"server_label": "zerosettle-imessage",
"authorization": f"Bearer {os.environ['ZEROSETTLE_TOKEN']}",
}
How to sign up and get a number from the agent
Run the get-started prompt, or say "get me an iMessage number", and the agent runs ZeroSettle's sign-up as tool calls; only the payment happens in a browser.
get_linereportsonboarding(sign_up,claim,test,subscribeorready) with anexthint.sign_upclaims a free number for youruse_cases:sign_in,branded_messagesorai_agent. A Growth signup link's token goes ininvite.set_profilesets the brand name and photo recipients see.send_test_messagetexts your own number and shares that name and photo.subscribereturns a Stripe Checkout link. After you pay,get_lineshowsactive: true.
A number not paid for within 30 minutes is released, and until the subscription is active the API answers 402 to everything. Numbers can run out; if all are taken, you can join the waitlist. Pro is $49/month with a 30-day money-back guarantee; see ZeroSettle pricing for Growth.
How to build your use case with a prompt
ZeroSettle's four build prompts each scaffold one integration in your stack: the prompt carries your account's state and the matching docs section, has the agent read the webhook and compliance sections, then walks it through the build, the API key, the webhook and a check on your own number. Claude Code shows them as slash commands such as /zerosettle:build-sign-in; Cursor and Claude list them in the prompts menu.
| Prompt | Builds | Docs section it carries |
|---|---|---|
build-support-bot | A receiver that routes each inbound text to your team and lets them reply from your number | Customer support |
build-agent | A receiver that hands each text plus the thread to your model and replies, with typing | AI agent |
build-retention-flow | The leave-event hook that sends one offer, and the receiver for the reply | Retention offers |
build-sign-in | The attempt store, the SIGNIN <code> matcher, the session mint for your auth provider, the tapback | Sign in with iMessage |
Pass stack (for example "Node + Express on Fly.io") or the agent asks. See also an AI agent on your own model and Sign in with iMessage.
How the agent wires your server: API key, webhook, test
Wiring your server takes four connector steps: create_api_key, set_webhook, test_webhook, and one send_imessage to your own number.
- API key:
create_api_keymints your server's bearer token, shown once. It belongs in the server's environment, never in source. Minting again revokes nothing; revoking revokes all. - Webhook: the agent exposes the receiver (locally,
cloudflared tunnel --url http://localhost:8100) and callsset_webhook(url). The signing secret is shown once; calling again rotates it. - Test event:
test_webhookPOSTs a signed syntheticmessage.received(id0,"test": true, headerX-ZeroSettle-Test: 1) and reports your receiver's status, latency and error. It is not retried and not recorded as a delivery. - Round trip:
send_imessagetexts your own number, you reply, andlist_messagesshows whether your server answered.
The test event is signed like a real one, so the receiver verifies it first and can then skip the business logic on the X-ZeroSettle-Test header. This FastAPI receiver uses the docs' verifier and dedupes on message.id plus event; how ZeroSettle webhooks work covers retries.
# receiver.py: run with uvicorn receiver:app --port 8100
import hashlib, hmac, json, os, time
from fastapi import FastAPI, Request, Response
app = FastAPI()
SECRET = os.environ["ZEROSETTLE_WEBHOOK_SECRET"]
seen: set[tuple[int, str]] = set() # use a durable store in production
def verify(header: str, raw: bytes, tolerance: int = 300) -> bool:
try:
parts = dict(p.split("=", 1) for p in header.split(","))
t, v1 = int(parts["t"]), parts["v1"]
except Exception:
return False
if abs(time.time() - t) > tolerance:
return False
expected = hmac.new(SECRET.encode(), f"{t}.".encode() + raw, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, v1)
def enqueue(message: dict) -> None:
print("inbound", message["id"], message["handle"]) # hand off to your worker here
@app.post("/webhook")
async def webhook(req: Request):
raw = await req.body()
if not verify(req.headers.get("X-ZeroSettle-Signature", ""), raw):
return Response(status_code=401)
if req.headers.get("X-ZeroSettle-Test") == "1":
return {"ok": True} # test_webhook: signature passed
ev = json.loads(raw)
if ev["event"] == "message.received":
key = (ev["message"]["id"], ev["event"]) # retries repeat this pair
if key not in seen:
seen.add(key)
enqueue(ev["message"]) # answer 2xx now, reply from the worker
return {"ok": True}
- Today 3:12 PM
- Business: Test from Fern Studio's new number. Reply to this text to check the round trip.
- Builder: does this reach the server?
- Business: It does. This answer came from your server through the API.
- Builder: STOP
send_imessage, then the builder's server replying. Gray: the builder's own number. The STOP tests opt-out handling; sends to this number now return 403 recipient_opted_out until the builder texts START.When test_webhook or the round trip fails
A failed check comes down to the URL, reachability, the signature check or the 10-second answer.
| What you see | Likely cause | Fix |
|---|---|---|
set_webhook error: "url must be https://" | Plain http:// for anything but localhost, or a URL over 2048 characters | Register the tunnel's https:// URL |
test_webhook: ConnectionError | The receiver or the tunnel is not running, so the URL is not reachable from the internet | Start both, then run test_webhook again |
test_webhook: HTTP 301, 302 or 307 | The URL redirects (for example, to add a trailing slash); ZeroSettle follows no redirects | Register the final URL |
test_webhook: HTTP 401 from your receiver | Signature checked on parsed JSON, or an old secret after set_webhook rotated it | Verify the raw bytes with the newest secret |
test_webhook: a timeout | The receiver works before answering; it has 10 seconds to return a 2xx | Answer first, then queue |
Round trip: your reply is in list_messages, with no answer after it | The receiver acted on message.sent instead of message.received, or the delivery failed | Check last_delivery (below) |
test_webhook is not recorded as a delivery, so last_delivery in GET /api/imessage/line shows only real events, such as the message.sent from the round-trip text, with its status code and error:
export BASE=https://portal.zerosettle.io
curl -s -H "Authorization: Bearer $ZEROSETTLE_TOKEN" $BASE/api/imessage/line
Can I skip the server and use ZeroSettle's hosted AI agent?
Yes. With no server, set_agent with managed_by: "zerosettle" and a business_context hands your number to ZeroSettle's hosted AI agent (Managed by AI Agent, Beta), which answers every inbound text from your business context. start_conversation opens new threads.
- Replace the example first. The business context is required, up to 40,000 characters, and defaults to a made-up business. Have the agent call
read_docs("agent")before writing it. - Either-or per number (per line group on Growth). Inbound texts no longer reach your webhook, and sends from the connector's
send_imessage, the API or the console are refused with403 managed_by_zerosettle. Test by texting the number yourself. - AI credits. One per text the hosted agent sends; Pro includes 1,000 a month and Growth 5,000.
managed_by: "api" hands the number back to your server. Settings are in how ZeroSettle's hosted AI agent answers iMessages.
Which ZeroSettle limits and rules bind the agent?
The connector's send_imessage is the same call as POST /api/imessage/send, so ZeroSettle's new-contact limits, STOP enforcement and consent rules bind the agent and the code it writes. ZeroSettle sets the limits to protect the number's standing with Apple, and they apply to every caller, the console included.
| Limit | Pro | Growth |
|---|---|---|
| New contacts per day (3 AM to 3 AM Eastern) | 5 | 50 |
| New contacts per rolling 15 minutes | — | 3 |
| Unanswered messages to one contact | 2, then 403 awaiting_reply | 2, then 403 awaiting_reply |
| Photos or voice to someone who never replied | Refused (403 attachment_before_reply) | Refused (403 attachment_before_reply) |
- New-contact limits: on
429 new_contact_limit, the code should waitretry_after_s. Anyone who texted the line first, and any ongoing conversation, is never limited. - STOP: a text with the word STOP in it, or a clear request like “take me off your list”, opts the sender out of every number on your account, and texts, voice messages, photos, reactions, typing and name-and-photo shares to them return
403 recipient_opted_out. Code should never retry it; only their START opts them back in (how STOP works on ZeroSettle). - Consent: message only people who gave you their number for this purpose; in the US, TCPA statutory damages run $500 to $1,500 per message. Have the agent call
read_docs("compliance")(and see the TCPA consent guide). This isn't legal advice.
More setup guides are in the ZeroSettle guides hub and plans are under pricing. To start without an agent, get a number in the console and read how to send an iMessage from code without a Mac.
Frequently asked questions
Can a CI job or script use the connector without signing in?
Yes. Mint a static token in the ZeroSettle console (or with create_api_key) and send it as Authorization: Bearer <token> to https://portal.zerosettle.io/mcp; ZeroSettle's docs give that path for the xAI API and headless jobs. Signing in with your phone number is for a person building in Claude Code, Claude, Cursor or grok.com.
What can't the connector do?
It can't pay for you: subscribe returns a Stripe Checkout link that you open in a browser. It also has no tool for tapbacks or for sharing your name and photo on demand; ZeroSettle keeps those on the REST API (POST /api/imessage/reactions and POST /api/imessage/profile/share), for the server you build.
How do I remove a client's access?
Each OAuth client gets its own token, refreshed automatically and revocable from the ZeroSettle console. For static API tokens, minting a new one revokes nothing, and revoking revokes every token on the account.
Does the connector work on a Growth account with several numbers?
Yes. An account with more than one number gets an optional line argument (a line_id or the number) on send_imessage, show_typing, list_conversations, list_messages, set_profile and the three agent tools.
Sources
- ZeroSettle iMessage API docs: "Connect your AI agent", "MCP", "Webhooks, step by step", "AI agent" and "Errors, limits, and compliance". Checked October 12, 2026.
- Authorization, Model Context Protocol specification (2025-06-18). Checked October 8, 2026.
- Transports, Model Context Protocol specification (2025-06-18), section "Streamable HTTP". Checked October 8, 2026.
- Connect Claude Code to tools via MCP, Claude Code docs, Anthropic. Checked October 8, 2026.
- Get started with custom connectors using remote MCP, Claude Help Center, Anthropic. Checked October 8, 2026.
- Model Context Protocol (MCP), Cursor docs. Checked October 8, 2026.
- Remote MCP Tools, xAI docs. Checked October 8, 2026.