@sendinel/mcp-server 1.0.148 → 1.0.150

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.
@@ -92,6 +92,8 @@ export const API_USAGE_ERROR_CODE_MAP = {
92
92
  'unprocessable_entity': 'validation_failed',
93
93
  'validation': 'validation_failed',
94
94
  'validation_failed': 'validation_failed',
95
+ 'approval_not_cancellable': 'conflict',
96
+ 'approval_not_pending': 'conflict',
95
97
  '23505': 'conflict',
96
98
  'conflict': 'conflict',
97
99
  'content_changed_since_approval': 'conflict',
@@ -131,7 +133,10 @@ export const API_USAGE_ERROR_CODE_MAP = {
131
133
  'activation_failed': 'internal_error',
132
134
  'ai_not_configured': 'internal_error',
133
135
  'ai_unavailable': 'internal_error',
136
+ 'approval_audit_failed': 'internal_error',
137
+ 'approval_failed': 'internal_error',
134
138
  'approval_lookup_failed': 'internal_error',
139
+ 'approval_update_failed': 'internal_error',
135
140
  'audience_lookup_failed': 'internal_error',
136
141
  'campaign_create_failed': 'internal_error',
137
142
  'campaign_lookup_failed': 'internal_error',
@@ -2936,7 +2936,7 @@ Do not include body_html in your response; Sendinel renders body_html from block
2936
2936
  : row.status === 'expired' ? 'no_reply_by_deadline'
2937
2937
  : 'unknown',
2938
2938
  }));
2939
- return j({ items, count: items.length });
2939
+ return j({ items, count: items.length, truncated: items.length === limit });
2940
2940
  });
