@sendinel/mcp-server 1.0.156 → 1.0.158

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3553,7 +3553,7 @@ Return ONLY valid JSON with this exact shape:
3553
3553
  server.registerTool('set_campaign_trigger', {
3554
3554
  title: 'Set Campaign Trigger',
3555
3555
  annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
3556
- description: 'Set or clear what a campaign fires on: trigger event name, tag, date_field, contact_event, or trigger_config events/tags and where event-data filter. Bind billing, payment failed, dunning or trial ending mail to an event trigger such as invoice_payment_failed or trial_ending. Drafts save directly; active/paused campaigns require standard human approval. Archived/completed campaigns cannot change. Returns saved trigger fields, derived trigger_kind, fires_on and trigger_diagnostics (including unseen-event warnings).',
3556
+ description: 'Send timing: the first step of an event-triggered product journey sends right away; later steps wait for the site send window (contact zone, then campaign zone, then UTC). Set or clear what a campaign fires on: trigger event name, tag, date_field, contact_event, or trigger_config events/tags and where event-data filter. Bind billing, payment failed, dunning or trial ending mail to an event trigger such as invoice_payment_failed or trial_ending. Drafts save directly; active/paused campaigns require standard human approval. Archived/completed campaigns cannot change. Returns saved trigger fields, derived trigger_kind, fires_on and trigger_diagnostics (including unseen-event warnings).',
3557
3557
  inputSchema: {
3558
3558
  ...reentryFields,
3559
3559
  campaign_id: z.string().uuid().optional(),
@@ -193,6 +193,7 @@ export function registerSiteTools(server) {
193
193
  name: z.string().optional(),
194
194
  from_email: z.string().email().optional(),
195
195
  from_name: z.string().optional(),
196
+ reply_to: z.string().email().nullable().optional().describe('Where replies to this site\'s email go; null clears it (replies then go to the From address). The previous value is returned as previous_reply_to.'),
196
197
  active: z.boolean().optional(),
197
198
  physical_address: z.string().trim().min(1).optional().describe('Physical mailing address; unchanged unless explicitly supplied.'),
198
199
  unsub_link_enabled: z.boolean().optional().describe('Enable the unsubscribe link in the email footer.'),
@@ -203,7 +204,7 @@ export function registerSiteTools(server) {
203
204
  unsub_brand_logo_url: z.string().nullable().optional().describe('HTTP(S) unsubscribe page logo URL; null or blank clears it.'),
204
205
  unsub_brand_color: z.string().nullable().optional().describe('Six-digit hex unsubscribe page color; null or blank clears it.'),
205
206
  },
206
- }, async ({ site_id, name, from_email, from_name, active, physical_address, ...unsubscribeInput }) => {
207
+ }, async ({ site_id, name, from_email, from_name, reply_to, active, physical_address, ...unsubscribeInput }) => {
207
208
  const updates = {};
208
209
  if (name)
209
210
  updates.name = name;
@@ -211,6 +212,8 @@ export function registerSiteTools(server) {
211
212
  updates.from_email = from_email;
212
213
  if (from_name)
213
214
  updates.from_name = from_name;
215
+ if (reply_to !== undefined)
216
+ updates.reply_to = reply_to;
214
217
  if (active !== undefined)
215
218
  updates.active = active;
216
219
  if (physical_address !== undefined)
@@ -238,6 +241,16 @@ export function registerSiteTools(server) {
238
241
  return j({ error: 'Site not found', code: 'NOT_FOUND' });
239
242
  previousTemplate = current.unsub_footer_template;
240
243
  }
244
+ // Read the old reply-to so the response carries the exact undo value.
245
+ let previousReplyTo;
246
+ if (reply_to !== undefined) {
247
+ const { data: current, error } = await sb.from('sites').select('reply_to').eq('id', site_id).eq('project_id', projectId).maybeSingle();
248
+ if (error)
249
+ return txt(`Error: ${dbToolError(error).error}`);
250
+ if (!current)
251
+ return j({ error: 'Site not found', code: 'NOT_FOUND' });
252
+ previousReplyTo = current.reply_to ?? null;
253
+ }
241
254
  updates.updated_at = new Date().toISOString();
242
255
  let query = sb
243
256
  .from('sites')
@@ -259,6 +272,7 @@ export function registerSiteTools(server) {
259
272
  });
260
273
  return j({
261
274
  ...data,
275
+ ...(previousReplyTo !== undefined ? { previous_reply_to: previousReplyTo } : {}),
262
276
  ...(previousTemplate !== undefined && previousTemplate !== data.unsub_footer_template
263
277
  ? { previous_unsub_footer_template: previousTemplate } : {}),
264
278
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendinel/mcp-server",
3
- "version": "1.0.156",
3
+ "version": "1.0.158",
4
4
  "description": "AI-controlled email operations control plane for campaigns, contacts, segments, analytics, and multi-provider sending via MCP.",
5
5
  "mcpName": "ai.sendinel/mcp-server",
6
6
  "type": "module",