Ray notifications

Send email, push, Slack, Discord, Telegram and webhook notifications and manage templates with Ray.

Sollte ich dies verwenden

Qualität und Sicherheit

A
Qualität der Beschreibung
100%
Vollständigkeit des Schemas
88%
Qualität der Benennung
97%
Risiko der Vergiftung
100%
Übereinstimmung der Berechtigungen
100%
Einhaltung des Protokolls
100%

Basierend auf einer automatisierten Analyse der Tool-Definitionen und der Einhaltung des Protokolls.

Kontextkosten

~9,518Tokens (Tool-Definitionen)
~3.4 KBTypische Antwortgröße
Erhebliche Auswirkung auf die Aufmerksamkeit (7.44% von 128k Kontext)

Dies ist die ungefähre Anzahl der Tokens, die jedes Mal verbraucht werden, wenn die Tools des Servers in den Kontext eines Modells geladen werden. Höhere Werte verringern die Aufmerksamkeit, die für andere Aufgaben verfügbar ist.

Installieren

Installation mit einem Klick

Fügen Sie dies Ihrer Datei `claude_desktop_config.json` hinzu:

{
  "mcpServers": {
    "ray-mcp": {
      "command": "npx",
      "args": [
        "@gege-mn/ray-mcp"
      ]
    }
  }
}

Ausführbare Pakete

npm@gege-mn/ray-mcp0.1.0stdio

Remote-Endpunkte

https://ray-api.gege.mn/mcpstreamable-http

Was es kann

Tool-Inventar

Tools (21)

🟢 Nur lesen🟡 Schreiben🔴 Löschen⚪ Unbekannt
🟢whoami

Identify the API key this connection uses (GET /me): `tenantId` (the workspace), `apiKeyId` and `scopes`. Write tools need the `write` scope; call this to check before attempting them.

Eingabe-Schema

