Skip to main content
Glama

Groundbase

campaigns_manage

CRUD + send-control verbs for marketing campaigns (email or SMS, single send for v1). Use action='list' to see what's there; action='create' to author a new draft; action='update' to modify a draft (only allowed when status is draft/scheduled/paused); action='send_now' to dispatch immediately to the audience; action='test_send' to fire a single message to one address for preview. Drip campaigns: pass send_mode='drip' plus steps. Single sends use content. get/list return steps, sending_window, send_mode and scheduled_at so a session can audit what is configured without the UI. 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.}}. Unknown tags render empty. 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. 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. 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 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.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
qNoFree-text name search for action=list.
idNoCampaign UUID — required for everything except list+create.
toNoFor action='test_send' — recipient email or phone.
nameNo
limitNo
stepsNoFor 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.
actionYes'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.
statusNoFilter for action=list.
channelNo
contentNoFor 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.
send_modeNo
contact_idsNoFor add_recipients: contact ids, at most 500.
scheduled_atNoUnix seconds for schedule/create.
enrolment_modeNoFor 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.
sending_windowNoFor 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.
audience_filterNoFor 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.

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observed

TDQS

A4.7/5.0
Behavior5/5

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

With no annotations, the description carries the full behavioral burden and delivers: soft-delete semantics, update-only-when-draft/scheduled/paused, sending_window waits instead of failing, reply-exit blindness with unconnected reply_to addresses, the content_json/content alias bug, unverified-domain failure at send time, and ongoing-vs-once enrollment behavior. These are material operational traits that no schema or annotation would convey.

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?

The description is long, but it is deliberately organized into action routing, content format, steps, sending window, and audience filter. Front-loading the action verbs helps orientation. The historical note about the content/content_json bug and some duplicated schema prose could be trimmed, but the complexity of the tool justifies most of the length.

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

Completeness5/5

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

For a 16-parameter tool with nested objects, no annotations, and no output schema, the description is unusually complete. It explains not just what parameters mean but how behaviors play out — what waits, what skips, what fails, and what returns enough fields to audit a campaign. The only notable omission is a full output/return contract for create/send actions, but the described behaviors cover practical calling needs.

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

Parameters5/5

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

Schema coverage is 75%, yet the description still adds substantial meaning beyond the schema: block formats for email/SMS, merge-tag behavior, step delay semantics, exit_on conditions, audience_filter rule shapes, sending_window timezone behavior, and add_recipients behavior. It effectively documents the nested object structures that the schema only names.

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

Purpose5/5

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

Opens with 'CRUD + send-control verbs for marketing campaigns (email or SMS, single send for v1)' — a specific verb category and resource. The explicit action list (list, create, update, send_now, test_send) makes the tool's job unambiguous and separates it from analytics/recipient-list siblings.

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?

The description explicitly routes each action ('Use action='list' to see what's there; action='create' to author...') and gives cross-tool prerequisites like 'call resend_manage(action='domains') first'. It also states status restrictions and drip-mode requirements. It does not explicitly compare against campaigns_preview_audience or campaigns_list_recipients, so it stops short of complete alternative routing.

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