Sakari MCP by usefulapi

Manage Sakari SMS contacts, conversations, templates and campaigns, and send texts.

Should I use this

Quality & Safety

A
Description quality
99%
Schema completeness
83%
Naming quality
80%
Poisoning risk
80%
Permission match
100%
Protocol compliance
100%

Findings (3)

  • HIGHTool poisoning patterns detected
  • MEDIUMTool 'sakari_send_message' description contains placeholder textin sakari_send_message
  • INFOTool description contains placeholder or incomplete textin sakari_send_message

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~3,972Tokens (tool definitions)
~1.1 KBTypical response size
Significant attention impact (3.10% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "sakari": {
      "url": "https://sakari.usefulapi.io/mcp"
    }
  }
}

Remote endpoints

https://sakari.usefulapi.io/mcpstreamable-http

What it can do

Tool inventory

Tools (23)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟢sakari_get_account

The Sakari account these credentials belong to: name, plan, balance, default country, business info and options. API credentials are never returned. GET /v1/accounts/{accountId}.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_get_balance

Prepaid balance, default country, remaining segments and the price per segment. GET /v1/accounts/{accountId}/balance.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_list_contacts(first_name, last_name, mobile, email, tags, ...)

List or search contacts (partial matches on name, mobile or email; filter by tag). GET /v1/accounts/{accountId}/contacts.

Input Schema

