Skip to main content
Glama

campaigns_manage

Destructive

Email/SMS campaigns and newsletters. Actions: list (kind=newsletter for newsletters), get, create (draft; template_id starts a newsletter from newsletter_templates), update, delete, duplicate, test_send, send_now, schedule, pause, resume, stop, add_recipients, preview_audience, newsletter_templates. send_now/schedule/resume message real people: confirm first.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
qNolist: name search.
idNoCampaign id; needed for all but list, create, preview_audience.
toNotest_send recipient.
kindNolist filter: newsletters, or everything else.
nameNo
roleNonewsletter_templates: another industry's set (e.g. real estate, mortgage, insurance). Default: the user's own.
limitNo
stepsNoDrip steps (send_mode 'drip'): [{ delay_seconds, content_json, exit_on?, channel? }]. Step 0 sends at start; each later step sends delay_seconds after that recipient's previous actual send. exit_on { reply?, open?, click?, meeting? } skips the rest for a contact who did that. channel overrides the campaign channel for the step.
actionYes
statusNolist filter.
channelNo
contentNoSingle send. Email: { subject, preheader?, from_name?, from_email?, reply_to?, blocks: [{ type, props }] }; block types text {html}, header {html, level 1-3}, image {src, alt, width}, button {text, url, bgColor?}, divider {color?}, spacer {height}. from_email must be on a domain verified in Resend (resend_manage domains) or it fails per recipient at send time. reply_to should be a mailbox connected in Groundbase, or drip reply-exit cannot see replies. SMS: { body, media_urls? }. Merge tags like {{first_name}}, {{cf.<key>}} work in any string. Newsletter: content.kind 'newsletter' (one email, sent once). Extra blocks: section_header {title}; agent_card {photoUrl, name, title, phone, email, website, brokerage, note}; listing_card {imageUrl, status, price, address, beds, baths, sqft, url, buttonText}; market_stats {title, stats:[{label,value,change}], footnote}; quote {quote, author, role, avatarUrl}; footer {businessName, businessAddress, tagline, unsubText}. It will not send until the footer has a real business name and mailing address and no [bracketed] or $— placeholder is left anywhere; the refusal names the first one.
audienceNoduplicate: copy goes only to people the (sent, email) campaign reached who did not open it.
send_modeNo
contact_idsNoadd_recipients: up to 500.
template_idNocreate: start a newsletter from this template (newsletter_templates). name defaults to the template name.
scheduled_atNoUnix seconds.
enrolment_modeNo'once' (default) fixes its audience at start. 'ongoing' keeps sending until stop and takes new entrants (filter re-run every 5 min, add_recipients, workflow add_to_campaign).
sending_windowNo{ days: [0-6, 0=Sunday], start_hour: 0-23, end_hour: 1-24 (exclusive), timezone?: IANA or 'auto' (account tz) }. Sends due outside the window wait for the next open hour. null = no restriction.
audience_filterNo{ all: [rules], any?: [rules] }. Rules: { type: "all_contacts" } or { type: "tag", op: "has"|"has_not", value: "<tag name>" }. all[] ANDs, any[] ORs.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • addedInput schema / properties / contact_ids / maxItems
      Added value: +500
  2. Changed5 schema fields changed
    • changedInput schema / properties / action / enum
      Previous value: -[
      -  "list",
      -  "get",
      -  "create",
      -  "update",
      -  "delete",
      -  "duplicate",
      -  "test_send",
      -  "send_now",
      -  "schedule",
      -  "pause",
      -  "resume",
      -  "stop",
      -  "add_recipients",
      -  "preview_audience"
      -]New value: +[
      +  "list",
      +  "get",
      +  "create",
      +  "update",
      +  "delete",
      +  "duplicate",
      +  "test_send",
      +  "send_now",
      +  "schedule",
      +  "pause",
      +  "resume",
      +  "stop",
      +  "add_recipients",
      +  "preview_audience",
      +  "newsletter_templates"
      +]
    • changedInput schema / properties / content / description
      Previous value: -"Single send. Email: { subject, preheader?, from_name?, from_email?, reply_to?, blocks: [{ type, props }] }; block types text {html}, header {html, level 1-3}, image {src, alt, width}, button {text, url, bgColor?}, divider {color?}, spacer {height}. from_email must be on a domain verified in Resend (resend_manage domains) or it fails per recipient at send time. reply_to should be a mailbox connected in Groundbase, or drip reply-exit cannot see replies. SMS: { body, media_urls? }. Merge tags like {{first_name}}, {{cf.<key>}} work in any string."New value: +"Single send. Email: { subject, preheader?, from_name?, from_email?, reply_to?, blocks: [{ type, props }] }; block types text {html}, header {html, level 1-3}, image {src, alt, width}, button {text, url, bgColor?}, divider {color?}, spacer {height}. from_email must be on a domain verified in Resend (resend_manage domains) or it fails per recipient at send time. reply_to should be a mailbox connected in Groundbase, or drip reply-exit cannot see replies. SMS: { body, media_urls? }. Merge tags like {{first_name}}, {{cf.<key>}} work in any string. Newsletter: content.kind 'newsletter' (one email, sent once). Extra blocks: section_header {title}; agent_card {photoUrl, name, title, phone, email, website, brokerage, note}; listing_card {imageUrl, status, price, address, beds, baths, sqft, url, buttonText}; market_stats {title, stats:[{label,value,change}], footnote}; quote {quote, author, role, avatarUrl}; footer {businessName, businessAddress, tagline, unsubText}. It will not send until the footer has a real business name and mailing address and no [bracketed] or $— placeholder is left anywhere; the refusal names the first one."
    • addedInput schema / properties / kind
      Added value: +{
      +  "description": "list filter: newsletters, or everything else.",
      +  "enum": [
      +    "newsletter",
      +    "campaign"
      +  ],
      +  "type": "string"
      +}
    • addedInput schema / properties / role
      Added value: +{
      +  "description": "newsletter_templates: another industry's set (e.g. real estate, mortgage, insurance). Default: the user's own.",
      +  "type": "string"
      +}
    • addedInput schema / properties / template_id
      Added value: +{
      +  "description": "create: start a newsletter from this template (newsletter_templates). name defaults to the template name.",
      +  "type": "string"
      +}
  3. Changed1 schema field changed
    • addedInput schema / properties / audience
      Added value: +{
      +  "description": "duplicate: copy goes only to people the (sent, email) campaign reached who did not open it.",
      +  "enum": [
      +    "non_openers"
      +  ],
      +  "type": "string"
      +}
  4. Changed18 schema fields changed
    • removedInput schema / properties / action / description
      Removed value: -"'list' returns user's campaigns. 'get' returns one by id. 'create' makes a draft (requires name + channel). 'update' patches a draft. 'delete' soft-deletes. 'duplicate' clones as a draft. 'test_send' fires one message to `to` without queuing recipients. 'send_now' resolves the audience and queues all recipients for dispatch. 'schedule' sets scheduled_at. 'pause' freezes. 'resume' un-pauses. 'stop' ends an ONGOING campaign (queued people dropped, sent ones kept). 'add_recipients' names contacts on a campaign by id: on a draft, scheduled or paused one they join the audience; on an ongoing campaign that is sending they are queued now, at the first message, under the campaign's rules."
    • changedInput schema / properties / action / enum
      Previous value: -[
      -  "list",
      -  "get",
      -  "create",
      -  "update",
      -  "delete",
      -  "duplicate",
      -  "test_send",
      -  "send_now",
      -  "schedule",
      -  "pause",
      -  "resume",
      -  "stop",
      -  "add_recipients"
      -]New value: +[
      +  "list",
      +  "get",
      +  "create",
      +  "update",
      +  "delete",
      +  "duplicate",
      +  "test_send",
      +  "send_now",
      +  "schedule",
      +  "pause",
      +  "resume",
      +  "stop",
      +  "add_recipients",
      +  "preview_audience"
      +]
    • changedInput schema / properties / audience_filter / description
      Previous value: -"For create/update. `audience_filter` shape: { all: [rules], any?: [rules] }. Rules are {type, ...}. Supported in v1: { type: \"all_contacts\" } — every contact with a valid channel address; { type: \"tag\", op: \"has\" | \"has_not\", value: \"<tag_name>\" } — tag membership filter. Multiple all[] rules AND together; any[] rules OR together. Behavior queries (opened campaign X / clicked X) and custom-field queries arrive in a follow-up."New value: +"{ all: [rules], any?: [rules] }. Rules: { type: \"all_contacts\" } or { type: \"tag\", op: \"has\"|\"has_not\", value: \"<tag name>\" }. all[] ANDs, any[] ORs."
    • changedInput schema / properties / contact_ids / description
      Previous value: -"For add_recipients: contact ids, at most 500."New value: +"add_recipients: up to 500."
    • changedInput schema / properties / content / description
      Previous value: -"For create/update, single-send. `content` for email = { subject, preheader?, from_name?, from_email?, reply_to?, blocks: [...] }. `from_email` may be any address on ANY domain verified in the connected Resend account — call resend_manage(action='domains') first to see which are verified. An unverified domain is not rejected here; it fails later, at send time, per recipient. `reply_to` sets where replies land — use it when replies should go somewhere other than from_email. IMPORTANT for drip campaigns: exit_on:{reply} can only fire for replies Groundbase can SEE, which means an address on a mailbox connected under Settings -> Email. Point reply_to at an unconnected address and the user still gets their replies, but reply-exit stays blind and the drip keeps sending to people who answered. Settable per step as well as per campaign. Each block is { type, props }. Block types: text (props.html: HTML), header (props.html: text, props.level: 1|2|3), image (props.src: url, props.alt, props.width), button (props.text, props.url, props.bgColor?), divider (props.color?), spacer (props.height: px). `content` for SMS = { body: text, media_urls?: [urls] }. Merge tags inside any string field: {{first_name}}, {{last_name}}, {{full_name}}, {{email}}, {{phone}}, {{company_name}}, {{cf.<custom_field_key>}}. Unknown tags render empty."New value: +"Single send. Email: { subject, preheader?, from_name?, from_email?, reply_to?, blocks: [{ type, props }] }; block types text {html}, header {html, level 1-3}, image {src, alt, width}, button {text, url, bgColor?}, divider {color?}, spacer {height}. from_email must be on a domain verified in Resend (resend_manage domains) or it fails per recipient at send time. reply_to should be a mailbox connected in Groundbase, or drip reply-exit cannot see replies. SMS: { body, media_urls? }. Merge tags like {{first_name}}, {{cf.<key>}} work in any string."
    • changedInput schema / properties / enrolment_mode / description
      Previous value: -"For create/update. 'once' (default) settles its audience when it starts and finishes when the last message goes. 'ongoing' stays sending until action='stop' and takes new entrants at any time: the audience filter is re-run every five minutes, add_recipients works while it sends, and a workflow add_to_campaign step can enrol someone. Cannot be changed to 'once' while sending — stop it instead."New value: +"'once' (default) fixes its audience at start. 'ongoing' keeps sending until stop and takes new entrants (filter re-run every 5 min, add_recipients, workflow add_to_campaign)."
    • changedInput schema / properties / id / description
      Previous value: -"Campaign UUID — required for everything except list+create."New value: +"Campaign id; needed for all but list, create, preview_audience."
    • changedInput schema / properties / q / description
      Previous value: -"Free-text name search for action=list."New value: +"list: name search."
    • changedInput schema / properties / scheduled_at / description
      Previous value: -"Unix seconds for schedule/create."New value: +"Unix seconds."
    • changedInput schema / properties / sending_window / description
      Previous value: -"For create/update. `sending_window` restricts when this campaign may send: { days: [0-6, 0=Sunday], start_hour: 0-23, end_hour: 1-24, timezone?: IANA or 'auto' }. end_hour is exclusive and must exceed start_hour. 'auto' (the default) means the account owner's timezone. A step falling due outside the window WAITS — the recipient stays queued and sends at the next open hour. Nothing fails or is skipped. Omit or pass null for no restriction."New value: +"{ days: [0-6, 0=Sunday], start_hour: 0-23, end_hour: 1-24 (exclusive), timezone?: IANA or 'auto' (account tz) }. Sends due outside the window wait for the next open hour. null = no restriction."
    • changedInput schema / properties / status / description
      Previous value: -"Filter for action=list."New value: +"list filter."
    • changedInput schema / properties / steps / description
      Previous value: -"For create/update when send_mode='drip'. `steps` authors a DRIP campaign (requires send_mode='drip'). Array of { delay_seconds, content_json, exit_on?, channel? } in order. `content_json` is the canonical key; `content` is accepted as an alias. Until 2026-08-30 this doc said `content` while the dispatcher read only `content_json`, so steps authored from this description silently sent step 0 every time. Step 0 fires when the campaign starts; every later step fires delay_seconds after THAT recipient's actual previous send, so a step held back by a sending window or the daily cap still spaces correctly. Each step's `content` uses the same block format as the single-send `content` param. `exit_on` is { reply?, open?, click?, meeting? } — when true and the contact has done that since the previous step, the rest of the drip is skipped for them. `channel` overrides the campaign channel for that step alone (mixed email/SMS drips); it also decides whether the step counts against the daily EMAIL cap."New value: +"Drip steps (send_mode 'drip'): [{ delay_seconds, content_json, exit_on?, channel? }]. Step 0 sends at start; each later step sends delay_seconds after that recipient's previous actual send. exit_on { reply?, open?, click?, meeting? } skips the rest for a contact who did that. channel overrides the campaign channel for the step."
    • removedInput schema / properties / steps / items / properties / channel / description
      Removed value: -"Overrides the campaign channel for this step only."
    • changedInput schema / properties / steps / items / properties / content / description
      Previous value: -"Alias for content_json, accepted for compatibility."New value: +"Alias of content_json."
    • changedInput schema / properties / steps / items / properties / content_json / description
      Previous value: -"Message for this step. Same shape as the top-level content param. Canonical key."New value: +"Same shape as content."
    • removedInput schema / properties / steps / items / properties / delay_seconds / description
      Removed value: -"Seconds after the previous step's actual send. Step 0 should be 0."
    • removedInput schema / properties / steps / items / properties / exit_on / description
      Removed value: -"Skip the rest of the drip for a contact who has replied/opened/clicked, or booked a meeting."
    • changedInput schema / properties / to / description
      Previous value: -"For action='test_send' — recipient email or phone."New value: +"test_send recipient."
  5. First observed

