SMS.ir MCP server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@SMS.ir MCP serverWhat's my current SMS credit?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
SMS.ir MCP server
A local Model Context Protocol server that exposes a curated, safety-gated set of tools for the SMS.ir Panel V2 API. Built with Python + FastMCP.
stdio transport for Codex / Claude Desktop / Claude Code
streamable HTTP transport for local development and testing
Read operations work out of the box; every send is billable and blocked by default behind a confirmation flag and a server-side kill switch.
Phone numbers, message text, API keys and OTP codes are masked in logs.
Built from the SMS.ir Panel V2 Postman collection (not included in this repo —
it embeds a real API key). The normalized API description lives in
docs/API.md and docs/openapi.yaml.
1. Setup
Requires Python 3.10+ (developed and tested on CPython 3.12).
cd C:\Users\Kasra\Documents\sms.ir-mcp
# create the project-local virtual environment
py -3.12 -m venv .venv
# install runtime deps (pinned)
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
# ...or install with the package + dev/test extras
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"Related MCP server: instantly-mcp
2. Configuration
All configuration comes from environment variables. For local use, copy the example env file and fill it in — it is git-ignored and never committed:
copy .env.example .env
notepad .envVariable | Required | Default | Purpose |
| yes | – | SMS.ir Panel API key, sent as the |
| no | – | Fallback sender line for send tools |
| no |
| Kill switch. Must be |
| no |
| API base URL (host-allowlisted) |
| no |
| Allow a non- |
| no |
| Per-request timeout |
| no |
| Retries for transient failures (429 / 5xx / network) |
| no |
| Client-side rate limit |
| no |
| Upper bound accepted for |
| no |
|
|
| no |
| Path to the env file to auto-load |
Real environment variables always override values from the env file.
3. Running
# stdio (what MCP clients launch)
.\.venv\Scripts\python.exe -m sms_ir_mcp --transport stdio
# streamable HTTP for local testing (http://127.0.0.1:8000/mcp)
.\.venv\Scripts\python.exe -m sms_ir_mcp --transport http --host 127.0.0.1 --port 8000For a quick connectivity + auth check that never spends credit, call the
health_check tool (or get_balance) from any connected client — both are
GET /v1/credit under the hood.
4. Tools
Read-only tools are always available. Write tools require confirm=true
and SMSIR_ALLOW_SEND=true; the destructive tool requires confirm=true.
Tool | Kind | API | Description |
| read |
| Remaining SMS credit |
| read |
| Sender line numbers / virtual numbers |
| read |
| Delivery report/status for one sent message |
| read |
| Per-recipient results for a bulk pack (paginated) |
| read |
| Sent messages, |
| read |
| Bulk packs, |
| read |
| Inbound messages, |
| read |
| Newest inbound message containing a parseable one-time code (heuristic) |
| read |
| Reachability + auth check, never billable; also returns effective config |
| admin | – | Re-read |
| billable |
| One text to one or more recipients |
| billable |
| Templated OTP/verification message |
| billable |
| A distinct text per recipient |
| destructive |
| Cancel a not-yet-sent scheduled pack |
Every tool returns {"ok": true, "data": …, …} on success or
{"ok": false, "error": {"code": …, "message": …}} on failure. Error codes:
config_error, validation_error, confirmation_required, send_disabled,
auth_error, rate_limited, transient_error, api_error, internal_error.
Examples
// check balance
get_balance() -> {"ok": true, "data": {"credit": 45210}}
// read the latest OTP received on a given number
extract_latest_otp({"mobile": "9821000"})
-> {"ok": true, "data": {"otp": "834122", "matched": true, "from": "*****1000", ...}}
// attempt a send without confirming -> refused, nothing sent
send_sms({"message_text": "Hi", "mobiles": ["09121234567"]})
-> {"ok": false, "error": {"code": "confirmation_required", ...}}
// confirmed send, but kill switch still off -> refused, nothing sent
send_sms({"message_text": "Hi", "mobiles": ["09121234567"], "confirm": true})
-> {"ok": false, "error": {"code": "send_disabled", ...}}
// edited .env to set SMSIR_ALLOW_SEND=true -> apply it without restarting
reload_config()
-> {"ok": true, "data": {"config": {"allow_send": true, ...}, "changed": ["allow_send"]}}
// with SMSIR_ALLOW_SEND=true AND confirm=true -> actually sends (billable)
send_sms({"message_text": "Hi", "mobiles": ["09121234567"],
"line_number": "30007732000000", "confirm": true})
-> {"ok": true, "data": {"packId": "…", "messageIds": [123], "cost": 1.0}, "recipients": 1}5. Safety model
Billable operations (
send_sms,send_verification_code,send_personalized_sms) need both:confirm=truein the tool call, andSMSIR_ALLOW_SEND=truein the server environment. With the kill switch off, a confirmed call still sends nothing.
Destructive operation (
cancel_scheduled_send) needsconfirm=true.No arbitrary base URLs: only
api.sms.iris accepted unlessSMSIR_ALLOW_CUSTOM_BASE_URL=true. HTTPS is enforced.No header injection: callers cannot set request headers; only typed, validated fields are forwarded.
Timeouts + bounded retries + client-side rate limiting on every request.
Masking: API keys, phone numbers, message bodies and OTP values are masked in log output.
No admin endpoints: only the operations in the Postman collection are exposed; nothing for account/config management.
6. Client registration
Your real API key goes in .env in this folder — never in a client config
file. Each config below only points the client at this server and its .env.
Codex CLI (installed)
codex mcp add sms-ir `
--env SMSIR_ENV_FILE=C:\Users\Kasra\Documents\sms.ir-mcp\.env `
-- C:\Users\Kasra\Documents\sms.ir-mcp\.venv\Scripts\python.exe -m sms_ir_mcp --transport stdio
codex mcp list # sms-ir should appear
codex mcp get sms-irManual equivalent: docs/codex_config.example.toml.
Claude Code (installed)
This repo ships a project-scoped .mcp.json. Open Claude Code in
this directory and approve the sms-ir server when prompted:
cd C:\Users\Kasra\Documents\sms.ir-mcp
claude
/mcp # shows sms-ir and its toolsTo register it at user scope instead:
claude mcp add sms-ir --scope user `
--env SMSIR_ENV_FILE=C:\Users\Kasra\Documents\sms.ir-mcp\.env `
-- C:\Users\Kasra\Documents\sms.ir-mcp\.venv\Scripts\python.exe -m sms_ir_mcp --transport stdioClaude Desktop (not installed)
When installed, merge docs/claude_desktop_config.example.json
into %APPDATA%\Claude\claude_desktop_config.json (back it up first; keep other
servers).
7. Development
.\.venv\Scripts\python.exe -m ruff check src tests
.\.venv\Scripts\python.exe -m ruff format --check src tests
.\.venv\Scripts\python.exe -m pytestTests cover request construction, auth header, envelope parsing, error normalization, retries/rate-limiting, argument validation, masking, OTP extraction, mocked integration for every tool (using the Postman example payloads), OpenAPI-vs-collection consistency, and MCP tool discovery.
8. First live test (after you provide a credential)
Nothing in this repo has made a billable call. To run the first real send, which you explicitly authorize:
Put your key in
.env:SMSIR_API_KEY=<your real key> SMSIR_DEFAULT_LINE_NUMBER=<your approved line> SMSIR_ALLOW_SEND=trueVerify connectivity without spending anything — from a connected client call
health_check(orget_balance).Then, and only then, make the first billable call. Exact tool call:
send_sms({ "message_text": "SMS.ir MCP test", "mobiles": ["<your own mobile>"], "line_number": "<your approved line>", "confirm": true })Codex phrasing: "Use the sms-ir server's send_sms tool to send 'SMS.ir MCP test' to from line , with confirm true."
9. Troubleshooting
Symptom | Cause / fix |
| No key in env or |
| Wrong/rotated key, or key lacks Panel API access |
|
|
Edited | The server reads config once at startup. Call |
| Re-call the tool with |
| Use 10–15 digits, optional leading |
| Client-side limiter tripped; raise |
| Network/5xx after retries; check connectivity and SMS.ir status |
Client shows no tools | Wrong |
| SMS.ir rejected the request; |
This server cannot be deployed
Maintenance
Related MCP Connectors
- SureSMSOAuthcom.suresms
Send SMS, manage contacts and groups, and read delivery reports. OAuth 2.1 SureSMS login.
Read Messente balance, prices, delivery status and statistics; send SMS to up to 10 numbers.
Send and schedule SMS and WhatsApp messages, manage contacts and templates, and track delivery.
Manage API keys, identities, permissions, rate-limit overrides and verification analytics.
Related MCP Servers
- AlicenseAqualityAmaintenanceEnables sending SMS, querying delivery reports, and managing senders and blacklists through the iletiMerkezi SMS API.1115 npm2MIT
- AlicenseAqualityAmaintenanceEnables MCP clients to read Instantly.ai analytics and manage leads, campaigns, Unibox, sender accounts, blocklist, and webhooks, with write actions gated behind confirm prompts and configurable safety policies.4059 PyPIMIT
- AlicenseAqualityCmaintenanceEnables policy-aware access to the Productive.io API v2 for managing projects, tasks, time tracking, resource planning, financials, CRM, and reports, with safe defaults and staged writes for sensitive operations.12Apache 2.0
- AlicenseNot gradedqualityAmaintenanceEnables sending and managing SMS, voice messages, contacts, templates, blacklists, and account reports through the przypominamy.com REST API, with key-scoped authorization and safety confirmations for destructive actions.MIT