Skip to main content
Glama
ali-toghiani

SMS.ir MCP server

by ali-toghiani

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: iletiMerkezi MCP Server

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 .env

Variable

Required

Default

Purpose

SMSIR_API_KEY

yes

SMS.ir Panel API key, sent as the X-API-KEY header

SMSIR_DEFAULT_LINE_NUMBER

no

Fallback sender line for send tools

SMSIR_ALLOW_SEND

no

false

Kill switch. Must be true for any real send to leave the process

SMSIR_BASE_URL

no

https://api.sms.ir

API base URL (host-allowlisted)

SMSIR_ALLOW_CUSTOM_BASE_URL

no

false

Allow a non-api.sms.ir host (local mocks only)

SMSIR_TIMEOUT_SECONDS

no

15

Per-request timeout

SMSIR_MAX_RETRIES

no

2

Retries for transient failures (429 / 5xx / network)

SMSIR_RATE_LIMIT_PER_MINUTE

no

60

Client-side rate limit

SMSIR_MAX_PAGE_SIZE

no

200

Upper bound accepted for page_size

SMSIR_LOG_LEVEL

no

INFO

DEBUG / INFO / WARNING / ERROR

SMSIR_ENV_FILE

no

./.env

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 8000

For 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

get_balance

read

GET /v1/credit

Remaining SMS credit

list_lines

read

GET /v1/line

Sender line numbers / virtual numbers

get_message_report

read

GET /v1/send/{id}

Delivery report/status for one sent message

get_pack_report

read

GET /v1/send/pack/{packId}

Per-recipient results for a bulk pack (paginated)

list_sent_messages

read

GET /v1/send/live · /archive

Sent messages, scope=today|archive

list_sent_packs

read

GET /v1/send/pack · /archive/pack

Bulk packs, scope=today|archive

list_inbound_messages

read

GET /v1/receive/latest · /live · /archive

Inbound messages, scope=latest|today|archive

extract_latest_otp

read

GET /v1/receive/latest

Newest inbound message containing a parseable one-time code (heuristic)

health_check

read

GET /v1/credit

Reachability + auth check, never billable; also returns effective config

reload_config

admin

Re-read .env / env vars without restarting the server (e.g. after flipping SMSIR_ALLOW_SEND); sends nothing

send_sms

billable

POST /v1/send/bulk

One text to one or more recipients

send_verification_code

billable

POST /v1/send/verify

Templated OTP/verification message

send_personalized_sms

billable

POST /v1/send/likeToLike

A distinct text per recipient

cancel_scheduled_send

destructive

DELETE /v1/send/scheduled/{packId}

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:

    1. confirm=true in the tool call, and

    2. SMSIR_ALLOW_SEND=true in the server environment. With the kill switch off, a confirmed call still sends nothing.

  • Destructive operation (cancel_scheduled_send) needs confirm=true.

  • No arbitrary base URLs: only api.sms.ir is accepted unless SMSIR_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-ir

Manual 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 tools

To 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 stdio

Claude 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 pytest

Tests 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:

  1. Put your key in .env:

    SMSIR_API_KEY=<your real key>
    SMSIR_DEFAULT_LINE_NUMBER=<your approved line>
    SMSIR_ALLOW_SEND=true
  2. Verify connectivity without spending anything — from a connected client call health_check (or get_balance).

  3. 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

config_error: SMSIR_API_KEY is not set

No key in env or .env; check SMSIR_ENV_FILE path the client passes

auth_error on every call

Wrong/rotated key, or key lacks Panel API access

send_disabled

SMSIR_ALLOW_SEND is not true in the server environment

Edited .env but nothing changed

The server reads config once at startup. Call reload_config, or restart the MCP client so it respawns the server

confirmation_required

Re-call the tool with "confirm": true

validation_error: Invalid mobile number

Use 10–15 digits, optional leading +

rate_limited

Client-side limiter tripped; raise SMSIR_RATE_LIMIT_PER_MINUTE or slow down

transient_error

Network/5xx after retries; check connectivity and SMS.ir status

Client shows no tools

Wrong command path in the client config; point at .venv\Scripts\python.exe

api_error with api_status

SMS.ir rejected the request; message carries their reason

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    A
    maintenance
    Enables comprehensive email marketing and transactional email operations through SendGrid's API v3. Supports contact management, campaign creation, email automation, list management, and email sending with built-in read-only safety mode.
    58
    1,384
    3
    ISC
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables searching SOLAPI documentation and examples, and sending/managing SMS, LMS, MMS, RCS, and Kakao messages with safety guards.
    250
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Enables 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.
    40
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ali-toghiani/sms-ir-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server