Skip to main content
Glama

messages_send

Destructive

Send a message to a thread, channel, or contact. Supports Telegram, Email, LinkedIn, and other connected channels. For LinkedIn posts (comment_thread kind), this posts a comment on the post. Can automatically resolve recipients and channels when not specified. Can send files/images/documents as attachments — pass attachments=[file_id, ...] with integer file IDs obtained from collections.list_files, search.files, or files.search. text is optional when attachments are provided.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
textNoMessage text to send. Optional if attachments provided.
formatNoMessage formattext
silentNoSend without notification
buttonsNoInline reply buttons shown under the message, one per row (max 10). Each item is {"label": "<visible button text>"} plus exactly one target: "value" (a string sent back as a normal incoming message when tapped, defaults to the label, max 64 bytes), "url" (opens a link) or "web_app" (opens an https page as a Telegram Mini App). Only on channels that support buttons (Telegram bot accounts); can accompany at most one attachment, and when the text is too long for a media caption the buttons arrive with the text as a second message.
templateNoWhatsApp Business API only. An approved template to send instead of free text, in Meta's shape: {name, language, components:[{type:'body', parameters:[{type:'text', text:...}]}, ...]}; `language` is the code as a string ('en_US'). Required when the 24-hour window of the conversation is closed (the send answers WINDOW_EXPIRED otherwise). Read the approved templates and their variables with channels.list(account_id=...).
thread_idNoTarget thread. OMIT to reply in the same chat you received the triggering message from — the backend defaults to the current thread. Pass an explicit value ONLY to reply in a DIFFERENT thread, and only use: (a) a numeric DB thread id from search.threads, or (b) a channel_ref like 'telegram:-12345'. To write to a phone number nobody has a thread with yet: 'whatsapp_business:+<number in international format>' opens a WhatsApp conversation from a WhatsApp Business API number (from_account_id picks which one; the first message must be a `template`), and 'sms:+<number>' texts it from a workspace phone number that has SMS turned on (from_account_id picks which one), landing in that number's conversation with the recipient, next to their calls. NEVER use a chat-type word (dm, group, channel, livechat, comment_thread) — those are category labels from the SITUATION block, not ids.
attachmentsNoArray of integer file IDs to send as attachments (images, documents, any files). Get file IDs from collections.list_files (field `file_id`), search.files (field `file_id`), or files.search — only ids returned by those calls in this workspace. The file must already exist in the workspace (status=ready) — no separate upload step needed. When attachments are provided, `text` becomes optional (a caption can be included alongside).
in_workspaceNoRun this one call in this workspace id instead of the session's. Nothing is stored; other sessions are not affected.
private_replyNoComment threads only (Instagram, Facebook): answer the comment in the commenter's private messages instead of publicly under the post (Meta's Private Replies). One message per comment, within 7 days of the comment. The message is filed in the person's private conversation. To also answer publicly, make a second call without this flag. OMIT for a normal send.
recipient_nameNoName of person to send to (e.g., 'Jane', 'John'). Tool will auto-resolve channel. Optional if thread_id provided.
from_account_idNoWhich of the workspace's accounts on this channel SENDS the message, i.e. the number or handle the recipient sees. Only meaningful when starting a NEW conversation — an existing thread already belongs to an account and that one is used. OMIT and the platform picks the most recently active account, which is a coin flip in a workspace with several numbers: pass it whenever one of them must not be used to open conversations (a personal line, or one under a spam restriction). An account that is not active in this workspace is refused, never silently swapped.
recipient_usernameNoTelegram @username to message (e.g. '@some_username'). Use this for a Telegram user NOT yet in contacts — it resolves the handle, adds the contact, and creates the thread. Telegram only; for existing contacts prefer thread_id or recipient_name.
reply_to_message_idNoID of message to reply to (optional)

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / thread_id / description
      Previous value: -"Target thread. OMIT to reply in the same chat you received the triggering message from — the backend defaults to the current thread. Pass an explicit value ONLY to reply in a DIFFERENT thread, and only use: (a) a numeric DB thread id from search.threads, or (b) a channel_ref like 'telegram:-12345'. To write to a phone number nobody has a thread with yet: 'whatsapp_business:+<number in international format>' opens a WhatsApp conversation from a WhatsApp Business API number (from_account_id picks which one; the first message must be a `template`), and 'sms:+<number>' texts it from a workspace phone number that has SMS turned on (from_account_id picks which one), landing in that number's conversation with the recipient, next to their calls. NEVER use a chat-type word (dm, group, channel, livechat) — those are category labels from the SITUATION block, not ids."New value: +"Target thread. OMIT to reply in the same chat you received the triggering message from — the backend defaults to the current thread. Pass an explicit value ONLY to reply in a DIFFERENT thread, and only use: (a) a numeric DB thread id from search.threads, or (b) a channel_ref like 'telegram:-12345'. To write to a phone number nobody has a thread with yet: 'whatsapp_business:+<number in international format>' opens a WhatsApp conversation from a WhatsApp Business API number (from_account_id picks which one; the first message must be a `template`), and 'sms:+<number>' texts it from a workspace phone number that has SMS turned on (from_account_id picks which one), landing in that number's conversation with the recipient, next to their calls. NEVER use a chat-type word (dm, group, channel, livechat, comment_thread) — those are category labels from the SITUATION block, not ids."
  2. Changed3 schema fields changed
    • changedInput schema / properties / template / description
      Previous value: -"WhatsApp Business API only. An approved template to send instead of free text, in Meta's shape: {name, language, components:[{type:'body', parameters:[{type:'text', text:...}]}, ...]}; `language` may be the code as a string ('en_US') or Meta's {code:'en_US'}. Required when the 24-hour window of the conversation is closed (the send answers WINDOW_EXPIRED otherwise). Read the approved templates and their variables with channels.list(account_id=...)."New value: +"WhatsApp Business API only. An approved template to send instead of free text, in Meta's shape: {name, language, components:[{type:'body', parameters:[{type:'text', text:...}]}, ...]}; `language` is the code as a string ('en_US'). Required when the 24-hour window of the conversation is closed (the send answers WINDOW_EXPIRED otherwise). Read the approved templates and their variables with channels.list(account_id=...)."
    • addedInput schema / properties / template / properties
      Added value: +{
      +  "components": {
      +    "description": "Variable values per component, in Meta's shape.",
      +    "items": {
      +      "properties": {
      +        "parameters": {
      +          "items": {
      +            "properties": {
      +              "text": {
      +                "description": "The value of this variable.",
      +                "type": "string"
      +              },
      +              "type": {
      +                "description": "'text'.",
      +                "type": "string"
      +              }
      +            },
      +            "type": "object"
      +          },
      +          "type": "array"
      +        },
      +        "type": {
      +          "description": "'body', 'header' or 'button'.",
      +          "type": "string"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "type": "array"
      +  },
      +  "language": {
      +    "description": "Template language code, e.g. 'en_US'.",
      +    "type": "string"
      +  },
      +  "name": {
      +    "description": "Template name as approved at Meta.",
      +    "type": "string"
      +  }
      +}
    • changedInput schema / properties / thread_id / description
      Previous value: -"Target thread. OMIT to reply in the same chat you received the triggering message from — the backend defaults to the current thread. Pass an explicit value ONLY to reply in a DIFFERENT thread, and only use: (a) a numeric DB thread id from search.threads, or (b) a channel_ref like 'telegram:-12345'. To text a phone number, pass 'sms:+<number in international format>': the message goes out from a workspace phone number that has SMS turned on (from_account_id picks which one) and lands in that number's conversation with the recipient, next to their calls. NEVER use a chat-type word (dm, group, channel, livechat) — those are category labels from the SITUATION block, not ids."New value: +"Target thread. OMIT to reply in the same chat you received the triggering message from — the backend defaults to the current thread. Pass an explicit value ONLY to reply in a DIFFERENT thread, and only use: (a) a numeric DB thread id from search.threads, or (b) a channel_ref like 'telegram:-12345'. To write to a phone number nobody has a thread with yet: 'whatsapp_business:+<number in international format>' opens a WhatsApp conversation from a WhatsApp Business API number (from_account_id picks which one; the first message must be a `template`), and 'sms:+<number>' texts it from a workspace phone number that has SMS turned on (from_account_id picks which one), landing in that number's conversation with the recipient, next to their calls. NEVER use a chat-type word (dm, group, channel, livechat) — those are category labels from the SITUATION block, not ids."
  3. Changed1 schema field changed
    • addedInput schema / properties / template
      Added value: +{
      +  "description": "WhatsApp Business API only. An approved template to send instead of free text, in Meta's shape: {name, language, components:[{type:'body', parameters:[{type:'text', text:...}]}, ...]}; `language` may be the code as a string ('en_US') or Meta's {code:'en_US'}. Required when the 24-hour window of the conversation is closed (the send answers WINDOW_EXPIRED otherwise). Read the approved templates and their variables with channels.list(account_id=...).",
      +  "type": "object"
      +}
  4. Changed1 schema field changed
    • addedInput schema / properties / in_workspace
      Added value: +{
      +  "description": "Run this one call in this workspace id instead of the session's. Nothing is stored; other sessions are not affected.",
      +  "type": "integer"
      +}
  5. Changed1 schema field changed
    • changedInput schema / properties / thread_id / description
      Previous value: -"Target thread. OMIT to reply in the same chat you received the triggering message from — the backend defaults to the current thread. Pass an explicit value ONLY to reply in a DIFFERENT thread, and only use: (a) a numeric DB thread id from search.threads, or (b) a channel_ref like 'telegram:-12345'. To text a phone number that has no thread yet, pass 'sms:+<number in international format>' (the workspace needs a phone number with SMS turned on; from_account_id picks which one). NEVER use a chat-type word (dm, group, channel, livechat) — those are category labels from the SITUATION block, not ids."New value: +"Target thread. OMIT to reply in the same chat you received the triggering message from — the backend defaults to the current thread. Pass an explicit value ONLY to reply in a DIFFERENT thread, and only use: (a) a numeric DB thread id from search.threads, or (b) a channel_ref like 'telegram:-12345'. To text a phone number, pass 'sms:+<number in international format>': the message goes out from a workspace phone number that has SMS turned on (from_account_id picks which one) and lands in that number's conversation with the recipient, next to their calls. NEVER use a chat-type word (dm, group, channel, livechat) — those are category labels from the SITUATION block, not ids."
  6. Changed1 schema field changed
    • changedInput schema / properties / thread_id / description
      Previous value: -"Target thread. OMIT to reply in the same chat you received the triggering message from — the backend defaults to the current thread. Pass an explicit value ONLY to reply in a DIFFERENT thread, and only use: (a) a numeric DB thread id from search.threads, or (b) a channel_ref like 'telegram:-12345'. NEVER use a chat-type word (dm, group, channel, livechat) — those are category labels from the SITUATION block, not ids."New value: +"Target thread. OMIT to reply in the same chat you received the triggering message from — the backend defaults to the current thread. Pass an explicit value ONLY to reply in a DIFFERENT thread, and only use: (a) a numeric DB thread id from search.threads, or (b) a channel_ref like 'telegram:-12345'. To text a phone number that has no thread yet, pass 'sms:+<number in international format>' (the workspace needs a phone number with SMS turned on; from_account_id picks which one). NEVER use a chat-type word (dm, group, channel, livechat) — those are category labels from the SITUATION block, not ids."
  7. First observed

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false, destructiveHint=true, idempotentHint=false and openWorldHint=true, so the mutating, irreversible, external-side-effect profile is covered structurally. The description adds useful behavioral context (attachments must be pre-existing workspace files, LinkedIn comment_thread posts a comment, text is optional with attachments) but says nothing about duplicate-send risk, permissions, or rate limits that a non-idempotent send tool would benefit from.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Five front-loaded sentences: the core action first, then channel scope, LinkedIn nuance, recipient auto-resolution, and attachment usage. It is efficient overall, though the attachment sentence duplicates schema text rather than adding to it, which costs it a point.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 13-parameter, nested-object, no-output-schema tool, the description covers the primary send paths and the non-obvious LinkedIn comment behavior adequately, and the rich annotations plus 100%-covered schema carry the rest. It stops short of the multi-account/from_account_id and WhatsApp template/WINDOW_EXPIRED nuances, but those are fully handled in the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all 13 parameters in detail. The description's parameter content (attachments=[file_id,...] sourced from collections.list_files/search.files/files.search, and text being optional with attachments) largely restates what the schema already says, adding no new semantics. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Send a message to a thread, channel, or contact') and enumerates the supported channels (Telegram, Email, LinkedIn), so the core action is unambiguous. However, it never contrasts itself with the close siblings messages_send_email or messages_edit, and naming Email as a supported channel here muddies rather than sharpens the boundary with messages_send_email.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage ('Can automatically resolve recipients and channels when not specified') and notes the LinkedIn comment_thread case, which is a genuine routing hint. But it gives no explicit when-to-use/when-not guidance and never names an alternative tool, so the agent must infer when this is preferred over messages_send_email, messages_forward, or messages_press_button.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.