Imported from akillness/jeo-skills (
.agent-skills/mcp-server-sv-number/SKILL.md). Install upstream withnpx skills add akillness/jeo-skills --skill mcp-server-sv-number. Copyright stays with the author.
SV Number MCP Server
SV Number is a stdio MCP server that turns phone numbers into tools: an agent orders a private number in the country a service expects, reads the SMS verification code straight from the API, and hands the number back. Nine tools, no SDK to learn, 200+ countries of coverage. It is not a messaging or calling product — receiving one verification code per activation is the whole job.
When to use this skill
- A signup or account-creation flow demands a real phone number to receive an SMS/OTP code
- Picking the right country id and service code before ordering a number
(
list_countries,list_services) - Ordering a number, waiting for the code, and closing out the activation
(
order_number,wait_for_code,finish_activation,cancel_activation) - Requesting a second SMS on the same number for a resend/password reset
(
request_another_sms) - Checking remaining account balance before ordering (
get_balance) - Computing a TOTP/2FA code locally from an already-known Base32 secret (
totp_code) - Wiring this MCP server into Claude Code, Claude Desktop, Codex, or Cursor
When not to use this skill
- The user needs a persistent number for real conversations, calls, banking, payment, or government accounts — these numbers are exclusive to one activation and expire in 20 minutes; point them at a carrier product instead
- No
SVN_API_KEYis configured and funding one is out of scope for the task — say so rather than guessing a key - The task is about sending or receiving arbitrary SMS/voice traffic, not a one-time verification code — out of scope for this server
- A general MCP client setup question unrelated to SV Number specifically → use a generic MCP-configuration skill instead
Instructions
Step 1: Confirm the environment before ordering anything
node --version # needs >=18
echo "${SVN_API_KEY:+set}"
SVN_API_KEY comes from the user's profile page
after signup, and the balance must be
funded — there is no free tier. Never print or echo the key itself; the server reads it from
the environment and no tool or error message ever returns it.
Step 2: Register the server with the MCP client
Claude Code:
claude mcp add sv-number --env SVN_API_KEY=your_key_here -- npx -y sv-number-mcp
Any JSON-config client (Codex, Cursor, Claude Desktop) — see references/setup.md for the full snippet and env var table.
Step 3: Check balance, then find the country and service
get_balance() -> current funded balance
list_countries(search?) -> id + operators per country
list_services(country, search?) -> matches ranked best-first, notInList fallback
Service codes are arbitrary strings, never guess them from memory — uk is Airbnb, re is
Coinbase, tn is LinkedIn. Always resolve the code via list_services first. When
deliveredPercent is non-null, prefer the pair with the higher rate; when it is null
(the common case), prefer the pair with more numbers online. If nothing in the catalogue
matches the target site, order the ot ("Not on list") fallback service, not a guessed code.
Step 4: Order the number and wait for the code
order_number(service, country, operator?, maxPrice?) -> { activationId, phone }
wait_for_code(activationId, timeoutSeconds?) -> { code } (polls internally, up to 20 min)
Trigger the target service's "send code" action only after order_number returns the phone
number — wait_for_code polls getStatus on a sane interval and stops at the number's
20-minute lifetime on its own; do not build a manual polling loop around it.
Step 5: Close out the activation
finish_activation(activationId) -> after the code was used successfully
cancel_activation(activationId) -> no code arrived; money returns to balance
request_another_sms(activationId) -> ask for a resend, only after a first code arrived
Always call finish_activation on success or cancel_activation on failure — a forgotten
activation holds money until it naturally expires after 20 minutes.
Step 6: Compute a TOTP code when the account already has 2FA configured
totp_code(secret, digits?, period?, algorithm?) -> RFC 6238 code, computed locally
This tool never calls the network; the shared secret stays on the local machine. Use it only
when the user already has a Base32 secret from an authenticator setup, not as a substitute
for order_number/wait_for_code.
Best practices
- Resolve service codes through
list_services, never from memory — the two-letter codes are arbitrary and easy to confuse (ukis not the United Kingdom). - Pick by
deliveredPercentwhen it exists, byonlinecount when it does not — anulldeliverability is the common case, not a red flag. - Always close the loop —
finish_activationon success,cancel_activationon failure, so money is not tied up until the 20-minute expiry. - Treat the API key as write-only — read it from the environment, never log it, never echo it back to the user, and never fund/rotate it without explicit confirmation.
- Do not build a manual polling loop —
wait_for_codealready polls at a sane interval and respects the 20-minute activation life; wrapping it in another retry loop just wastes calls. - These are single-activation numbers, not persistent lines — route requests for a real, ongoing phone number to a carrier product instead of trying to reuse an activation.
References
- references/setup.md — install methods, env var table, MCP client registration snippets for Claude Code / Codex / Cursor / Claude Desktop
- SV Number MCP server GitHub repo
- Same product as a markdown skill
- API reference
- Coverage and prices
- Project standards:
.agent-skills/skill-standardization/SKILL.md
Examples
Example 1: Verify a Telegram signup with an Indonesian number
list_services(country=6, search="telegram") -> service="tg", price, online, deliveredPercent
order_number(service="tg", country=6) -> { activationId, phone: "62 838 1234 5678" }
# trigger Telegram's "send code" with the phone number (add leading + for E.164)
wait_for_code(activationId) -> { code: "123456" }
finish_activation(activationId)
Example 2: No code arrives, so cancel and get the money back
order_number(service="ds", country=0) -> { activationId, phone }
wait_for_code(activationId, timeoutSeconds=120) -> { code: null, state: "timeout", next: "..." }
cancel_activation(activationId) -> { state: "cancelled", money: "returned to the balance" }