TDQS

A3.8/5.0
Behavior4/5

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

Adds traits beyond the annotations: create only produces a draft, and send_now/schedule/resume reach real people so confirmation is required first. Annotations already declare destructiveHint/openWorldHint, so the description's job is smaller, and it delivers the key safety nuance.

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?

Compact and front-loaded: the resource is stated first, then a dense action list, then the one critical warning. The action enumeration is information-dense but each token earns its place for a multi-action tool.

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

Completeness3/5

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

For a 20-parameter, nested-object, 15-action tool with no output schema, the description routes actions adequately and flags the send-confirmation risk, but says nothing about permissions/auth, return shapes for list/get, or what delete destroys. Adequate but with clear gaps.

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 75%, so the schema already documents most parameters and the baseline is 3. The description adds only a couple of action-specific hints (kind=newsletter for list, template_id for create) and does not clarify the other ~20 parameters.

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+resource (manage email/SMS campaigns and newsletters) and enumerates all 15 actions, which lets an agent see the scope immediately. It does not explicitly distinguish itself from near-neighbors like sms_send, email_send, or campaigns_analytics, so sibling differentiation is only implied.

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

Usage Guidelines4/5

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

Provides real context for the tricky actions: 'list (kind=newsletter for newsletters)', 'create (draft; template_id starts a newsletter from newsletter_templates)', and 'send_now/schedule/resume message real people: confirm first'. It stops short of naming alternatives (e.g. when to use sms_send instead) or listing exclusions.

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.

Resources