{
  "type": "object",
  "properties": {},
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_usage

The workspace's plan, subscription status and this calendar month's usage against the monthly quota (GET /billing/subscription). `used`/`remaining` are null on unmetered plans. On a hard-capped plan, sends beyond the quota fail with HTTP 402 quota_exceeded.

Eingabe-Schema

{
  "type": "object",
  "properties": {},
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢list_channels

List the delivery channels configured in this workspace (GET /channels). Call this FIRST before sending: each entry's `id` is the `channelConfigId` for send_notification and test_send_template, `kind` is the channel type (ses_email, smtp_email, fcm_push, slack_webhook, discord_webhook, telegram_bot, twilio_sms, sendsms_mn, generic_webhook), `templateKind` is the template channelKind it accepts, and `recipientSchema` is the exact JSON Schema of the `recipient` it expects. Channels and their provider credentials are set up in the Ray dashboard, not through this API; if the list is empty, ask the user to add one there.

Eingabe-Schema

{
  "type": "object",
  "properties": {},
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡send_notification(channelConfigId, recipient, targets, deliveries, templateId, ...)

Send a notification (POST /send; needs a `write`-scoped key). Returns `{ sendId }` with HTTP 202: delivery is asynchronous, so check the outcome with get_send_status. Use exactly one mode: 1. Single: `channelConfigId` + `recipient`. 2. Fan-out: `channelConfigId` + `targets` (1-1000 `{ recipient, externalUserId? }`), one channel, one sendId. 3. Multi-channel: `deliveries` (1-10, each with its own `channelConfigId`, `recipient` and `templateId` or `content`) for ONE person over several channels; add `feed` + `externalUserId` for a single in-app feed entry. 4. Feed-only: `feed` (with `title`) + `externalUserId` and no channel: an in-app notification only. In modes 1-2 give exactly one of `templateId` (a published template, plus `params`) or inline `content`; in mode 3 that choice is made per delivery. Get channel ids and each recipient shape from list_channels first. Pass `idempotencyKey` whenever a retry must not deliver twice.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "channelConfigId": {
      "description": "Modes 1-2: the channel to send through — an `id` from list_channels. Not allowed together with `deliveries`.",
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "recipient": {
      "description": "Mode 1: the single recipient. Mutually exclusive with `targets`. Channel-specific delivery target. Its shape depends on the kind of the chosen channel (list_channels returns each channel's exact `recipientSchema`): ses_email / smtp_email → `{ email, name?, cc?: [{ email, name? }], bcc?: [...], attachments?: [{ filename, content (base64), contentType?, disposition?: \"attachment\"|\"inline\", contentId? }] }`; fcm_push → `{ deviceToken }` OR `{ topic }` (exactly one; Ray keeps no device registry); telegram_bot → `{ chatId }` (numeric id as a string, or \"@channelname\"); twilio_sms → `{ phoneNumber }` (international E.164, e.g. \"+97699112233\"); sendsms_mn → `{ phoneNumber }` (Mongolian 8-digit, e.g. \"99112233\"); slack_webhook, discord_webhook, generic_webhook → `{}` (the destination is part of the channel config).",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    },
    "targets": {
      "description": "Mode 2: fan-out to 1-1000 recipients over ONE channel, sharing one sendId. Mutually exclusive with `recipient`.",
      "minItems": 1,
      "maxItems": 1000,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "recipient": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {},
            "description": "Channel-specific delivery target. Its shape depends on the kind of the chosen channel (list_channels returns each channel's exact `recipientSchema`): ses_email / smtp_email → `{ email, name?, cc?: [{ email, name? }], bcc?: [...], attachments?: [{ filename, content (base64), contentType?, disposition?: \"attachment\"|\"inline\", contentId? }] }`; fcm_push → `{ deviceToken }` OR `{ topic }` (exactly one; Ray keeps no device registry); telegram_bot → `{ chatId }` (numeric id as a string, or \"@channelname\"); twilio_sms → `{ phoneNumber }` (international E.164, e.g. \"+97699112233\"); sendsms_mn → `{ phoneNumber }` (Mongolian 8-digit, e.g. \"99112233\"); slack_webhook, discord_webhook, generic_webhook → `{}` (the destination is part of the channel config)."
          },
          "externalUserId": {
            "description": "Your own id for this recipient. With `feed`/`showInFeed` they also get an in-app feed entry.",
            "type": "string",
            "minLength": 1,
            "maxLength": 256
          }
        },
        "required": [
          "recipient"
        ]
      }
    },
    "deliveries": {
      "description": "Mode 3: the same notification to ONE person over several channels (e.g. push + email), max 10. Each entry has its own channel, recipient and content source. Do not combine with top-level channelConfigId/recipient/targets/templateId/content.",
      "minItems": 1,
      "maxItems": 10,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "channelConfigId": {
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
            "description": "Channel for this delivery (from list_channels)."
          },
          "recipient": {
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {},
            "description": "Channel-specific delivery target. Its shape depends on the kind of the chosen channel (list_channels returns each channel's exact `recipientSchema`): ses_email / smtp_email → `{ email, name?, cc?: [{ email, name? }], bcc?: [...], attachments?: [{ filename, content (base64), contentType?, disposition?: \"attachment\"|\"inline\", contentId? }] }`; fcm_push → `{ deviceToken }` OR `{ topic }` (exactly one; Ray keeps no device registry); telegram_bot → `{ chatId }` (numeric id as a string, or \"@channelname\"); twilio_sms → `{ phoneNumber }` (international E.164, e.g. \"+97699112233\"); sendsms_mn → `{ phoneNumber }` (Mongolian 8-digit, e.g. \"99112233\"); slack_webhook, discord_webhook, generic_webhook → `{}` (the destination is part of the channel config)."
          },
          "templateId": {
            "description": "Published template for this delivery. Exactly one of `templateId` or `content`.",
            "type": "string",
            "format": "uuid",
            "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
          },
          "content": {
            "description": "Inline message content, used INSTEAD of `templateId` (give exactly one of the two). Shape by channel kind: ses_email / smtp_email → `{ subject, bodyHtml, bodyText }`; fcm_push → `{ title, body, imageUrl?, data?: { [key]: string } }`; slack_webhook → `{ text }` (Slack mrkdwn); discord_webhook → `{ content }` (max 2000 chars); telegram_bot → `{ text, disableLinkPreview? }` (Telegram HTML subset); twilio_sms / sendsms_mn → `{ text }` (plain text; up to 1600 chars on Twilio, sendsms_mn splits long text into SMS of 159 plain-Latin / 69 Cyrillic chars, each billed); generic_webhook → `{ title, body, data?: { [key]: string } }`. `{{name}}` placeholders are filled from `params` and escaped for the channel.",
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {}
          },
          "params": {
            "description": "Params for this delivery; falls back to the top-level `params`.",
            "type": "object",
            "propertyNames": {
              "type": "string"
            },
            "additionalProperties": {}
          },
          "logTitle": {
            "description": "Feed/log title; only valid with inline `content`.",
            "type": "string",
            "maxLength": 500
          },
          "logDescription": {
            "description": "Feed/log description; only valid with inline `content`.",
            "type": "string",
            "maxLength": 2000
          }
        },
        "required": [
          "channelConfigId",
          "recipient"
        ]
      }
    },
    "templateId": {
      "description": "Modes 1-2: a PUBLISHED template to render (see list_templates / publish_template). Exactly one of `templateId` or `content`. Its channelKind must match the channel's `templateKind`.",
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "content": {
      "description": "Inline message content, used INSTEAD of `templateId` (give exactly one of the two). Shape by channel kind: ses_email / smtp_email → `{ subject, bodyHtml, bodyText }`; fcm_push → `{ title, body, imageUrl?, data?: { [key]: string } }`; slack_webhook → `{ text }` (Slack mrkdwn); discord_webhook → `{ content }` (max 2000 chars); telegram_bot → `{ text, disableLinkPreview? }` (Telegram HTML subset); twilio_sms / sendsms_mn → `{ text }` (plain text; up to 1600 chars on Twilio, sendsms_mn splits long text into SMS of 159 plain-Latin / 69 Cyrillic chars, each billed); generic_webhook → `{ title, body, data?: { [key]: string } }`. `{{name}}` placeholders are filled from `params` and escaped for the channel.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    },
    "params": {
      "description": "Values for the template's `{{placeholders}}`. Any JSON: strings, numbers, booleans, arrays and nested objects (arrays/objects drive `{{#section}}…{{/section}}` blocks). Missing required params are rejected with a 400 naming them.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    },
    "logTitle": {
      "description": "Feed/log title for inline `content` sends only (template sends take it from the template). Placeholders allowed.",
      "type": "string",
      "maxLength": 500
    },
    "logDescription": {
      "description": "Feed/log description for inline `content` sends only. Placeholders allowed.",
      "type": "string",
      "maxLength": 2000
    },
    "feed": {
      "description": "Create exactly ONE in-app feed entry for `externalUserId` (read back with list_feed_notifications). `title`/`description` default to the rendered template text; `title` is required for a feed-only send (mode 4).",
      "type": "object",
      "properties": {
        "title": {
          "type": "string",
          "maxLength": 500
        },
        "description": {
          "type": "string",
          "maxLength": 2000
        }
      }
    },
    "externalUserId": {
      "description": "Your own id for the end user. Required with `feed`; keys their in-app feed.",
      "type": "string",
      "minLength": 1,
      "maxLength": 256
    },
    "showInFeed": {
      "description": "Legacy modes 1-2 flag: also add a feed entry for each target that has an externalUserId. Prefer `feed`. Not valid with `deliveries`.",
      "type": "boolean"
    },
    "trackClicks": {
      "description": "Email channels only: rewrite links in bodyHtml so clicks are counted (read with get_click_stats). Default false.",
      "type": "boolean"
    },
    "campaignId": {
      "description": "Free-form campaign id used to group click stats across sends.",
      "type": "string",
      "minLength": 1,
      "maxLength": 256
    },
    "notBefore": {
      "description": "Schedule delivery for later: ISO 8601 datetime with offset, e.g. \"2026-09-15T09:00:00+08:00\". Omit to send now.",
      "type": "string",
      "format": "date-time",
      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
    },
    "priority": {
      "description": "\"high\" (default) for transactional messages; \"low\" for marketing/bulk so it never delays transactional sends.",
      "type": "string",
      "enum": [
        "high",
        "low"
      ]
    },
    "idempotencyKey": {
      "description": "Sent as the Idempotency-Key header. Retrying with the same key and same arguments returns the original sendId without sending again (24h window); the same key with different arguments fails with 409. Use a fresh unique value (e.g. a UUID) per logical notification.",
      "type": "string",
      "minLength": 1,
      "maxLength": 255
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_send_status(sendId, cursor, limit)

Delivery status of a send (GET /sends/{id}): `aggregate` counts per status over the whole send (pending, claimed, delivered, failed_retryable, failed_terminal, suppressed) plus one page of per-recipient delivery rows including provider errors. Right after sending, rows are usually `pending`; check again after a few seconds. Feed-only sends have no rows. For more rows, pass the returned `nextCursor` as `cursor`.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "sendId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The `sendId` returned by send_notification or test_send_template."
    },
    "cursor": {
      "description": "`nextCursor` from the previous page.",
      "type": "string",
      "minLength": 1
    },
    "limit": {
      "description": "Rows per page (default 50, max 200).",
      "type": "integer",
      "minimum": 1,
      "maximum": 200
    }
  },
  "required": [
    "sendId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢list_templates(folder, includeArchived)

List message templates (GET /templates): id, name, folder, channelKind, and `publishedVersionId` (null = never published, so it cannot be sent by templateId yet). Archived templates are hidden unless `includeArchived` is true. Use get_template for content and required params.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "folder": {
      "description": "Only templates in this folder.",
      "type": "string",
      "maxLength": 200
    },
    "includeArchived": {
      "description": "Include archived templates. Default false.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_template(templateId)

Get one template with its published version and its current draft (GET /templates/{id}): content, logTitle/logDescription, `requiredParams` a send must supply, and paramOverrides. Read this before update_template_draft, which needs the full body.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "templateId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The template id (UUID)."
    }
  },
  "required": [
    "templateId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡create_template(name, folder, channelKind, content, logTitle, ...)

Create a template (POST /templates; write scope). `channelKind` is permanent and must match the channels you'll send through (list_channels `templateKind`). It is saved as an unpublished draft unless `publish: true`; sending by templateId needs a published version (publish_template). Names are unique per workspace including archived templates: a collision returns 409, so unarchive_template the old one instead. Returns `{ id, requiredParams }`. Designed (drag-and-drop) email templates can only be made in the dashboard.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100,
      "description": "Template name, unique per workspace (archived templates included)."
    },
    "folder": {
      "description": "Optional folder path for organisation, e.g. \"billing\".",
      "type": "string",
      "maxLength": 200
    },
    "channelKind": {
      "type": "string",
      "enum": [
        "email_html",
        "fcm_basic",
        "slack_text",
        "discord_text",
        "telegram_text",
        "sms_text",
        "webhook_json"
      ],
      "description": "Which channel family the template renders for. Must match the `templateKind` of the channels you will send through (list_channels). Can't be changed after creation."
    },
    "content": {
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {},
      "description": "Channel-shaped template body; the shape is fixed by `channelKind`: email_html → `{ subject, bodyHtml, bodyText }`; fcm_basic → `{ title, body, imageUrl?, data?: { [key]: string } }`; slack_text → `{ text }`; discord_text → `{ content }` (max 2000 chars); telegram_text → `{ text, disableLinkPreview? }`; sms_text → `{ text }` (plain text, max 1600; long text is split into several billed SMS — on sendsms_mn into parts of 159 plain-Latin / 69 Cyrillic chars); webhook_json → `{ title, body, data?: { [key]: string } }`. Use `{{name}}` placeholders and `{{#items}}…{{/items}}` sections; the required params are derived from them automatically."
    },
    "logTitle": {
      "type": "string",
      "minLength": 1,
      "maxLength": 500,
      "description": "Short title shown in the in-app feed and delivery logs, e.g. \"Invoice {{number}} is due\". Placeholders allowed."
    },
    "logDescription": {
      "type": "string",
      "minLength": 1,
      "maxLength": 2000,
      "description": "One-line description for the in-app feed and delivery logs. Placeholders allowed."
    },
    "paramOverrides": {
      "description": "Per-param metadata keyed by param name: `{ optional?: boolean, description?: string }`. Mark a placeholder optional so sends may omit it.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {
        "type": "object",
        "properties": {
          "optional": {
            "type": "boolean"
          },
          "description": {
            "type": "string",
            "maxLength": 500
          }
        }
      }
    },
    "publish": {
      "description": "true = publish this version immediately so sends by templateId use it. Default false (saved as draft).",
      "type": "boolean"
    }
  },
  "required": [
    "name",
    "channelKind",
    "content",
    "logTitle",
    "logDescription"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡update_template_draft(templateId, name, folder, channelKind, content, ...)

Replace a template's draft (PATCH /templates/{id}; write scope). This is a full replacement, not a partial patch: pass content, logTitle, logDescription and paramOverrides as they should end up (get_template first). `name`, `folder` and `channelKind` are required for validation but not changed (channelKind must equal the original). Live sends keep using the published version until you publish, either with `publish: true` here or publish_template. Fails on archived templates.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "templateId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The template id (UUID)."
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100,
      "description": "Template name, unique per workspace (archived templates included)."
    },
    "folder": {
      "description": "Optional folder path for organisation, e.g. \"billing\".",
      "type": "string",
      "maxLength": 200
    },
    "channelKind": {
      "type": "string",
      "enum": [
        "email_html",
        "fcm_basic",
        "slack_text",
        "discord_text",
        "telegram_text",
        "sms_text",
        "webhook_json"
      ],
      "description": "Which channel family the template renders for. Must match the `templateKind` of the channels you will send through (list_channels). Can't be changed after creation."
    },
    "content": {
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {},
      "description": "Channel-shaped template body; the shape is fixed by `channelKind`: email_html → `{ subject, bodyHtml, bodyText }`; fcm_basic → `{ title, body, imageUrl?, data?: { [key]: string } }`; slack_text → `{ text }`; discord_text → `{ content }` (max 2000 chars); telegram_text → `{ text, disableLinkPreview? }`; sms_text → `{ text }` (plain text, max 1600; long text is split into several billed SMS — on sendsms_mn into parts of 159 plain-Latin / 69 Cyrillic chars); webhook_json → `{ title, body, data?: { [key]: string } }`. Use `{{name}}` placeholders and `{{#items}}…{{/items}}` sections; the required params are derived from them automatically."
    },
    "logTitle": {
      "type": "string",
      "minLength": 1,
      "maxLength": 500,
      "description": "Short title shown in the in-app feed and delivery logs, e.g. \"Invoice {{number}} is due\". Placeholders allowed."
    },
    "logDescription": {
      "type": "string",
      "minLength": 1,
      "maxLength": 2000,
      "description": "One-line description for the in-app feed and delivery logs. Placeholders allowed."
    },
    "paramOverrides": {
      "description": "Per-param metadata keyed by param name: `{ optional?: boolean, description?: string }`. Mark a placeholder optional so sends may omit it.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {
        "type": "object",
        "properties": {
          "optional": {
            "type": "boolean"
          },
          "description": {
            "type": "string",
            "maxLength": 500
          }
        }
      }
    },
    "publish": {
      "description": "true = publish this version immediately so sends by templateId use it. Default false (saved as draft).",
      "type": "boolean"
    }
  },
  "required": [
    "templateId",
    "name",
    "channelKind",
    "content",
    "logTitle",
    "logDescription"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡publish_template(templateId)

Publish a template's current draft as its new live version (POST /templates/{id}/publish; write scope). Sends by templateId use it immediately. Fails if there is no draft or the template is archived.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "templateId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The template id (UUID)."
    }
  },
  "required": [
    "templateId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🔴archive_template(templateId)

Archive a template (POST /templates/{id}/archive; write scope). Sends that reference it fail until it is restored with unarchive_template; its name stays reserved meanwhile. Confirm with the user first if it may be in production use.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "templateId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The template id (UUID)."
    }
  },
  "required": [
    "templateId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡unarchive_template(templateId)

Restore an archived template (POST /templates/{id}/unarchive; write scope). This is how to reclaim a name held by an archived template instead of creating a new one.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "templateId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The template id (UUID)."
    }
  },
  "required": [
    "templateId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡test_send_template(templateId, channelConfigId, recipient, params)

Send a real test of a template's PUBLISHED version to one recipient (POST /templates/{id}/test-send; write scope). It goes through the provider for real, so use a recipient the user controls. Test sends don't count toward the monthly quota (a small daily allowance applies instead) and never appear in feeds. Returns `{ sendId }` for get_send_status.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "templateId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The template id (UUID)."
    },
    "channelConfigId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "Channel to test through (from list_channels); its templateKind must match the template's channelKind."
    },
    "recipient": {
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {},
      "description": "Channel-specific delivery target. Its shape depends on the kind of the chosen channel (list_channels returns each channel's exact `recipientSchema`): ses_email / smtp_email → `{ email, name?, cc?: [{ email, name? }], bcc?: [...], attachments?: [{ filename, content (base64), contentType?, disposition?: \"attachment\"|\"inline\", contentId? }] }`; fcm_push → `{ deviceToken }` OR `{ topic }` (exactly one; Ray keeps no device registry); telegram_bot → `{ chatId }` (numeric id as a string, or \"@channelname\"); twilio_sms → `{ phoneNumber }` (international E.164, e.g. \"+97699112233\"); sendsms_mn → `{ phoneNumber }` (Mongolian 8-digit, e.g. \"99112233\"); slack_webhook, discord_webhook, generic_webhook → `{}` (the destination is part of the channel config)."
    },
    "params": {
      "description": "Values for the template's `{{placeholders}}`. Any JSON: strings, numbers, booleans, arrays and nested objects (arrays/objects drive `{{#section}}…{{/section}}` blocks). Missing required params are rejected with a 400 naming them.",
      "type": "object",
      "propertyNames": {
        "type": "string"
      },
      "additionalProperties": {}
    }
  },
  "required": [
    "templateId",
    "channelConfigId",
    "recipient"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢list_feed_notifications(externalUserId, templateId, channelConfigId, after, before, ...)

Read one end user's in-app notification feed (GET /notifications): the entries created by sends with `feed` or `showInFeed`. This is what an in-app inbox would show, not delivery status (use get_send_status for that). Paginate by passing `nextCursor` back as `cursor`.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "externalUserId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 256,
      "description": "The end user whose feed to read (the `externalUserId` used when sending)."
    },
    "templateId": {
      "description": "Only entries from this template.",
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "channelConfigId": {
      "description": "Only entries whose first delivery used this channel.",
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "after": {
      "description": "Only entries created after this ISO 8601 UTC datetime (e.g. \"2026-09-01T00:00:00Z\").",
      "type": "string",
      "format": "date-time",
      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
    },
    "before": {
      "description": "Only entries created before this ISO 8601 UTC datetime.",
      "type": "string",
      "format": "date-time",
      "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
    },
    "cursor": {
      "description": "`nextCursor` from the previous page.",
      "type": "string",
      "minLength": 1
    },
    "limit": {
      "description": "Entries per page (default 50, max 200).",
      "type": "integer",
      "minimum": 1,
      "maximum": 200
    }
  },
  "required": [
    "externalUserId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_click_stats(sendId, campaignId)

Email link click counts grouped by destination URL (GET /clicks) for a `sendId`, a `campaignId`, or both (at least one is required). Only links from email sends made with `trackClicks: true` are counted.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "sendId": {
      "description": "A sendId from send_notification.",
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
    },
    "campaignId": {
      "description": "The `campaignId` passed to send_notification, to total clicks across many sends.",
      "type": "string",
      "minLength": 1,
      "maxLength": 256
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢list_webhooks(includeArchived)

List the workspace's outbound event webhooks (GET /tenant-webhooks): url, subscribed events, enabled flag and delivery health (consecutiveFailures, lastError). Signing secrets are never returned.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "includeArchived": {
      "description": "Include deleted (archived) webhooks. Default false.",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_webhook(webhookId)

Get one outbound webhook (GET /tenant-webhooks/{id}) including its delivery health (consecutiveFailures, lastDeliveryAt, lastFailureAt, lastError).

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "webhookId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The webhook id (UUID)."
    }
  },
  "required": [
    "webhookId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡create_webhook(name, url, events)

Create an outbound webhook that Ray POSTs signed event payloads to (POST /tenant-webhooks; write scope; Pro plan or higher, otherwise 403). The URL must be public HTTPS. The response contains the signing `secret` exactly once: show it to the user to store (e.g. as an env var), since it can't be read again, only rotated with update_webhook. Read the `webhooks` docs page for the signature scheme.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100,
      "description": "Label for the webhook, e.g. \"Production delivery events\"."
    },
    "url": {
      "type": "string",
      "description": "Public HTTPS endpoint that will receive the events."
    },
    "events": {
      "minItems": 1,
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "notification.delivered",
          "notification.failed_terminal",
          "send.completed"
        ]
      },
      "description": "Events to receive: \"notification.delivered\", \"notification.failed_terminal\" (one per recipient), and \"send.completed\" (once per send, with status totals)."
    }
  },
  "required": [
    "name",
    "url",
    "events"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡update_webhook(webhookId, name, url, events, enabled, ...)

Change a webhook (PATCH /tenant-webhooks/{id}; write scope). Only the fields you pass change; pass at least one. `rotateSecret: true` issues a new signing secret, returned once in the response, and the old secret stops verifying immediately, so the receiving service must be updated at the same time.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "webhookId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The webhook id (UUID)."
    },
    "name": {
      "description": "New label.",
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "url": {
      "description": "New public HTTPS endpoint.",
      "type": "string"
    },
    "events": {
      "description": "Replaces the subscribed events. Events to receive: \"notification.delivered\", \"notification.failed_terminal\" (one per recipient), and \"send.completed\" (once per send, with status totals).",
      "minItems": 1,
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "notification.delivered",
          "notification.failed_terminal",
          "send.completed"
        ]
      }
    },
    "enabled": {
      "description": "false pauses deliveries without deleting the webhook.",
      "type": "boolean"
    },
    "rotateSecret": {
      "description": "true rotates the signing secret (new secret returned once; old one invalid immediately).",
      "type": "boolean"
    }
  },
  "required": [
    "webhookId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🔴delete_webhook(webhookId)

Delete (archive) a webhook so it receives no more events (DELETE /tenant-webhooks/{id}; write scope). It cannot be restored through the API; confirm with the user first.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "webhookId": {
      "type": "string",
      "format": "uuid",
      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
      "description": "The webhook id (UUID)."
    }
  },
  "required": [
    "webhookId"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢read_docs(slug)

Read Ray's documentation as markdown. With no `slug` it returns the index (llms.txt) listing every page; then pass a page slug, i.e. the path after /docs/ without `.md`, such as `sending`, `templates`, `idempotency`, `errors`, `rate-limits`, `webhooks`, `status-and-feeds` or `channels/telegram`. Use it for anything the tool descriptions don't cover.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "slug": {
      "description": "Page slug like \"sending\" or \"channels/push-fcm\". Omit for the index of all pages.",
      "type": "string",
      "maxLength": 100
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}

Community

Diesen Server bewerten

Nachweis

Aktuelle Beobachtungen

verifiziertVersion nicht aufgezeichnet21 Tools
verifiziertVersion nicht aufgezeichnet21 Tools
verifiziertVersion nicht aufgezeichnet21 Tools