Quickstart
You need an Android phone, or a Mac, Windows or Linux computer, and an AI app that can use remote MCP servers, such as Claude. Setup takes a few minutes.
Create an account
Sign up with your email and a password of at least 10 characters. The Free plan covers one device and 50 messages a month, and needs no card.
Pair a device
In the dashboard, open Devices and choose Add a device. You get an 8-character pairing code such as K7Q2-M9XD. It works once and expires after 10 minutes.
Android
Download the signed Pocketwire APK from GitHub Releases and open it to install. Android may first ask you to allow installs from your browser. The app needs Android 8 or newer, and Obtainium can keep it up to date for you.
Open Pocketwire, type the pairing code and a name for the phone, then tap Pair. Leave Server set to
https://pocketwire.appunless you run your own server.Allow what Pocketwire asks for: SMS, to send the texts you approve, and notifications, to ask you about each one. A quiet notification shows that the connection is running.
The phone asks you to approve each text itself. The key it creates while pairing never leaves the phone; Pocketwire only gets the public half.
Mac, for iPhone users
On your iPhone, turn on Text Message Forwarding for your Mac. You’ll find it in Settings under Messages (inside Apps on recent iOS versions). Messages on the Mac must be signed in with the same Apple Account.
-
Download the Bridge for macOS from GitHub Releases:
pocketwire-darwin-arm64for Apple silicon orpocketwire-darwin-amd64for Intel. Rename it topocketwire, then pair it:Terminalchmod +x pocketwire ./pocketwire pair K7Q2-M9XD ./pocketwire runTo keep it running after you close Terminal, and start it when you log in, run
./pocketwire service installinstead ofrun. The first time it sends, macOS asks whether the Bridge may control Messages. Allow it. You can change this later in System Settings, under Privacy & Security, Automation.
You approve these texts in the dashboard under Approvals, because the Bridge has no screen of its own to ask on. To send iMessage instead of SMS, pair with --messages-service imessage.
Windows and Linux
Install KDE Connect on the computer and on your Android phone, and pair the two. In the KDE Connect app on the phone, allow the SMS permission.
-
Download the Bridge for your system from GitHub Releases, for example
pocketwire-linux-amd64orpocketwire-windows-amd64.exe. Rename it topocketwire(pocketwire.exeon Windows), then pair it:Linux terminalchmod +x pocketwire ./pocketwire pair K7Q2-M9XD ./pocketwire runOn Windows, run
.\pocketwire.exe pair K7Q2-M9XDand then.\pocketwire.exe runin PowerShell. To keep the Bridge running in the background and start it when you log in, useservice installinstead ofrun. The Bridge sends through the first phone KDE Connect can reach. To pick another one, list them with
kdeconnect-cli -land pair again with--kdeconnect-device <id>.
You approve these texts in the dashboard under Approvals.
Just trying things out? Pair the Bridge with --driver dry-run. It prints each approved message in the terminal instead of sending it.
Connect your AI app
Add https://pocketwire.app/mcp to your AI app as a remote MCP server. The app opens Pocketwire’s sign-in page: sign in, check what the app asks for, and allow it. Step-by-step guides: Claude, Claude Code, Cursor and others.
Send a first text
Ask in plain words, with the number in international format:
Text +44 7700 900123 that I’m running 10 minutes late, sorry!
Your phone shows Text to +447700900123? with the whole message. Tap Send; on Android 12 and newer the phone asks you to unlock it first. With the Bridge, approve the text under Approvals in the dashboard instead. Either way, the request shows up under Activity.
Pocketwire doesn’t read your contacts. Give your AI app the number, or let it look the number up with another tool you’ve connected.
Desktop Bridge
The Bridge is one small program for macOS, Windows and Linux. It opens a secure connection out to Pocketwire, so it needs no open ports, and sends each approved text through a driver. GitHub Releases has builds for x86-64 and ARM64 on all three systems, with a SHA256SUMS file to check them against. The examples below assume the program is on your PATH as pocketwire.
Commands
| Command | What it does |
|---|---|
pocketwire pair <CODE> | Links this computer to your account, with the options below. |
pocketwire run | Stays connected in the foreground and sends approved texts. Stop it with Ctrl+C. |
pocketwire service install | Keeps the Bridge running in the background and starts it when you log in: a launchd agent on macOS, a systemd user service on Linux, a scheduled task on Windows. service uninstall removes it. |
pocketwire doctor | Shows the pairing and which drivers work on this computer. |
pocketwire test-send <number> <text> | Sends one text straight through the driver after you type yes. It doesn’t go through Pocketwire, so it isn’t logged. Good for checking a driver. |
pocketwire unpair | Forgets the pairing on this computer. Remove the device in the dashboard too. |
pocketwire version | Prints the version. |
Options for pair
| Option | Default | Meaning |
|---|---|---|
--name | The computer’s name | How the device is named in the dashboard. |
--driver | macos-messages on a Mac, kdeconnect elsewhere | How texts are sent. See drivers below. |
--server | https://pocketwire.app | Your own server, if you self-host. The POCKETWIRE_SERVER variable works too. |
--kdeconnect-device | First reachable phone | Which KDE Connect device to send through. |
--messages-service | sms | Use imessage to have Messages send iMessage instead. |
Drivers
| Driver | Runs on | Needs |
|---|---|---|
macos-messages | macOS | Messages signed in. For SMS, an iPhone with Text Message Forwarding turned on for this Mac. Automation permission for Messages, asked for once. |
kdeconnect | Windows, Linux | KDE Connect paired with an Android phone, and the SMS permission allowed in the KDE Connect app on the phone. |
dry-run | All | Nothing. Prints messages instead of sending them. |
Where the pairing is kept
Pairing creates a key pair on your computer, and only the public key is sent to Pocketwire. The private key and settings live in config.json, readable only by you: in ~/Library/Application Support/pocketwire/ on macOS, %AppData%\pocketwire\ on Windows and ~/.config/pocketwire/ on Linux. Set POCKETWIRE_CONFIG to use another path.
Connect to Claude
Pocketwire works in Claude as a custom connector. Custom connectors are available on Claude’s paid plans; on Team and Enterprise, an owner may need to add Pocketwire for the organization first.
In Claude, open Settings, then Connectors, and choose Add custom connector.
-
Name it Pocketwire and paste this server URL:
https://pocketwire.app/mcp Add the connector and choose Connect. Claude opens Pocketwire: sign in, check what Claude asks for, and choose Allow.
In a chat, make sure Pocketwire is switched on in the tools menu, then ask for a text. Claude usually checks with you before it calls
send_sms, and then your phone asks too.
What an app can do
The consent screen names the app, where it will send you back to, and each kind of access it asks for:
| Access | On the consent screen | Used by |
|---|---|---|
devices:read | See your paired devices and whether they are online | list_devices |
sms:send | Send text messages from your phone (subject to your approval settings) | send_sms, get_message_status |
messages:read | See the status and history of messages it sent | get_message_status, list_recent_messages |
Note that list_recent_messages reads your whole activity log, so it also shows texts that other connected apps sent.
Connecting an app never changes your approval settings: with the defaults, every text still waits for your tap on Send. Disconnect an app under Connected apps in the dashboard, and its access ends at once.
Other AI apps
Any app that supports remote MCP servers with OAuth sign-in can use Pocketwire, with the same URL everywhere: https://pocketwire.app/mcp.
Claude Code
claude mcp add --transport http pocketwire https://pocketwire.app/mcp
Then run /mcp in Claude Code and choose Pocketwire to sign in.
Cursor
Add Pocketwire to ~/.cursor/mcp.json, or to .cursor/mcp.json in a project. Cursor asks you to sign in the first time it connects.
{
"mcpServers": {
"pocketwire": {
"url": "https://pocketwire.app/mcp"
}
}
}
ChatGPT, Claude Duet and others
Where your app lets you add a custom connector or a remote MCP server, add the URL above and choose OAuth if it asks how to sign in. In ChatGPT, whether custom connectors are available depends on your plan and workspace settings.
Building your own client
- Transport: Streamable HTTP at
/mcp, stateless, with JSON responses. - Discovery: unauthenticated requests get
401with aWWW-Authenticateheader that points to/.well-known/oauth-protected-resource/mcp. Authorization server metadata is at/.well-known/oauth-authorization-server. - Clients: client ID metadata documents or dynamic client registration. Redirect URIs must be HTTPS, a loopback address on any port, or a private-use scheme.
- Flow: authorization code with PKCE;
S256is required. Theresourceparameter is checked as the token’s audience. - Tokens: access tokens last an hour. Refresh tokens last 30 days and change on every use; reusing an old one revokes the whole grant.
- Scopes:
devices:read,sms:sendandmessages:read, plusoffline_access.
MCP tools
Pocketwire gives your agent four tools and nothing else. Each has a title and MCP annotations; send_sms is marked as destructive, so clients know to check with you before calling it. There’s no tool for texting a list of people, reading your inbox or reading replies.
list_devices
read-onlydevices:readLists your paired phones and Bridges, whether each one is online, and whether it can send SMS.
No parameters. Returns devices, each with device_id, name, kind, platform, online, can_send_sms and last_seen_at.
send_sms
sends a textsms:sendSends a text from your own number through a paired device. Depending on your settings, it first waits for your approval on the phone or in the dashboard.
tostring · requiredRecipient in E.164 format, such as
+48501234567. Spaces, dots, dashes and brackets are removed, and a leading00becomes+.bodystring · requiredThe exact text, 1 to 1,600 characters. Longer texts go out as several SMS parts.
device_idstring · optionalWhich device to send from, from
list_devices. By default, the first online device.
The call waits up to 25 seconds for the message to be sent, rejected or expired, then returns the message as it stands, with its message_id. If you haven’t tapped Send by then, the status is awaiting_approval or queued, and the agent can check again with get_message_status.
get_message_status
read-onlymessages:read or sms:sendReturns the current state of a message that send_sms created.
message_idstring · requiredThe
message_idthatsend_smsreturned, such asmsg_Qm3v7KxR2pTnF8wd.
list_recent_messages
read-onlymessages:readLists recent messages from your activity log, newest first, with recipient, status and time, including texts other connected apps sent. The text itself is included only if you turned on message history.
limitinteger · optionalHow many messages, from 1 to 50. Default 10.
What a message looks like
{
"message_id": "msg_Qm3v7KxR2pTnF8wd",
"device_id": "dev_8bQe1sKfP0xYtL2m",
"to": "+48501234567",
"status": "sent",
"error": null,
"approval": "device",
"client_name": "Claude",
"body_length": 59,
"segments": 1,
"created_at": "2026-10-29T13:01:48.000Z",
"updated_at": "2026-10-29T13:02:03.000Z"
}
approval says where the message was approved: device (on the phone), dashboard or none (trusted contact, or a setting that didn’t ask). Times are in UTC.
Statuses
| Status | Meaning |
|---|---|
queued | Accepted, waiting for your device to pick it up. |
awaiting_approval | Waiting for your tap on Send, on the phone or in the dashboard. |
sending | Approved. The device is sending it. |
sent | The device handed it to the mobile network, or to Messages on a Mac. |
delivered | The network confirmed delivery. Android only, where your carrier sends delivery reports. |
failed | It couldn’t be sent. error says why, for example no_service or radio_off on Android. |
rejected | You tapped Reject. Nothing was sent. |
expired | Nobody approved it within 10 minutes (approval_timeout), or the device stayed unreachable (device_unreachable). |
Errors
When a request can’t go ahead, the tool returns an error with a plain message the agent can pass on. Numbers in the messages depend on your plan.
| When | The agent is told |
|---|---|
| No device is paired | No device is paired yet. Pair a phone or the desktop Bridge at /app/devices. |
device_id isn’t yours | No such device on this account. |
| The number isn’t valid | Phone number must be in international E.164 format, e.g. +48501234567. |
| The text is empty or too long | Message must be 1–1600 characters. |
| Too many at once | Too many messages this minute (limit 5). Try again shortly. Or: Daily limit of 20 messages reached. |
| The month’s quota is used up | Monthly quota of 50 messages reached on the Free plan. |
| Too many new numbers today | You can text at most 5 new numbers per day on the Free plan. |
| Sending is paused | Sending is paused for this account. Resume it in the Pocketwire dashboard. |
| The app wasn’t given that access | This connection was not granted “sms:send”. Reconnect Pocketwire and allow it. |
Unknown message_id | No such message on this account. |
Approvals and limits
Pocketwire assumes your agent can get things wrong, or be tricked by something it read. Approvals keep you in the loop, and limits cap the damage if something slips through.
When Pocketwire asks
Choose this under Settings in the dashboard.
| Setting | Plans | What happens |
|---|---|---|
| Every message | All plans; the only one on Free | Every text waits for your tap on Send. This is the default and what we recommend. |
| Only the first message to a new number | Pro, Team | Pocketwire asks the first time your agent texts a number. Once a text to it has gone out, later ones go without asking. |
Android phones ask with a notification that shows the number and the whole text, with Reject and Send. On Android 12 and newer, Send asks you to unlock the phone first. Tap the notification to see the request in full before you decide. Bridge devices are approved in the dashboard under Approvals, which refreshes itself every 10 seconds. A request nobody answers expires after 10 minutes, and nothing is sent.
Trusted contacts
On Pro and Team, add numbers under Settings, Trusted contacts, with a name if you like. Texts to those numbers go out without asking. Every other number still follows your approval setting.
Limits
Limits apply to every request, whoever approves it. Requests you rejected and requests that expired don’t count.
| Free | Pro | Team | |
|---|---|---|---|
| Devices | 1 | 3 | 10 |
| Messages a month | 50 | 2,000 | 10,000 |
| Messages a day | 20 | 300 | 2,000 |
| Messages a minute | 5 | 20 | 60 |
| New numbers a day | 5 | 50 | 200 |
| Activity log kept for | 7 days | 1 year | 1 year |
| Trusted contacts | No | Yes | Yes |
A day is any 24 hours, and a month is the calendar month in UTC. A new number is one your account has never texted before. Numbers shorter than 7 digits, such as short codes, are refused.
Kill switch
Pause all sending in the dashboard’s Settings stops everything at once: while it’s on, every request is refused and the agent is told that sending is paused. The Android app has its own Pause sending switch, which refuses every request on that phone, whatever the dashboard says.
Security and privacy
- Outbound only. Phones and Bridges connect out to Pocketwire over TLS. Nothing listens for connections on your devices.
- Keys stay on the device. Pairing creates a key pair on the phone or computer. Only the public key is sent, and the device proves itself with the private one.
- Message text isn’t kept. The text is stored encrypted only until the message is sent, rejected, failed or expired, then deleted, unless you turn on message history. The log keeps the recipient, the length, a SHA-256 fingerprint of the text, the status and the times.
- Encrypted at rest. Recipients, and the text while it waits, are encrypted with AES-256-GCM. The key lives in the server’s environment, never in the database.
- Hashed secrets. Access tokens, refresh tokens and pairing codes are stored only as SHA-256 hashes, and passwords with scrypt.
- Checked twice. The phone and the Bridge check every request again before sending: a valid number, 1 to 1,600 characters, not expired, not a repeat.
- Hosted in the EU. Our servers and backups are with Hetzner, in the European Union.
Not end-to-end encrypted. Your AI app sends each message to Pocketwire in an ordinary MCP tool call, so our server sees the text while it passes it on to your phone. If no third party may see your messages, host Pocketwire yourself.
Reporting a vulnerability
Email security@pocketwire.app, in English or Polish. Please give us a reasonable time to fix a problem before you make it public. Details of how we handle personal data are in the privacy policy.
Self-hosting
Run Pocketwire Cloud on your own server and no message passes through us. The repository’s infra folder has a production setup for one Linux server with Docker: Pocketwire itself, Caddy for automatic HTTPS, and Litestream for continuous backups of the SQLite database.
Point your domain at the server with
AandAAAArecords, for the domain and forwww.-
In a copy of the repository on the server, create the settings file and two secrets:
Servercd pocketwire/infra cp .env.example .env openssl rand -base64 32 # paste as ENCRYPTION_KEY openssl rand -base64 32 # paste as HMAC_SECRETSet
DOMAIN,ENCRYPTION_KEYandHMAC_SECRETin.env. TheLITESTREAM_*values send backups to any S3-compatible bucket. If you don’t want off-site backups, remove thelitestreamservice fromdocker-compose.yml. -
Start it:
Serverdocker compose up -d --buildCaddy gets a certificate on the first request.
https://your-domain/healthzshould answer{"ok":true}. Use your server everywhere: on Android, type your address in the Server field when pairing; pair the Bridge with
--server https://your-domain; connect AI apps tohttps://your-domain/mcp.
Keep .env somewhere safe, such as a password manager. If ENCRYPTION_KEY is lost, stored recipients can’t be read any more.
To update, pull the newer code and run docker compose up -d --build again. For help with a larger setup, talk to us.
Try it on your computer
cd server && npm install && npm run dev # http://localhost:8080
Sign up at http://localhost:8080/app/signup, pair the Bridge with --server http://localhost:8080 --driver dry-run, and point an MCP client at http://localhost:8080/mcp. Claude on the web needs a public HTTPS address, for example through a tunnel.
Troubleshooting
My agent says no device is paired, or the device is offline
Check Devices in the dashboard. If the device shows as offline, open the Android app, or start the Bridge with pocketwire run (or pocketwire service install to keep it running), and check that it has a connection.
The approval notification doesn’t show up
Make sure Pocketwire may show notifications and that its Approvals channel isn’t turned off in Android’s settings. If Android paused the background connection, Pocketwire shows a notification asking you to reconnect: tap it. On some phones it helps to exclude Pocketwire from battery optimization.
The message expired
Requests expire after 10 minutes if nobody approves them, or if the device stays unreachable. Ask your agent to send it again.
“Phone number must be in international E.164 format”
Use a plus sign and the country code, such as +48501234567 or +44 7700 900123. Numbers shorter than 7 digits, like short codes, aren’t accepted.
A limit was reached
You hit a per-minute, daily, monthly or new-number limit. The limits table shows them for each plan; the per-minute and daily ones free up on their own.
Messages on the Mac doesn’t send
Run pocketwire doctor. Check that Messages is signed in, that Text Message Forwarding is on for this Mac on your iPhone, and that the Bridge may control Messages in System Settings, under Privacy & Security, Automation. When the Bridge runs as a service, its log is in ~/Library/Logs/pocketwire-bridge.log.
KDE Connect doesn’t send
Run kdeconnect-cli -l to check that the phone is paired and reachable, and that the KDE Connect app on the phone has the SMS permission. Then send yourself a test with pocketwire test-send and your own number.
Claude can’t connect, or a tool says access wasn’t granted
Check that the URL is exactly https://pocketwire.app/mcp. If you chose Deny by mistake, or a tool says the connection wasn’t granted some access, remove the connector, add it again and allow it.
Still stuck?
Write to support@pocketwire.app with the time and, if you have it, the message ID (msg_…). Never send us your password.