sv-number/mcp-server: phone numbers as MCP tools for SMS verification
MCP server for AI agents that need a phone number: order a private number in 200+ countries, read the SMS verification code, hand it back. The widest country coverage in the category, and you can check it with one API call.
At a glance
- What is it?
- A nine-tool MCP server that lets an agent rent a number, read the verification code and release it. It is a thin wrapper over a commercial API, and the whole value depends on coverage and delivery rates you should check before paying.
- Who is it for?
- Adopt this if your agent needs a one-shot SMS code for a signup flow and you accept that the number is rented from a commercial service with no free tier. Do not adopt it for sending SMS, voice, banking, payment or government accounts, and do not treat it as a permanent number.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 36 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem it solves: an agent that cannot receive an SMS
An agent can fill in a signup form, but the form then sends a code to a phone number and the agent stops. The sv-number MCP server closes that gap. It exposes phone numbers as MCP tools over stdio, so a client that speaks the Model Context Protocol can order a private number in the country a service expects, poll for the SMS, read the code out of the message body, and close the activation. The README frames it as "phone numbers as tools" and the whole job is receiving verification codes. It is aimed at agent builders working inside Claude Code, Cursor, Cline, Windsurf, Codex or Claude Desktop, since those are the clients named in the install instructions. If you are building a signup or onboarding flow that an agent drives end to end, this is the missing step. If you need to send messages or hold a voice call, it is the wrong product entirely.
Nine tools and the shape of an activation
The tool surface is deliberately small. get_balance reports what is left on the account. list_countries returns every country with its id and operators. list_services finds the code for a site by name or domain. order_number rents a number for one service in one country. wait_for_code polls until the code lands and returns it already parsed out of the SMS. finish_activation closes a successful activation, cancel_activation cancels and refunds, request_another_sms asks for one more code on the same number, and totp_code computes an authenticator code locally by RFC 6238. The README gives the happy path in three lines: order_number with a service and country, wait_for_code with the activation id, then finish_activation. Two details in that flow matter more than the list. First, service codes are arbitrary and the README is explicit that they must never be recalled from memory: uk is Airbnb, re is Coinbase, tn is LinkedIn. Second, list_services returns matches ranked best first plus a notInList fallback, and ranks a whole word above a substring, so x puts X.com (Twitter) above Maxim. That ranking choice is a small thing that saves a class of wrong-service orders.
How the server behaves between your agent and the API
The server is a wrapper, and most of its engineering sits in the gap between a raw HTTP API and an agent that has to act on the answer. Every call carries lang. According to the README, the API answers without it but then prices in another currency, so the server never leaves it out. Text markers that the API returns instead of JSON are checked before anything is parsed and rewritten into a sentence an agent can act on: NO_NUMBERS becomes "change country, or set operator to any" rather than a bare token. Polling runs at a fixed interval instead of hammering getStatus, and wait_for_code stops at the 20 minute life of a number. That last bound is the one to design around. Your agent must handle the timeout as a normal outcome, not an exception, and decide between cancel_activation and request_another_sms. The API key is read from the environment, no tool returns it, and no error message quotes it, which is the right default for a process that an agent can call repeatedly.
Install and configuration
For Claude Code the README gives a single command: claude mcp add sv-number --env SVN_API_KEY=your_key_here -- npx -y sv-number-mcp. For anything that reads a JSON config, the README shows the mcpServers block with command npx, args ["-y", "sv-number-mcp"], and an env object holding SVN_API_KEY. The key comes from the user profile page after signup, and the balance has to be funded because there is no free tier on this API. Four environment variables are documented: SVN_API_KEY is required, SVN_API_BASE defaults to https://sms-verification-number.com/stubs/handler_api, SVN_LANG defaults to en and sets both the language and the currency of the answers, and SVN_POLL_SECONDS defaults to 4. The poll interval is the one knob worth thinking about. Lowering it makes wait_for_code return sooner and increases the request rate against a paid API; the default of four seconds is a starting point, not a requirement. There are no releases retrieved for this repository, so pinning a version is not something the material supports.
The delivery-rate field is the honest part of the design
list_services returns deliveredPercent, the delivery rate for that service and country pair, and null when the pair has no statistics yet. The README says null is the common case. That admission is more useful than a marketing number would be, because it tells you what the tool can and cannot rank on. Where a figure exists, the README advises picking by it instead of by price. Where it does not, online shows the size of the live pool, described as the next best signal. The practical consequence is that for most country and service combinations your agent is choosing blind, and the only feedback loop is whether a code actually arrives. If you are building anything that needs a predictable success rate rather than a best-effort one, this is the part to test first, with your own target services, before you commit to a funded balance.
What it will not do, and where it fails
The README states the boundary plainly: receiving verification codes is the whole job. These numbers do not send SMS, do not take calls, and are not meant for banking, payment or government accounts. An agent that needs a permanent number to hold a conversation wants a carrier product instead. There is also a catalogue limitation that will bite in practice. The service list is not the same in every country, so a match in one country may not exist in another, and when nothing matches the answer says so and points elsewhere. The ot code ("Not on list") receives SMS from any sender that is not in the list, but the README is careful to call it a fallback and not a wildcard, because a site that has its own code sends to that code. Two failure modes follow. A wrong country produces a NO_NUMBERS marker, which the server rewrites into advice rather than a hard error, so an agent that ignores the sentence will loop. And a number whose 20 minute life expires mid-flow leaves an activation that must be cancelled or replaced. Neither is a bug, but both require the calling agent to have a policy.
How this differs from Twilio or a carrier API
The obvious alternative is a programmable telecoms provider such as Twilio, or a carrier number you own outright. The difference is in what you are buying. A carrier product gives you a number you keep, with inbound voice and outbound SMS, and you are responsible for compliance, registration and per-message cost. This server gives you a short-lived number rented per activation, chosen from a catalogue, priced per order, and returned when you finish. You do not manage a number pool or a messaging pipeline, and you cannot send anything. The trade is control for convenience: a carrier API lets you decide which number a service sees and lets you reuse it, while this one hands you whatever the pool has in that country. For a one-shot verification in an automated signup, the rented model is the smaller integration. For anything that needs a stable identity or two-way messaging, it is not a substitute. There is also a sibling project listed under Related: the same product packaged as a markdown skill at github.com/sv-number/skills, which is worth knowing about if your client does not speak MCP.
Cost, maintenance and licence
The repository is MIT, and the README says so in one line, but adds that the service behind it is commercial. That split is the thing to keep straight: the wrapper code is permissively licensed and you can read, fork or vendor it, while every order_number call spends money on an account you have to fund. There is no free tier. On maintenance, the material is thin. No releases were retrieved, so there is no version history to reason about, and the last push recorded is 2026-08-10. The code is JavaScript, the repository lists TypeScript among its topics, and the install path is npx -y sv-number-mcp, which means you are running whatever the registry serves at that moment unless you pin it yourself. The API base is overridable through SVN_API_BASE, which is the escape hatch if you need to point at a different endpoint, and also the reason to keep that variable under your own control rather than inheriting it from a shared environment. Nothing here suggests a migration burden; the risk is on the service side, not the client side.
Editorial conclusion
Adopt this if your agent needs a one-shot SMS code for a signup flow and you accept that the number is rented from a commercial service with no free tier. Do not adopt it for sending SMS, voice, banking, payment or government accounts, and do not treat it as a permanent number. Before funding a balance, verify two things yourself: run list_countries and count the rows for the countries you actually need, and run list_services for your target site to see whether deliveredPercent is null or has a real figure.
Community notes