verifywith

SMS MCP server for verification codes

The VerifyWith MCP server lets an AI client buy a private US phone number, wait for a text and read the verification code, inside spending limits the account owner sets. The endpoint is https://api.verifywith.io/mcp, over Streamable HTTP. There are two ways in: browser sign-in, which Claude, ChatGPT and Cursor start when you add the address, or an API key sent as a bearer token. Numbers receive texts only, from $3.99 a day.

Checked by VerifyWith on

A server box cabled to a message card

The tools

The server has nine tools. Each one needs a level, and the levels include each other: a connection that can get numbers can also read and manage them.

ToolWhat it doesLevel it needs
list_pricesThe four durations and prices, this connection’s level and spending limits. Buys nothing.Any
buy_numberBuys a number. Arguments: duration, auto_renew, nickname, buy_another.Get and extend numbers
wait_for_codeWaits for the next text on a number and returns it with the code. timeout_seconds 5 to 55, default 45.Read
list_numbersThe person’s numbers, newest first, with the latest code.Read
get_number_detailsOne number: status, end date, texts received, and whether it can be cancelled.Read
read_messagesThe texts on a number, newest first, with the code found in each.Read
extend_numberAdds time, charged to the saved card at once.Get and extend numbers
set_auto_renewTurns automatic renewal on or off.Manage
cancel_numberCancels a number with no texts, within 24 hours, money back when our provider accepts.Manage

There is no tool for choosing an area code or a specific number: buy_number assigns one.

How each client connects

Every client uses the same address, https://api.verifywith.io/mcp. The server name in the examples is verifywith. Click-by-click steps for Claude, Claude Code and Cursor are in give Claude a phone number.

ClientWhere you add itHow it signs in
Claude (web and desktop)Customize, Connectors, Add custom connectorBrowser sign-in
ChatGPTPlugins, Add custom MCP server, with OAuthBrowser sign-in
Claude Codeclaude mcp add --transport http verifywith https://api.verifywith.io/mcp/mcp or claude mcp login verifywith, or an API key header
Cursor~/.cursor/mcp.json or .cursor/mcp.jsonBrowser sign-in from Cursor’s MCP settings
Your own codeAny MCP client over Streamable HTTPAPI key, or the SDK’s OAuth support

Browser sign-in or an API key

Browser sign-in is OAuth 2.1, and it is what an AI app does on its own when you add the address. An unauthenticated request gets a 401 that points at the server’s metadata; the app opens VerifyWith, the owner signs in (email code, passkey, Google or Apple) and lands on a consent page that names the app and its domain. There the owner picks the level and the spending limits and presses Allow. The approval then appears on the Developers page beside any API keys, where it can be changed or disconnected.

Under the hood the server supports PKCE (S256 only), Client ID Metadata Documents and dynamic client registration, and every client is a public client. Access tokens last 30 minutes and are bound to the /mcp address; refresh tokens rotate on every use. The server re-reads the approval on every request, so disconnecting stops the app at once.

An API key is for your own code, or any client that can’t sign in. Create one on the Developers page and send it as Authorization: Bearer sk_…. The same key works on the REST API at https://api.verifywith.io/v1. With the official TypeScript SDK:

import { Client, StreamableHTTPClientTransport } from "@modelcontextprotocol/client";

const client = new Client({ name: "my-agent", version: "1.0.0" });
await client.connect(
  new StreamableHTTPClientTransport(new URL("https://api.verifywith.io/mcp"), {
    requestInit: { headers: { Authorization: `Bearer ${process.env.VERIFYWITH_API_KEY}` } },
  }),
);

const bought = await client.callTool({
  name: "buy_number",
  arguments: { duration: "day", nickname: "Acme sign-up" },
});
// Type number.type_into_forms into the site, ask it to send the code, then:
const text = await client.callTool({
  name: "wait_for_code",
  arguments: { number_id: bought.structuredContent.number.number_id },
});
A control panel with three sliders at different heights
Access levels and spending limits decide what a connected agent may do.

Access levels and spending limits