{
  "type": "object",
  "properties": {
    "first_name": {
      "description": "Filter by first name or part of it.",
      "type": "string",
      "maxLength": 200
    },
    "last_name": {
      "description": "Filter by last name or part of it.",
      "type": "string",
      "maxLength": 200
    },
    "mobile": {
      "description": "Filter by mobile number or part of it.",
      "type": "string",
      "maxLength": 40
    },
    "email": {
      "description": "Filter by email or part of it.",
      "type": "string",
      "maxLength": 254
    },
    "tags": {
      "description": "Filter by tag(s).",
      "type": "string",
      "maxLength": 200
    },
    "offset": {
      "description": "Results to skip (default 0). Pass the previous reply's next_offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 10000000
    },
    "limit": {
      "description": "Results per page, 1-100 (default 25).",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_get_contact(contact_id)

One contact by id: name, mobile (with validity and line type), email, lists, attributes, opt-in and blocked state. GET /v1/accounts/{accountId}/contacts/{contactId}.

Input Schema

{
  "type": "object",
  "properties": {
    "contact_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari contact id."
    }
  },
  "required": [
    "contact_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴sakari_create_contact(mobile, country, first_name, last_name, email, ...)

WRITE: create a contact. If a contact with the same mobile number exists, merge_strategy decides what happens (append, core or remove, per Sakari). A contact is not opted in to messages by this call. POST /v1/accounts/{accountId}/contacts.

Input Schema

{
  "type": "object",
  "properties": {
    "mobile": {
      "type": "string",
      "pattern": "^\\+[1-9]\\d{6,14}$",
      "description": "Mobile number in international format, e.g. +13471234567."
    },
    "country": {
      "description": "2-letter country of the number (default: the account's default country).",
      "type": "string",
      "pattern": "^[A-Za-z]{2}$"
    },
    "first_name": {
      "type": "string",
      "maxLength": 200
    },
    "last_name": {
      "type": "string",
      "maxLength": 200
    },
    "email": {
      "type": "string",
      "maxLength": 254
    },
    "merge_strategy": {
      "description": "How an existing contact with the same mobile is treated.",
      "type": "string",
      "enum": [
        "append",
        "core",
        "remove"
      ]
    }
  },
  "required": [
    "mobile"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴sakari_update_contact(contact_id, first_name, last_name, email, mobile, ...)

WRITE: change a contact's name, email or mobile. Sakari's update replaces the contact, so this reads the current contact first and sends it back whole (lists, opt-in, blocked, attributes) with only your changes applied. PUT /v1/accounts/{accountId}/contacts/{contactId}.

Input Schema

{
  "type": "object",
  "properties": {
    "contact_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari contact id."
    },
    "first_name": {
      "type": "string",
      "maxLength": 200
    },
    "last_name": {
      "type": "string",
      "maxLength": 200
    },
    "email": {
      "type": "string",
      "maxLength": 254
    },
    "mobile": {
      "description": "New mobile number in international format.",
      "type": "string",
      "pattern": "^\\+[1-9]\\d{6,14}$"
    },
    "country": {
      "description": "2-letter country of the mobile number.",
      "type": "string",
      "pattern": "^[A-Za-z]{2}$"
    }
  },
  "required": [
    "contact_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_list_messages(contact_id, conversation_id, offset, limit)

List messages (sent and received) with status, segments, price and timestamps; filter by contact or conversation. GET /v1/accounts/{accountId}/messages.

Input Schema

{
  "type": "object",
  "properties": {
    "contact_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari contact id."
    },
    "conversation_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari conversation id."
    },
    "offset": {
      "description": "Results to skip (default 0). Pass the previous reply's next_offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 10000000
    },
    "limit": {
      "description": "Results per page, 1-100 (default 25).",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_get_message(message_id)

One message by id: text, direction, status, segments, price, error. GET /v1/accounts/{accountId}/messages/{messageId}.

Input Schema

{
  "type": "object",
  "properties": {
    "message_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari message id."
    }
  },
  "required": [
    "message_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴sakari_send_message(text, to_numbers, contact_ids, conversation_ids, type, ...)

WRITE: SEND REAL TEXT MESSAGES that cost account balance and cannot be recalled. Recipients: phone numbers (international format), existing contact ids, or conversation ids (max 100 in total). Only text people who opted in; Sakari enforces TCPA/CTIA rules and the sender is responsible. Confirm the recipients and the text with the user first. Placeholders like {{firstName}} are filled per contact. POST /v1/accounts/{accountId}/messages.

Input Schema

{
  "type": "object",
  "properties": {
    "text": {
      "type": "string",
      "minLength": 1,
      "maxLength": 1600,
      "description": "Message text (the Sakari 'template')."
    },
    "to_numbers": {
      "description": "Recipient phone numbers in international format.",
      "maxItems": 100,
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^\\+[1-9]\\d{6,14}$"
      }
    },
    "contact_ids": {
      "description": "Existing Sakari contact ids.",
      "maxItems": 100,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 128,
        "description": "Sakari contact id."
      }
    },
    "conversation_ids": {
      "description": "Existing conversation ids to reply into.",
      "maxItems": 100,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 128,
        "description": "Sakari conversation id."
      }
    },
    "type": {
      "description": "SMS (default) or MMS.",
      "type": "string",
      "enum": [
        "SMS",
        "MMS"
      ]
    },
    "media_urls": {
      "description": "Public media URLs to attach (MMS).",
      "maxItems": 10,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 2000,
        "format": "uri"
      }
    },
    "confirm_send": {
      "type": "boolean",
      "const": true,
      "description": "Must be true: you confirm the user approved these recipients and this text, and that the texts go out now."
    }
  },
  "required": [
    "text",
    "confirm_send"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_list_conversations(offset, limit)

List conversations (the inbox): contact, last message, unread count, open or closed. GET /v1/accounts/{accountId}/conversations.

Input Schema

{
  "type": "object",
  "properties": {
    "offset": {
      "description": "Results to skip (default 0). Pass the previous reply's next_offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 10000000
    },
    "limit": {
      "description": "Results per page, 1-100 (default 25).",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_get_conversation(conversation_id)

One conversation by id. Use sakari_list_messages with conversation_id for its messages. GET /v1/accounts/{accountId}/conversations/{conversationId}.

Input Schema

{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari conversation id."
    }
  },
  "required": [
    "conversation_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🔴sakari_close_conversation(conversation_id)

WRITE: mark a conversation closed in the Sakari inbox (a new inbound message reopens it). PUT /v1/accounts/{accountId}/conversations/{conversationId}/close.

Input Schema

{
  "type": "object",
  "properties": {
    "conversation_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari conversation id."
    }
  },
  "required": [
    "conversation_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_list_templates(name, offset, limit)

List reusable message templates. GET /v1/accounts/{accountId}/templates.

Input Schema

{
  "type": "object",
  "properties": {
    "name": {
      "description": "Filter by name or part of it.",
      "type": "string",
      "maxLength": 200
    },
    "offset": {
      "description": "Results to skip (default 0). Pass the previous reply's next_offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 10000000
    },
    "limit": {
      "description": "Results per page, 1-100 (default 25).",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_get_template(template_id)

One message template by id. GET /v1/accounts/{accountId}/templates/{templateId}.

Input Schema

{
  "type": "object",
  "properties": {
    "template_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari template id."
    }
  },
  "required": [
    "template_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟡sakari_create_template(name, text)

WRITE: create a reusable SMS template (does not send anything). POST /v1/accounts/{accountId}/templates.

Input Schema

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 200,
      "description": "Template name."
    },
    "text": {
      "type": "string",
      "minLength": 1,
      "maxLength": 1600,
      "description": "Template text; may contain placeholders such as {{firstName}}."
    }
  },
  "required": [
    "name",
    "text"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_list_campaigns(name, offset, limit)

List message campaigns with schedule, template, status and reporting. GET /v1/accounts/{accountId}/campaigns.

Input Schema

{
  "type": "object",
  "properties": {
    "name": {
      "description": "Filter by name or part of it.",
      "type": "string",
      "maxLength": 200
    },
    "offset": {
      "description": "Results to skip (default 0). Pass the previous reply's next_offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 10000000
    },
    "limit": {
      "description": "Results per page, 1-100 (default 25).",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_get_campaign(campaign_id)

One campaign by id. GET /v1/accounts/{accountId}/campaigns/{campaignId}.

Input Schema

{
  "type": "object",
  "properties": {
    "campaign_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari campaign id."
    }
  },
  "required": [
    "campaign_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_list_calls(contact_id, conversation_id, direction, status, from, ...)

Call history (voice) with direction, status, duration and contact; filter by contact, conversation, direction, status or date range. GET /v1/accounts/{accountId}/calls.

Input Schema

{
  "type": "object",
  "properties": {
    "contact_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari contact id."
    },
    "conversation_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari conversation id."
    },
    "direction": {
      "type": "string",
      "enum": [
        "inbound",
        "outbound"
      ]
    },
    "status": {
      "type": "string",
      "enum": [
        "initiated",
        "ringing",
        "active",
        "ended",
        "rejected",
        "forwarded",
        "missed",
        "transferring"
      ]
    },
    "from": {
      "description": "Start of the date range (ISO 8601 date-time).",
      "type": "string",
      "minLength": 10,
      "maxLength": 40
    },
    "to": {
      "description": "End of the date range (ISO 8601 date-time).",
      "type": "string",
      "minLength": 10,
      "maxLength": 40
    },
    "offset": {
      "description": "Results to skip (default 0). Pass the previous reply's next_offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 10000000
    },
    "limit": {
      "description": "Results per page, 1-100 (default 25).",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_get_call(call_id)

One call history record by id. GET /v1/accounts/{accountId}/calls/{callId}.

Input Schema

{
  "type": "object",
  "properties": {
    "call_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128,
      "description": "Sakari call id."
    }
  },
  "required": [
    "call_id"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_list_links(q)

Shortened tracked links with destination, short URL and click stats. GET /v1/accounts/{accountId}/links.

Input Schema

{
  "type": "object",
  "properties": {
    "q": {
      "description": "Search term across link fields.",
      "type": "string",
      "maxLength": 200
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_list_forms(q, offset, limit)

Lead capture forms with active state, impressions and conversions. GET /v1/accounts/{accountId}/forms.

Input Schema

{
  "type": "object",
  "properties": {
    "q": {
      "description": "Search term across form fields.",
      "type": "string",
      "maxLength": 200
    },
    "offset": {
      "description": "Results to skip (default 0). Pass the previous reply's next_offset.",
      "type": "integer",
      "minimum": 0,
      "maximum": 10000000
    },
    "limit": {
      "description": "Results per page, 1-100 (default 25).",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_list_webhooks

Active webhook subscriptions (message event notifications). GET /v1/accounts/{accountId}/webhooks.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}
🟢sakari_list_autoresponders

Autoresponders (automatic replies) configured on the account. GET /v1/accounts/{accountId}/autoresponders.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "https://json-schema.org/draft/2020-12/schema"
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded23 tools