2941
2941
  server.registerTool('validate_template', {
2942
2942
  title: 'Validate Template',
@@ -341,7 +341,7 @@ export function registerDeliveryOpsTools(server) {
341
341
  if (error)
342
342
  return j(dbToolError(error));
343
343
  const failed = (data ?? []).filter((row) => row.status === 'failed');
344
- return j({ runs: data ?? [], recent_failures: failed.length, total: data?.length ?? 0 });
344
+ return j({ runs: data ?? [], recent_failures: failed.length, total: data?.length ?? 0, truncated: (data?.length ?? 0) === limit });
345
345
  });
346
346
  server.registerTool('get_queue_status', {
347
347
  title: 'Get Queue Status',
@@ -406,7 +406,7 @@ export function registerDeliveryOpsTools(server) {
406
406
  const { data, error } = await query;
407
407
  if (error)
408
408
  return j(dbToolError(error));
409
- return j({ dlq: data ?? [], count: data?.length ?? 0 });
409
+ return j({ dlq: data ?? [], count: data?.length ?? 0, truncated: (data?.length ?? 0) === limit });
410
410
  });
411
411
  server.registerTool('get_enrollment_dlq', {
412
412
  title: 'Get Enrollment DLQ',
@@ -436,7 +436,7 @@ export function registerDeliveryOpsTools(server) {
436
436
  const { data, error } = await query;
437
437
  if (error)
438
438
  return j(dbToolError(error));
439
- return j({ dlq: data ?? [], count: data?.length ?? 0 });
439
+ return j({ dlq: data ?? [], count: data?.length ?? 0, truncated: (data?.length ?? 0) === limit });
440
440
  });
441
441
  server.registerTool('get_send_queue_rows', {
442
442
  title: 'Get Send Queue Rows',
@@ -110,7 +110,7 @@ export function registerGdprTools(server) {
110
110
  .limit(limit ?? 50);
111
111
  if (error)
112
112
  return txt(`Error: ${dbToolError(error).error}`);
113
- return j({ requests: data ?? [], count: data?.length ?? 0 });
113
+ return j({ requests: data ?? [], count: data?.length ?? 0, truncated: (data?.length ?? 0) === (limit ?? 50) });
114
114
  });
115
115
  server.registerTool('action_ccpa_request', {
116
116
  title: 'Action CCPA Request',
@@ -183,7 +183,7 @@ export function registerNewsletterTools(server) {
183
183
  const { data, error } = await query;
184
184
  if (error)
185
185
  return j(dbToolError(error));
186
- return j({ newsletters: data ?? [], count: data?.length ?? 0 });
186
+ return j({ newsletters: data ?? [], count: data?.length ?? 0, truncated: (data?.length ?? 0) === limit });
187
187
  });
188
188
  server.registerTool('get_newsletter', {
189
189
  title: 'Get Newsletter',
@@ -376,7 +376,7 @@ export function registerNewsletterTools(server) {
376
376
  const { data, error } = await query;
377
377
  if (error)
378
378
  return j(dbToolError(error));
379
- return j({ issues: data ?? [], count: data?.length ?? 0 });
379
+ return j({ issues: data ?? [], count: data?.length ?? 0, truncated: (data?.length ?? 0) === limit });
380
380
  });
381
381
  server.registerTool('schedule_newsletter_issue', {
382
382
  title: 'Schedule Newsletter Issue',
@@ -587,7 +587,7 @@ export function registerNewsletterTools(server) {
587
587
  const { data, error } = await query;
588
588
  if (error)
589
589
  return j(dbToolError(error));
590
- return j({ subscribers: data ?? [], count: data?.length ?? 0 });
590
+ return j({ subscribers: data ?? [], count: data?.length ?? 0, truncated: (data?.length ?? 0) === limit });
591
591
  });
592
592
  server.registerTool('get_newsletter_stats', {
593
593
  title: 'Get Newsletter Stats',
@@ -107,9 +107,9 @@ export function registerShortLinkTools(server) {
107
107
  return j(dbToolError(linkError));
108
108
  if (!link)
109
109
  return j({ error: 'Short link not found', code: 'not_found' });
110
- const { data: clicks, error: clickError } = await db()
110
+ const { data: clicks, error: clickError, count: total } = await db()
111
111
  .from('short_link_clicks')
112
- .select('clicked_at, ip_hash, referer')
112
+ .select('clicked_at, ip_hash, referer', { count: 'exact' })
113
113
  .eq('short_link_id', short_link_id)
114
114
  .order('clicked_at', { ascending: false })
115
115
  .limit(500);
@@ -118,7 +118,9 @@ export function registerShortLinkTools(server) {
118
118
  const uniqueClicks = new Set((clicks ?? []).map((click) => click.ip_hash).filter(Boolean)).size;
119
119
  return j({
120
120
  short_link: link,
121
- total_clicks: link.click_count ?? clicks?.length ?? 0,
121
+ total_clicks: link.click_count ?? total ?? clicks?.length ?? 0,
122
+ ...(total != null ? { total } : {}),
123
+ truncated: (clicks?.length ?? 0) === 500,
122
124
  unique_clicks: uniqueClicks,
123
125
  recent_clicks: clicks ?? [],
124
126
  });
@@ -140,7 +140,7 @@ export function registerSurveyTools(server) {
140
140
  status: z.enum(['draft', 'active', 'closed']).optional(),
141
141
  limit: z.number().int().min(1).max(200).optional().default(50),
142
142
  },
143
- }, async ({ status, limit }) => {
143
+ }, async ({ status, limit = 50 }) => {
144
144
  const projectId = getProjectId();
145
145
  let query = db().from('surveys').select('id, title, status, short_link_id, created_at, updated_at').eq('project_id', projectId).order('created_at', { ascending: false }).limit(limit);
146
146
  if (status)
@@ -148,7 +148,7 @@ export function registerSurveyTools(server) {
148
148
  const { data, error } = await query;
149
149
  if (error)
150
150
  return j(dbToolError(error));
151
- return j({ surveys: data ?? [], count: data?.length ?? 0 });
151
+ return j({ surveys: data ?? [], count: data?.length ?? 0, truncated: (data?.length ?? 0) === limit });
152
152
  });
153
153
  server.registerTool('get_survey', {
154
154
  title: 'Get Survey',
@@ -93,7 +93,7 @@ export function registerTemplateTools(server) {
93
93
  const { data, error } = await query;
94
94
  if (error)
95
95
  return j(dbToolError(error));
96
- return j({ templates: data ?? [], count: data?.length ?? 0 });
96
+ return j({ templates: data ?? [], count: data?.length ?? 0, truncated: (data?.length ?? 0) === limit });
97
97
  });
98
98
  server.registerTool('translate_template', {
99
99
  title: 'Translate Template',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendinel/mcp-server",
3
- "version": "1.0.148",
3
+ "version": "1.0.150",
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",