{"id":221267,"recorded_at":"2026-10-26T15:07:14.340964Z","observed_at":"2026-10-26T15:07:14.340786Z","subject_kind":"endpoint","subject":"9e97907e-8c2c-4962-836f-58914a77ab83","kind":"mcp.tools","method":"probe.mcp/1","body":{"count":21,"tools":[{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"templateId":{"description":"The template id (UUID).","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)$","type":"string"}},"required":["templateId"],"type":"object"},"name":"archive_template"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"channelKind":{"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.","enum":["email_html","fcm_basic","slack_text","discord_text","telegram_text","sms_text","webhook_json"],"type":"string"},"content":{"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.","propertyNames":{"type":"string"},"type":"object"},"folder":{"description":"Optional folder path for organisation, e.g. \"billing\".","maxLength":200,"type":"string"},"logDescription":{"description":"One-line description for the in-app feed and delivery logs. Placeholders allowed.","maxLength":2000,"minLength":1,"type":"string"},"logTitle":{"description":"Short title shown in the in-app feed and delivery logs, e.g. \"Invoice {{number}} is due\". Placeholders allowed.","maxLength":500,"minLength":1,"type":"string"},"name":{"description":"Template name, unique per workspace (archived templates included).","maxLength":100,"minLength":1,"type":"string"},"paramOverrides":{"additionalProperties":{"properties":{"description":{"maxLength":500,"type":"string"},"optional":{"type":"boolean"}},"type":"object"},"description":"Per-param metadata keyed by param name: `{ optional?: boolean, description?: string }`. Mark a placeholder optional so sends may omit it.","propertyNames":{"type":"string"},"type":"object"},"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"],"type":"object"},"name":"create_template"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"events":{"description":"Events to receive: \"notification.delivered\", \"notification.failed_terminal\" (one per recipient), and \"send.completed\" (once per send, with status totals).","items":{"enum":["notification.delivered","notification.failed_terminal","send.completed"],"type":"string"},"minItems":1,"type":"array"},"name":{"description":"Label for the webhook, e.g. \"Production delivery events\".","maxLength":100,"minLength":1,"type":"string"},"url":{"description":"Public HTTPS endpoint that will receive the events.","type":"string"}},"required":["name","url","events"],"type":"object"},"name":"create_webhook"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"webhookId":{"description":"The webhook id (UUID).","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)$","type":"string"}},"required":["webhookId"],"type":"object"},"name":"delete_webhook"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"campaignId":{"description":"The `campaignId` passed to send_notification, to total clicks across many sends.","maxLength":256,"minLength":1,"type":"string"},"sendId":{"description":"A sendId from send_notification.","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)$","type":"string"}},"type":"object"},"name":"get_click_stats"},{"description":"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`.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"cursor":{"description":"`nextCursor` from the previous page.","minLength":1,"type":"string"},"limit":{"description":"Rows per page (default 50, max 200).","maximum":200,"minimum":1,"type":"integer"},"sendId":{"description":"The `sendId` returned by send_notification or test_send_template.","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)$","type":"string"}},"required":["sendId"],"type":"object"},"name":"get_send_status"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"templateId":{"description":"The template id (UUID).","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)$","type":"string"}},"required":["templateId"],"type":"object"},"name":"get_template"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{},"type":"object"},"name":"get_usage"},{"description":"Get one outbound webhook (GET /tenant-webhooks/{id}) including its delivery health (consecutiveFailures, lastDeliveryAt, lastFailureAt, lastError).","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"webhookId":{"description":"The webhook id (UUID).","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)$","type":"string"}},"required":["webhookId"],"type":"object"},"name":"get_webhook"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{},"type":"object"},"name":"list_channels"},{"description":"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`.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"after":{"description":"Only entries created after this ISO 8601 UTC datetime (e.g. \"2026-09-01T00:00:00Z\").","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))$","type":"string"},"before":{"description":"Only entries created before this ISO 8601 UTC datetime.","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))$","type":"string"},"channelConfigId":{"description":"Only entries whose first delivery used this channel.","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)$","type":"string"},"cursor":{"description":"`nextCursor` from the previous page.","minLength":1,"type":"string"},"externalUserId":{"description":"The end user whose feed to read (the `externalUserId` used when sending).","maxLength":256,"minLength":1,"type":"string"},"limit":{"description":"Entries per page (default 50, max 200).","maximum":200,"minimum":1,"type":"integer"},"templateId":{"description":"Only entries from this template.","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)$","type":"string"}},"required":["externalUserId"],"type":"object"},"name":"list_feed_notifications"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"folder":{"description":"Only templates in this folder.","maxLength":200,"type":"string"},"includeArchived":{"description":"Include archived templates. Default false.","type":"boolean"}},"type":"object"},"name":"list_templates"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"includeArchived":{"description":"Include deleted (archived) webhooks. Default false.","type":"boolean"}},"type":"object"},"name":"list_webhooks"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"templateId":{"description":"The template id (UUID).","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)$","type":"string"}},"required":["templateId"],"type":"object"},"name":"publish_template"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"slug":{"description":"Page slug like \"sending\" or \"channels/push-fcm\". Omit for the index of all pages.","maxLength":100,"type":"string"}},"type":"object"},"name":"read_docs"},{"description":"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:\n1. Single: `channelConfigId` + `recipient`.\n2. Fan-out: `channelConfigId` + `targets` (1-1000 `{ recipient, externalUserId? }`), one channel, one sendId.\n3. 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.\n4. Feed-only: `feed` (with `title`) + `externalUserId` and no channel: an in-app notification only.\nIn 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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"campaignId":{"description":"Free-form campaign id used to group click stats across sends.","maxLength":256,"minLength":1,"type":"string"},"channelConfigId":{"description":"Modes 1-2: the channel to send through — an `id` from list_channels. Not allowed together with `deliveries`.","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)$","type":"string"},"content":{"additionalProperties":{},"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.","propertyNames":{"type":"string"},"type":"object"},"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.","items":{"properties":{"channelConfigId":{"description":"Channel for this delivery (from list_channels).","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)$","type":"string"},"content":{"additionalProperties":{},"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.","propertyNames":{"type":"string"},"type":"object"},"logDescription":{"description":"Feed/log description; only valid with inline `content`.","maxLength":2000,"type":"string"},"logTitle":{"description":"Feed/log title; only valid with inline `content`.","maxLength":500,"type":"string"},"params":{"additionalProperties":{},"description":"Params for this delivery; falls back to the top-level `params`.","propertyNames":{"type":"string"},"type":"object"},"recipient":{"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?: [...], from?: { email?, name? } (per-send sender override; omitted fields fall back to the channel config; email must be on exactly the domain of the config fromAddress, subdomains rejected), replyTo?: [{ email, name? }], headers?: { \"X-Name\": \"value\" } (ASCII, max 15; From/To/Cc/Bcc/Reply-To/Subject etc. and provider controls such as X-SES-*/X-SMTPAPI/X-PM-*/X-Mailgun-* rejected), 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).","propertyNames":{"type":"string"},"type":"object"},"templateId":{"description":"Published template for this delivery. Exactly one of `templateId` or `content`.","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)$","type":"string"}},"required":["channelConfigId","recipient"],"type":"object"},"maxItems":10,"minItems":1,"type":"array"},"externalUserId":{"description":"Your own id for the end user. Required with `feed`; keys their in-app feed.","maxLength":256,"minLength":1,"type":"string"},"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).","properties":{"description":{"maxLength":2000,"type":"string"},"title":{"maxLength":500,"type":"string"}},"type":"object"},"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.","maxLength":255,"minLength":1,"type":"string"},"logDescription":{"description":"Feed/log description for inline `content` sends only. Placeholders allowed.","maxLength":2000,"type":"string"},"logTitle":{"description":"Feed/log title for inline `content` sends only (template sends take it from the template). Placeholders allowed.","maxLength":500,"type":"string"},"notBefore":{"description":"Schedule delivery for later: ISO 8601 datetime with offset, e.g. \"2026-09-15T09:00:00+08:00\". Omit to send now.","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)))$","type":"string"},"params":{"additionalProperties":{},"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.","propertyNames":{"type":"string"},"type":"object"},"priority":{"description":"\"high\" (default) for transactional messages; \"low\" for marketing/bulk so it never delays transactional sends.","enum":["high","low"],"type":"string"},"recipient":{"additionalProperties":{},"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?: [...], from?: { email?, name? } (per-send sender override; omitted fields fall back to the channel config; email must be on exactly the domain of the config fromAddress, subdomains rejected), replyTo?: [{ email, name? }], headers?: { \"X-Name\": \"value\" } (ASCII, max 15; From/To/Cc/Bcc/Reply-To/Subject etc. and provider controls such as X-SES-*/X-SMTPAPI/X-PM-*/X-Mailgun-* rejected), 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).","propertyNames":{"type":"string"},"type":"object"},"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"},"targets":{"description":"Mode 2: fan-out to 1-1000 recipients over ONE channel, sharing one sendId. Mutually exclusive with `recipient`.","items":{"properties":{"externalUserId":{"description":"Your own id for this recipient. With `feed`/`showInFeed` they also get an in-app feed entry.","maxLength":256,"minLength":1,"type":"string"},"recipient":{"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?: [...], from?: { email?, name? } (per-send sender override; omitted fields fall back to the channel config; email must be on exactly the domain of the config fromAddress, subdomains rejected), replyTo?: [{ email, name? }], headers?: { \"X-Name\": \"value\" } (ASCII, max 15; From/To/Cc/Bcc/Reply-To/Subject etc. and provider controls such as X-SES-*/X-SMTPAPI/X-PM-*/X-Mailgun-* rejected), 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).","propertyNames":{"type":"string"},"type":"object"}},"required":["recipient"],"type":"object"},"maxItems":1000,"minItems":1,"type":"array"},"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`.","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)$","type":"string"},"trackClicks":{"description":"Email channels only: rewrite links in bodyHtml so clicks are counted (read with get_click_stats). Default false.","type":"boolean"}},"type":"object"},"name":"send_notification"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"channelConfigId":{"description":"Channel to test through (from list_channels); its templateKind must match the template's channelKind.","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)$","type":"string"},"params":{"additionalProperties":{},"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.","propertyNames":{"type":"string"},"type":"object"},"recipient":{"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?: [...], from?: { email?, name? } (per-send sender override; omitted fields fall back to the channel config; email must be on exactly the domain of the config fromAddress, subdomains rejected), replyTo?: [{ email, name? }], headers?: { \"X-Name\": \"value\" } (ASCII, max 15; From/To/Cc/Bcc/Reply-To/Subject etc. and provider controls such as X-SES-*/X-SMTPAPI/X-PM-*/X-Mailgun-* rejected), 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).","propertyNames":{"type":"string"},"type":"object"},"templateId":{"description":"The template id (UUID).","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)$","type":"string"}},"required":["templateId","channelConfigId","recipient"],"type":"object"},"name":"test_send_template"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"templateId":{"description":"The template id (UUID).","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)$","type":"string"}},"required":["templateId"],"type":"object"},"name":"unarchive_template"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"channelKind":{"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.","enum":["email_html","fcm_basic","slack_text","discord_text","telegram_text","sms_text","webhook_json"],"type":"string"},"content":{"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.","propertyNames":{"type":"string"},"type":"object"},"folder":{"description":"Optional folder path for organisation, e.g. \"billing\".","maxLength":200,"type":"string"},"logDescription":{"description":"One-line description for the in-app feed and delivery logs. Placeholders allowed.","maxLength":2000,"minLength":1,"type":"string"},"logTitle":{"description":"Short title shown in the in-app feed and delivery logs, e.g. \"Invoice {{number}} is due\". Placeholders allowed.","maxLength":500,"minLength":1,"type":"string"},"name":{"description":"Template name, unique per workspace (archived templates included).","maxLength":100,"minLength":1,"type":"string"},"paramOverrides":{"additionalProperties":{"properties":{"description":{"maxLength":500,"type":"string"},"optional":{"type":"boolean"}},"type":"object"},"description":"Per-param metadata keyed by param name: `{ optional?: boolean, description?: string }`. Mark a placeholder optional so sends may omit it.","propertyNames":{"type":"string"},"type":"object"},"publish":{"description":"true = publish this version immediately so sends by templateId use it. Default false (saved as draft).","type":"boolean"},"templateId":{"description":"The template id (UUID).","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)$","type":"string"}},"required":["templateId","name","channelKind","content","logTitle","logDescription"],"type":"object"},"name":"update_template_draft"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{"enabled":{"description":"false pauses deliveries without deleting the webhook.","type":"boolean"},"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).","items":{"enum":["notification.delivered","notification.failed_terminal","send.completed"],"type":"string"},"minItems":1,"type":"array"},"name":{"description":"New label.","maxLength":100,"minLength":1,"type":"string"},"rotateSecret":{"description":"true rotates the signing secret (new secret returned once; old one invalid immediately).","type":"boolean"},"url":{"description":"New public HTTPS endpoint.","type":"string"},"webhookId":{"description":"The webhook id (UUID).","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)$","type":"string"}},"required":["webhookId"],"type":"object"},"name":"update_webhook"},{"description":"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.","inputSchema":{"$schema":"http://json-schema.org/draft-07/schema#","properties":{},"type":"object"},"name":"whoami"}]},"body_sha256":"541eef29417c9ec07dc90c700747211d882408a5a1106b860cb81c3a8d72c233","prev_id":null,"leaf":"0x01ef523672bc2e31dbb95f8a526438bc7b16ac239dbf0da3502cf5bbf715f69d","leaf_text":"{\"body\":\"541eef29417c9ec07dc90c700747211d882408a5a1106b860cb81c3a8d72c233\",\"id\":221267,\"kind\":\"mcp.tools\",\"method\":\"probe.mcp/1\",\"observed_us\":1793027234340786,\"prev\":null,\"subject\":\"9e97907e-8c2c-4962-836f-58914a77ab83\",\"subject_kind\":\"endpoint\"}","day":{"day":"2026-10-26","leaves":296695,"root":"0xf43e8dcc3d451a4788b26be904c55e8c4c0fa75c9666796c51db38d37e2c0df8","chained":"0x702d5ac508f08b0d1accf36af25822d8e5660367494edd17a642fb61e158a57a","anchor_chain":"eip155:5042002","anchor_tx":"0x495162f8936e19f0039918feebe6c307f327cd6bf8c37219620b1970041fa9ae","anchor_block":69251483},"proof":["0x01ef6a7deb93189211840c2eb3666da37d937d94a3e13ab790a4ac746ea67319","0xeb7edaf854aa664a78e38e3a3071b1feb6689f75637bca3298ffd81169ba6b16","0x63e74d36d24e7322c9dc09f428c7a54ca8349756e7120dc00adb7921ba0a708f","0x12deba8bf78a5745a0616b1439c7b348d7ad056a0516c8dc25c3590469bb4f19","0x74c9ea4a4ddcec5d118b57620a19811a5b0fe9b16f249309862d0ea0407015f4","0x33fd6648633233936bfef03ae69b386c3086d60efeff1dc54d78ff9afb156f57","0x62cb7ea79920c8be33ba6c0ad5d163b945cce94daa58018116a9f0eb5162fe43","0x0451a97eb9042c698e9901e1c19be7893e3d938ae0dd71404fa28f7469d4a1be","0xc1892e1f31516991ebd2b68b1883c63619880797be155d4c7f6ef90340e294aa","0xb59ab9723c94bb11211a69aab135061f373122c6fca8c5dbfd525237ac1ef164","0x588f372bbaaf730e538542f070b005c0dd23fdb8c7f43a940481de0c1681aae1","0xd75ede2689ed83bbc8980becaf4f32a77c7e05567790cd351e997bb28aa0844c","0x92ff7d176556ddbe3d885e2ab73948b14a6aa3568a8fd237427d4f8415235a23","0xd1d3499072edb10edc68f84bcae2365d2ab534df689250cab18c751b6f13b6ff","0x7ddc2fead128357f881b63e6c7c26d7fbbb84fca6c7c8e0bbfe386de86ca8d39","0xc6a4d7899a0f442958e26505011190b7cff2483611c1b94eba9043e0ba9ac36e","0x8c756542e482157df0c36464d75c937b845e4423dbbcfad08f0cf8d5a16b9a13","0x20704208aa6923d6b2450ef74ede87a6e0265d46447926038fe9506e9e154b2d","0x9b9ce5b74b9bab5121612ef6b64920a8d453cbf311096a423eef9702747e868a"]}