The owner gives each connection or key one of three levels. Only the top level can spend money, and it always comes with two limits the owner sets.

LevelWhat it allowsCan spend
Read (“See your numbers and texts”)List numbers, read texts and codes, wait for a codeNo
Manage (“See and manage them”)Also cancel numbers and switch auto-renewNo
Get and extend numbers (“Full access” for a key)Also buy numbers and add timeYes, within the two limits

The two limits are the most the connection may spend on one number (extensions included) and the most in any 24 hours. A purchase over either is refused with over_spending_limit, naming the limit and its amount, and nothing is charged. Renewals the owner turns on do not count toward them.

What an agent can never do

  • Send a text or make a call. The numbers receive texts only. A site that offers to call with the code can’t reach them.
  • Spend past the limits, or do more than the level the owner chose. A call outside the level answers not_allowed and says which level it needs.
  • Skip the owner’s bank. When the bank wants the card holder to confirm a payment, the agent gets needs_bank_confirmation and a link for the owner, valid about an hour. The purchase waits until the owner confirms.
  • Touch the account itself. Cards, keys, passkeys and account settings are managed only by the signed-in owner. With no saved card the agent gets needs_card and a link for the owner.
  • See card details or payment ids. Results carry VerifyWith’s own ids only.

Our acceptable use policy applies to agents too: an agent verifies accounts that belong to its owner, not accounts in bulk or for other people.

How the tools behave

  • Buying is safe to retry without an idempotency key. Repeating a buy_number call with the same arguments within 10 minutes returns the same purchase with already_bought: true and charges nothing new. After the owner confirms with their bank, the same call completes the purchase. To buy a second identical number on purpose, pass buy_another: true. extend_number works the same way with extend_again.
  • wait_for_code blocks for at most 55 seconds, because most clients cut a tool call off at about a minute. It returns a text that arrived up to 15 minutes before the call if this tool hasn’t returned it yet. On timeout it answers no_text_yet; texts are stored as they arrive, so calling again misses nothing. It sends progress notifications every 10 seconds when the client asks for them.
  • Every result says what to do next. Each carries an outcome, a sentence, the facts and a next_step, repeated as text for clients that pass only text to the model. Results where nothing was done are errors; results waiting for the owner are not, and carry a link.
  • Rate limits. Purchases are capped at 20 an hour per key or connection and 30 per person, shared with the REST API. At most 5 waits can be open at once per connection.

The numbers and what they cost

Each number is a non-VoIP US (+1) number that receives texts from any sender for as long as it is rented. Line type matters because many services look a number up and refuse VoIP numbers (see why apps reject VoIP numbers). Services also refuse numbers for other reasons, so no particular service is promised. If no text comes after a resend, the tools tell the agent to stop and tell the owner.

Numbers are rented for 1 day $3.99, 1 week $7.99, 1 month $12.99, 1 year $34.99, the same prices as on the website. The MCP server itself costs nothing, and list_prices is free to call. The price is held on the owner’s saved card and taken when the first text arrives or after 24 hours. A number that has received no texts can be cancelled from 5 minutes to 24 hours after purchase; the money comes back when our provider accepts the cancellation (see the refund policy).

For a one-time sign-up code a day is enough. A longer rental suits an account that will text the number again at login.

Questions people ask

Is there an MCP server that can receive SMS verification codes?
Yes. VerifyWith runs one at https://api.verifywith.io/mcp. An AI client connected to it can buy a private US number, wait for the text and read the code, charged to the owner’s card within limits the owner sets.
Does the MCP server need to be installed or run locally?
No. It is a remote server over Streamable HTTP, so a client connects to its address. There is nothing to install or keep running on your machine.
Which MCP protocol versions does it support?
Both eras from one endpoint: 2026-07-28 clients, which send one stateless request at a time, and 2025-era clients that start with initialize.
Can the agent choose the area code?
No. buy_number assigns a US number; there is no choice of area code or of a specific number.
What happens if the agent calls buy_number twice by mistake?
A second call with the same arguments within 10 minutes returns the number the first one bought and charges nothing. Only buy_another: true buys an additional number.