mcp-resend 1.0.0-1

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.
Files changed (56) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +257 -0
  3. package/data/embeddings.json +245241 -0
  4. package/dist/config/environment.d.ts +152 -0
  5. package/dist/config/environment.d.ts.map +1 -0
  6. package/dist/config/environment.js +217 -0
  7. package/dist/config/environment.js.map +1 -0
  8. package/dist/index.d.ts +13 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +119 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/services/rate-limiter.d.ts +90 -0
  13. package/dist/services/rate-limiter.d.ts.map +1 -0
  14. package/dist/services/rate-limiter.js +267 -0
  15. package/dist/services/rate-limiter.js.map +1 -0
  16. package/dist/services/tool-registry.d.ts +219 -0
  17. package/dist/services/tool-registry.d.ts.map +1 -0
  18. package/dist/services/tool-registry.js +459 -0
  19. package/dist/services/tool-registry.js.map +1 -0
  20. package/dist/tools/docs/embeddings-loader.d.ts +69 -0
  21. package/dist/tools/docs/embeddings-loader.d.ts.map +1 -0
  22. package/dist/tools/docs/embeddings-loader.js +218 -0
  23. package/dist/tools/docs/embeddings-loader.js.map +1 -0
  24. package/dist/tools/docs/errors.d.ts +75 -0
  25. package/dist/tools/docs/errors.d.ts.map +1 -0
  26. package/dist/tools/docs/errors.js +145 -0
  27. package/dist/tools/docs/errors.js.map +1 -0
  28. package/dist/tools/docs/index.d.ts +11 -0
  29. package/dist/tools/docs/index.d.ts.map +1 -0
  30. package/dist/tools/docs/index.js +14 -0
  31. package/dist/tools/docs/index.js.map +1 -0
  32. package/dist/tools/docs/metrics.d.ts +94 -0
  33. package/dist/tools/docs/metrics.d.ts.map +1 -0
  34. package/dist/tools/docs/metrics.js +174 -0
  35. package/dist/tools/docs/metrics.js.map +1 -0
  36. package/dist/tools/docs/search-docs-tool.d.ts +54 -0
  37. package/dist/tools/docs/search-docs-tool.d.ts.map +1 -0
  38. package/dist/tools/docs/search-docs-tool.js +231 -0
  39. package/dist/tools/docs/search-docs-tool.js.map +1 -0
  40. package/dist/tools/docs/types.d.ts +70 -0
  41. package/dist/tools/docs/types.d.ts.map +1 -0
  42. package/dist/tools/docs/types.js +7 -0
  43. package/dist/tools/docs/types.js.map +1 -0
  44. package/dist/tools/docs/vector-search.d.ts +80 -0
  45. package/dist/tools/docs/vector-search.d.ts.map +1 -0
  46. package/dist/tools/docs/vector-search.js +297 -0
  47. package/dist/tools/docs/vector-search.js.map +1 -0
  48. package/dist/tools/index.d.ts +27 -0
  49. package/dist/tools/index.d.ts.map +1 -0
  50. package/dist/tools/index.js +3413 -0
  51. package/dist/tools/index.js.map +1 -0
  52. package/dist/utils/mcp-errors.d.ts +109 -0
  53. package/dist/utils/mcp-errors.d.ts.map +1 -0
  54. package/dist/utils/mcp-errors.js +306 -0
  55. package/dist/utils/mcp-errors.js.map +1 -0
  56. package/package.json +77 -0
@@ -0,0 +1,3413 @@
1
+ /**
2
+ * Tool Definitions for MCP Server
3
+ *
4
+ * Central factory for creating ToolDefinition objects with proper
5
+ * tier and scope assignments per tool-curation.md.
6
+ *
7
+ * @module tools
8
+ */
9
+ import { z } from "zod";
10
+ import { formatResendError, createToolResponse, createValidationError, } from "../utils/mcp-errors.js";
11
+ import { withRateLimitAndRetry } from "../services/rate-limiter.js";
12
+ import { getSearchDocsDefinition, executeSearchDocs, } from "./docs/index.js";
13
+ // ============================================================================
14
+ // Zod Schemas - Core Tools
15
+ // ============================================================================
16
+ const sendEmailSchema = z.object({
17
+ from: z.string().email("Invalid 'from' email address"),
18
+ to: z.union([
19
+ z.string().email("Invalid 'to' email address"),
20
+ z.array(z.string().email("Invalid 'to' email address")),
21
+ ]),
22
+ subject: z.string().min(1, "Subject is required").max(998, "Subject too long"),
23
+ html: z.string().optional(),
24
+ text: z.string().optional(),
25
+ cc: z.union([z.string().email(), z.array(z.string().email())]).optional(),
26
+ bcc: z.union([z.string().email(), z.array(z.string().email())]).optional(),
27
+ reply_to: z.union([z.string().email(), z.array(z.string().email())]).optional(),
28
+ headers: z.record(z.string()).optional(),
29
+ tags: z.array(z.object({ name: z.string(), value: z.string() })).optional(),
30
+ }).refine((data) => data.html || data.text, {
31
+ message: "Either 'html' or 'text' content is required",
32
+ });
33
+ const getEmailSchema = z.object({
34
+ id: z.string().min(1, "Email ID is required"),
35
+ });
36
+ const listEmailsSchema = z.object({
37
+ limit: z.number().int().min(1).max(100).optional(),
38
+ cursor: z.string().optional(),
39
+ });
40
+ const getDomainSchema = z.object({
41
+ id: z.string().min(1, "Domain ID is required"),
42
+ });
43
+ // ============================================================================
44
+ // Zod Schemas - Secondary Tools (Domain)
45
+ // ============================================================================
46
+ const createDomainSchema = z.object({
47
+ name: z.string().min(1, "Domain name is required"),
48
+ region: z.enum(["us-east-1", "eu-west-1", "sa-east-1", "ap-northeast-1"]).optional(),
49
+ });
50
+ const updateDomainSchema = z.object({
51
+ id: z.string().min(1, "Domain ID is required"),
52
+ openTracking: z.boolean().optional(),
53
+ clickTracking: z.boolean().optional(),
54
+ tls: z.enum(["enforced", "opportunistic"]).optional(),
55
+ });
56
+ const verifyDomainSchema = z.object({
57
+ id: z.string().min(1, "Domain ID is required"),
58
+ });
59
+ // ============================================================================
60
+ // Zod Schemas - Secondary Tools (Email)
61
+ // ============================================================================
62
+ const updateEmailSchema = z.object({
63
+ id: z.string().min(1, "Email ID is required"),
64
+ scheduledAt: z.string().min(1, "Scheduled time is required"),
65
+ });
66
+ const cancelEmailSchema = z.object({
67
+ id: z.string().min(1, "Email ID is required"),
68
+ });
69
+ // ============================================================================
70
+ // Zod Schemas - Secondary Tools (Contact)
71
+ // ============================================================================
72
+ const listContactsSchema = z.object({
73
+ audienceId: z.string().min(1, "Audience ID is required"),
74
+ });
75
+ const createContactSchema = z.object({
76
+ audienceId: z.string().min(1, "Audience ID is required"),
77
+ email: z.string().email("Invalid email address"),
78
+ firstName: z.string().optional(),
79
+ lastName: z.string().optional(),
80
+ unsubscribed: z.boolean().optional(),
81
+ });
82
+ const getContactSchema = z.object({
83
+ audienceId: z.string().min(1, "Audience ID is required"),
84
+ id: z.string().min(1, "Contact ID is required"),
85
+ });
86
+ const updateContactSchema = z.object({
87
+ audienceId: z.string().min(1, "Audience ID is required"),
88
+ id: z.string().min(1, "Contact ID is required"),
89
+ firstName: z.string().optional(),
90
+ lastName: z.string().optional(),
91
+ unsubscribed: z.boolean().optional(),
92
+ });
93
+ // ============================================================================
94
+ // Zod Schemas - Secondary Tools (Template)
95
+ // ============================================================================
96
+ const listTemplatesSchema = z.object({});
97
+ const createTemplateSchema = z.object({
98
+ name: z.string().min(1, "Template name is required"),
99
+ subject: z.string().min(1, "Subject is required"),
100
+ html: z.string().min(1, "HTML content is required"),
101
+ });
102
+ const getTemplateSchema = z.object({
103
+ id: z.string().min(1, "Template ID is required"),
104
+ });
105
+ const updateTemplateSchema = z.object({
106
+ id: z.string().min(1, "Template ID is required"),
107
+ name: z.string().optional(),
108
+ subject: z.string().optional(),
109
+ html: z.string().optional(),
110
+ });
111
+ const publishTemplateSchema = z.object({
112
+ id: z.string().min(1, "Template ID is required"),
113
+ });
114
+ const duplicateTemplateSchema = z.object({
115
+ id: z.string().min(1, "Template ID is required"),
116
+ });
117
+ // ============================================================================
118
+ // Zod Schemas - Secondary Tools (Webhook)
119
+ // ============================================================================
120
+ const webhookEventsSchema = z.array(z.enum([
121
+ "email.sent",
122
+ "email.delivered",
123
+ "email.delivery_delayed",
124
+ "email.complained",
125
+ "email.bounced",
126
+ "email.opened",
127
+ "email.clicked",
128
+ ]));
129
+ const listWebhooksSchema = z.object({});
130
+ const createWebhookSchema = z.object({
131
+ endpoint: z.string().url("Invalid webhook URL"),
132
+ events: webhookEventsSchema.min(1, "At least one event is required"),
133
+ });
134
+ const getWebhookSchema = z.object({
135
+ id: z.string().min(1, "Webhook ID is required"),
136
+ });
137
+ const updateWebhookSchema = z.object({
138
+ id: z.string().min(1, "Webhook ID is required"),
139
+ endpoint: z.string().url("Invalid webhook URL").optional(),
140
+ events: webhookEventsSchema.optional(),
141
+ enabled: z.boolean().optional(),
142
+ });
143
+ // ============================================================================
144
+ // Zod Schemas - Secondary Tools (Audience)
145
+ // ============================================================================
146
+ const listAudiencesSchema = z.object({});
147
+ const createAudienceSchema = z.object({
148
+ name: z.string().min(1, "Audience name is required"),
149
+ });
150
+ const getAudienceSchema = z.object({
151
+ id: z.string().min(1, "Audience ID is required"),
152
+ });
153
+ // ============================================================================
154
+ // Zod Schemas - Tertiary Tools (Destructive)
155
+ // ============================================================================
156
+ const deleteDomainSchema = z.object({
157
+ id: z.string().min(1, "Domain ID is required"),
158
+ });
159
+ const deleteContactSchema = z.object({
160
+ audienceId: z.string().min(1, "Audience ID is required"),
161
+ id: z.string().optional(),
162
+ email: z.string().email().optional(),
163
+ }).refine((data) => data.id || data.email, {
164
+ message: "Either 'id' or 'email' is required",
165
+ });
166
+ const deleteTemplateSchema = z.object({
167
+ id: z.string().min(1, "Template ID is required"),
168
+ });
169
+ const deleteTopicSchema = z.object({
170
+ id: z.string().min(1, "Topic ID is required"),
171
+ });
172
+ const deleteWebhookSchema = z.object({
173
+ id: z.string().min(1, "Webhook ID is required"),
174
+ });
175
+ const deleteSegmentSchema = z.object({
176
+ id: z.string().min(1, "Segment ID is required"),
177
+ });
178
+ const deleteBroadcastSchema = z.object({
179
+ id: z.string().min(1, "Broadcast ID is required"),
180
+ });
181
+ const deleteContactPropertySchema = z.object({
182
+ id: z.string().min(1, "Contact property ID is required"),
183
+ });
184
+ // ============================================================================
185
+ // Zod Schemas - Tertiary Tools (Batch)
186
+ // ============================================================================
187
+ const sendBatchEmailsSchema = z.object({
188
+ emails: z.array(z.object({
189
+ from: z.string().min(1, "From address is required"),
190
+ to: z.union([z.string().email(), z.array(z.string().email())]),
191
+ subject: z.string().min(1).max(998),
192
+ html: z.string().optional(),
193
+ text: z.string().optional(),
194
+ cc: z.union([z.string().email(), z.array(z.string().email())]).optional(),
195
+ bcc: z.union([z.string().email(), z.array(z.string().email())]).optional(),
196
+ reply_to: z.union([z.string().email(), z.array(z.string().email())]).optional(),
197
+ headers: z.record(z.string()).optional(),
198
+ tags: z.array(z.object({ name: z.string(), value: z.string() })).optional(),
199
+ scheduled_at: z.string().optional(),
200
+ })).min(1).max(100, "Maximum 100 emails per batch"),
201
+ });
202
+ // ============================================================================
203
+ // Zod Schemas - Tertiary Tools (Broadcast)
204
+ // ============================================================================
205
+ const listBroadcastsSchema = z.object({});
206
+ const createBroadcastSchema = z.object({
207
+ name: z.string().optional(),
208
+ segmentId: z.string().min(1, "Segment ID is required"),
209
+ from: z.string().min(1, "From address is required"),
210
+ subject: z.string().min(1, "Subject is required"),
211
+ html: z.string().optional(),
212
+ text: z.string().optional(),
213
+ replyTo: z.union([z.string().email(), z.array(z.string().email())]).optional(),
214
+ previewText: z.string().optional(),
215
+ }).refine((data) => data.html || data.text, {
216
+ message: "Either 'html' or 'text' content is required",
217
+ });
218
+ const getBroadcastSchema = z.object({
219
+ id: z.string().min(1, "Broadcast ID is required"),
220
+ });
221
+ const updateBroadcastSchema = z.object({
222
+ id: z.string().min(1, "Broadcast ID is required"),
223
+ name: z.string().optional(),
224
+ from: z.string().optional(),
225
+ subject: z.string().optional(),
226
+ html: z.string().optional(),
227
+ text: z.string().optional(),
228
+ replyTo: z.union([z.string().email(), z.array(z.string().email())]).optional(),
229
+ previewText: z.string().optional(),
230
+ });
231
+ const sendBroadcastSchema = z.object({
232
+ id: z.string().min(1, "Broadcast ID is required"),
233
+ scheduledAt: z.string().optional(),
234
+ });
235
+ // ============================================================================
236
+ // Zod Schemas - Tertiary Tools (Segment)
237
+ // ============================================================================
238
+ const listSegmentsSchema = z.object({});
239
+ const createSegmentSchema = z.object({
240
+ name: z.string().min(1, "Segment name is required"),
241
+ });
242
+ const getSegmentSchema = z.object({
243
+ id: z.string().min(1, "Segment ID is required"),
244
+ });
245
+ const addContactToSegmentSchema = z.object({
246
+ segmentId: z.string().min(1, "Segment ID is required"),
247
+ contactId: z.string().optional(),
248
+ email: z.string().email().optional(),
249
+ }).refine((data) => data.contactId || data.email, {
250
+ message: "Either 'contactId' or 'email' is required",
251
+ });
252
+ const removeContactFromSegmentSchema = z.object({
253
+ segmentId: z.string().min(1, "Segment ID is required"),
254
+ contactId: z.string().optional(),
255
+ email: z.string().email().optional(),
256
+ }).refine((data) => data.contactId || data.email, {
257
+ message: "Either 'contactId' or 'email' is required",
258
+ });
259
+ // ============================================================================
260
+ // Zod Schemas - Tertiary Tools (Contact Property)
261
+ // ============================================================================
262
+ const listContactPropertiesSchema = z.object({});
263
+ const createContactPropertySchema = z.object({
264
+ key: z.string().min(1, "Property key is required"),
265
+ type: z.enum(["string", "number"]),
266
+ fallbackValue: z.union([z.string(), z.number()]).nullable().optional(),
267
+ });
268
+ const getContactPropertySchema = z.object({
269
+ id: z.string().min(1, "Contact property ID is required"),
270
+ });
271
+ const updateContactPropertySchema = z.object({
272
+ id: z.string().min(1, "Contact property ID is required"),
273
+ fallbackValue: z.union([z.string(), z.number()]).nullable().optional(),
274
+ });
275
+ // ============================================================================
276
+ // Zod Schemas - Tertiary Tools (Inbound Email)
277
+ // ============================================================================
278
+ const listReceivedEmailsSchema = z.object({});
279
+ const getReceivedEmailSchema = z.object({
280
+ id: z.string().min(1, "Email ID is required"),
281
+ });
282
+ const listReceivedEmailAttachmentsSchema = z.object({
283
+ emailId: z.string().min(1, "Email ID is required"),
284
+ });
285
+ const getReceivedEmailAttachmentSchema = z.object({
286
+ emailId: z.string().min(1, "Email ID is required"),
287
+ id: z.string().min(1, "Attachment ID is required"),
288
+ });
289
+ // ============================================================================
290
+ // Zod Schemas - Tertiary Tools (Sent Email Attachments)
291
+ // ============================================================================
292
+ const listEmailAttachmentsSchema = z.object({
293
+ emailId: z.string().min(1, "Email ID is required"),
294
+ });
295
+ const getEmailAttachmentSchema = z.object({
296
+ emailId: z.string().min(1, "Email ID is required"),
297
+ id: z.string().min(1, "Attachment ID is required"),
298
+ });
299
+ // ============================================================================
300
+ // Zod Schemas - Tertiary Tools (Topic Advanced)
301
+ // ============================================================================
302
+ const getTopicSchema = z.object({
303
+ id: z.string().min(1, "Topic ID is required"),
304
+ });
305
+ const updateTopicSchema = z.object({
306
+ id: z.string().min(1, "Topic ID is required"),
307
+ name: z.string().optional(),
308
+ description: z.string().optional(),
309
+ });
310
+ const getContactTopicsSchema = z.object({
311
+ id: z.string().optional(),
312
+ email: z.string().email().optional(),
313
+ }).refine((data) => data.id || data.email, {
314
+ message: "Either 'id' or 'email' is required",
315
+ });
316
+ const updateContactTopicsSchema = z.object({
317
+ id: z.string().optional(),
318
+ email: z.string().email().optional(),
319
+ topics: z.array(z.object({
320
+ id: z.string(),
321
+ subscription: z.enum(["opt_in", "opt_out"]),
322
+ })),
323
+ }).refine((data) => data.id || data.email, {
324
+ message: "Either 'id' or 'email' is required",
325
+ });
326
+ // ============================================================================
327
+ // Zod Schemas - Tertiary Tools (Contact Segments)
328
+ // ============================================================================
329
+ const listContactSegmentsSchema = z.object({
330
+ contactId: z.string().min(1),
331
+ email: z.never().optional(),
332
+ }).or(z.object({
333
+ contactId: z.never().optional(),
334
+ email: z.string().email(),
335
+ }));
336
+ // ============================================================================
337
+ // Helper: Validation Error Handler
338
+ // ============================================================================
339
+ function handleValidationError(parseResult) {
340
+ const errorMsg = parseResult.error.errors
341
+ .map((e) => `${e.path.join(".")}: ${e.message}`)
342
+ .join("; ");
343
+ return createToolResponse(createValidationError(`Invalid input: ${errorMsg}`, {
344
+ errors: parseResult.error.errors,
345
+ }));
346
+ }
347
+ // ============================================================================
348
+ // Tool Factories - Core Tools
349
+ // ============================================================================
350
+ function createSendEmailTool(resend) {
351
+ return {
352
+ name: "send_email",
353
+ description: "Send an email via Resend API. The 'from' address must be from a verified domain. " +
354
+ "Supports HTML or plain text content, CC/BCC recipients, custom headers, and tags.",
355
+ inputSchema: {
356
+ type: "object",
357
+ properties: {
358
+ from: {
359
+ type: "string",
360
+ description: "Sender email address (must be from verified domain)",
361
+ },
362
+ to: {
363
+ oneOf: [
364
+ { type: "string" },
365
+ { type: "array", items: { type: "string" } },
366
+ ],
367
+ description: "Recipient email address(es)",
368
+ },
369
+ subject: {
370
+ type: "string",
371
+ description: "Email subject line (max 998 characters)",
372
+ },
373
+ html: {
374
+ type: "string",
375
+ description: "HTML body content (provide either html or text)",
376
+ },
377
+ text: {
378
+ type: "string",
379
+ description: "Plain text body content (provide either html or text)",
380
+ },
381
+ cc: {
382
+ oneOf: [{ type: "string" }, { type: "array", items: { type: "string" } }],
383
+ description: "CC recipient(s)",
384
+ },
385
+ bcc: {
386
+ oneOf: [{ type: "string" }, { type: "array", items: { type: "string" } }],
387
+ description: "BCC recipient(s)",
388
+ },
389
+ reply_to: {
390
+ oneOf: [{ type: "string" }, { type: "array", items: { type: "string" } }],
391
+ description: "Reply-to address(es)",
392
+ },
393
+ headers: {
394
+ type: "object",
395
+ additionalProperties: { type: "string" },
396
+ description: "Custom email headers",
397
+ },
398
+ tags: {
399
+ type: "array",
400
+ items: {
401
+ type: "object",
402
+ properties: { name: { type: "string" }, value: { type: "string" } },
403
+ required: ["name", "value"],
404
+ },
405
+ description: "Tags for email categorization",
406
+ },
407
+ },
408
+ required: ["from", "to", "subject"],
409
+ },
410
+ annotations: {
411
+ title: "Send Email",
412
+ readOnlyHint: false,
413
+ destructiveHint: false,
414
+ idempotentHint: false,
415
+ openWorldHint: false,
416
+ },
417
+ tier: "core",
418
+ scopes: ["write"],
419
+ execute: async (args) => {
420
+ const parseResult = sendEmailSchema.safeParse(args);
421
+ if (!parseResult.success) {
422
+ return handleValidationError(parseResult);
423
+ }
424
+ try {
425
+ const input = parseResult.data;
426
+ const emailOptions = {
427
+ from: input.from,
428
+ to: input.to,
429
+ subject: input.subject,
430
+ ...(input.html ? { html: input.html } : {}),
431
+ ...(input.text ? { text: input.text } : {}),
432
+ ...(input.cc ? { cc: input.cc } : {}),
433
+ ...(input.bcc ? { bcc: input.bcc } : {}),
434
+ ...(input.reply_to ? { replyTo: input.reply_to } : {}),
435
+ ...(input.headers ? { headers: input.headers } : {}),
436
+ ...(input.tags ? { tags: input.tags } : {}),
437
+ };
438
+ const result = await withRateLimitAndRetry(() => resend.emails.send(emailOptions));
439
+ if (result.error) {
440
+ return createToolResponse(formatResendError(result.error));
441
+ }
442
+ return createToolResponse({
443
+ success: true,
444
+ message: "Email sent successfully",
445
+ id: result.data?.id,
446
+ });
447
+ }
448
+ catch (error) {
449
+ return createToolResponse(formatResendError(error));
450
+ }
451
+ },
452
+ };
453
+ }
454
+ function createGetEmailTool(resend) {
455
+ return {
456
+ name: "get_email",
457
+ description: "Retrieve details of a previously sent email by its ID.",
458
+ inputSchema: {
459
+ type: "object",
460
+ properties: {
461
+ id: {
462
+ type: "string",
463
+ description: "The email ID returned from send_email",
464
+ },
465
+ },
466
+ required: ["id"],
467
+ },
468
+ annotations: {
469
+ title: "Get Email",
470
+ readOnlyHint: true,
471
+ destructiveHint: false,
472
+ idempotentHint: true,
473
+ openWorldHint: false,
474
+ },
475
+ tier: "core",
476
+ scopes: ["read"],
477
+ execute: async (args) => {
478
+ const parseResult = getEmailSchema.safeParse(args);
479
+ if (!parseResult.success) {
480
+ return handleValidationError(parseResult);
481
+ }
482
+ try {
483
+ const { id } = parseResult.data;
484
+ const result = await withRateLimitAndRetry(() => resend.emails.get(id));
485
+ if (result.error) {
486
+ return createToolResponse(formatResendError(result.error));
487
+ }
488
+ return createToolResponse(result.data);
489
+ }
490
+ catch (error) {
491
+ return createToolResponse(formatResendError(error));
492
+ }
493
+ },
494
+ };
495
+ }
496
+ function createListEmailsTool(resend) {
497
+ return {
498
+ name: "list_emails",
499
+ description: "List emails that have been sent. Supports pagination with cursor-based navigation.",
500
+ inputSchema: {
501
+ type: "object",
502
+ properties: {
503
+ limit: {
504
+ type: "integer",
505
+ minimum: 1,
506
+ maximum: 100,
507
+ description: "Maximum number of emails to return (default: 10, max: 100)",
508
+ },
509
+ cursor: {
510
+ type: "string",
511
+ description: "Pagination cursor from previous response",
512
+ },
513
+ },
514
+ },
515
+ annotations: {
516
+ title: "List Emails",
517
+ readOnlyHint: true,
518
+ destructiveHint: false,
519
+ idempotentHint: true,
520
+ openWorldHint: false,
521
+ },
522
+ tier: "core",
523
+ scopes: ["read"],
524
+ execute: async (args) => {
525
+ const parseResult = listEmailsSchema.safeParse(args);
526
+ if (!parseResult.success) {
527
+ return handleValidationError(parseResult);
528
+ }
529
+ try {
530
+ const result = await withRateLimitAndRetry(() => resend.emails.list());
531
+ if (result.error) {
532
+ return createToolResponse(formatResendError(result.error));
533
+ }
534
+ return createToolResponse(result.data);
535
+ }
536
+ catch (error) {
537
+ return createToolResponse(formatResendError(error));
538
+ }
539
+ },
540
+ };
541
+ }
542
+ function createListDomainsTool(resend) {
543
+ return {
544
+ name: "list_domains",
545
+ description: "List all domains associated with the account, including verification status.",
546
+ inputSchema: {
547
+ type: "object",
548
+ properties: {},
549
+ },
550
+ annotations: {
551
+ title: "List Domains",
552
+ readOnlyHint: true,
553
+ destructiveHint: false,
554
+ idempotentHint: true,
555
+ openWorldHint: false,
556
+ },
557
+ tier: "core",
558
+ scopes: ["read"],
559
+ execute: async () => {
560
+ try {
561
+ const result = await withRateLimitAndRetry(() => resend.domains.list());
562
+ if (result.error) {
563
+ return createToolResponse(formatResendError(result.error));
564
+ }
565
+ return createToolResponse(result.data);
566
+ }
567
+ catch (error) {
568
+ return createToolResponse(formatResendError(error));
569
+ }
570
+ },
571
+ };
572
+ }
573
+ function createGetDomainTool(resend) {
574
+ return {
575
+ name: "get_domain",
576
+ description: "Get details of a specific domain including DNS records and verification status.",
577
+ inputSchema: {
578
+ type: "object",
579
+ properties: {
580
+ id: {
581
+ type: "string",
582
+ description: "The domain ID",
583
+ },
584
+ },
585
+ required: ["id"],
586
+ },
587
+ annotations: {
588
+ title: "Get Domain",
589
+ readOnlyHint: true,
590
+ destructiveHint: false,
591
+ idempotentHint: true,
592
+ openWorldHint: false,
593
+ },
594
+ tier: "secondary",
595
+ scopes: ["read"],
596
+ execute: async (args) => {
597
+ const parseResult = getDomainSchema.safeParse(args);
598
+ if (!parseResult.success) {
599
+ return handleValidationError(parseResult);
600
+ }
601
+ try {
602
+ const { id } = parseResult.data;
603
+ const result = await withRateLimitAndRetry(() => resend.domains.get(id));
604
+ if (result.error) {
605
+ return createToolResponse(formatResendError(result.error));
606
+ }
607
+ return createToolResponse(result.data);
608
+ }
609
+ catch (error) {
610
+ return createToolResponse(formatResendError(error));
611
+ }
612
+ },
613
+ };
614
+ }
615
+ function createSearchDocsTool() {
616
+ const docsDefinition = getSearchDocsDefinition();
617
+ return {
618
+ name: docsDefinition.name,
619
+ description: docsDefinition.description,
620
+ inputSchema: docsDefinition.inputSchema,
621
+ annotations: docsDefinition.annotations,
622
+ tier: "core",
623
+ scopes: ["read"],
624
+ execute: async (args) => {
625
+ return executeSearchDocs(args);
626
+ },
627
+ };
628
+ }
629
+ // ============================================================================
630
+ // Tool Factories - Secondary Tools (Domain)
631
+ // ============================================================================
632
+ function createCreateDomainTool(resend) {
633
+ return {
634
+ name: "create_domain",
635
+ description: "Add a new domain for sending emails. After creation, configure DNS records to verify the domain.",
636
+ inputSchema: {
637
+ type: "object",
638
+ properties: {
639
+ name: {
640
+ type: "string",
641
+ description: "The domain name to add (e.g., 'example.com')",
642
+ },
643
+ region: {
644
+ type: "string",
645
+ enum: ["us-east-1", "eu-west-1", "sa-east-1", "ap-northeast-1"],
646
+ description: "AWS region for sending (default: us-east-1)",
647
+ },
648
+ },
649
+ required: ["name"],
650
+ },
651
+ annotations: {
652
+ title: "Create Domain",
653
+ readOnlyHint: false,
654
+ destructiveHint: false,
655
+ idempotentHint: false,
656
+ openWorldHint: false,
657
+ },
658
+ tier: "secondary",
659
+ scopes: ["write"],
660
+ execute: async (args) => {
661
+ const parseResult = createDomainSchema.safeParse(args);
662
+ if (!parseResult.success) {
663
+ return handleValidationError(parseResult);
664
+ }
665
+ try {
666
+ const input = parseResult.data;
667
+ const result = await withRateLimitAndRetry(() => resend.domains.create(input));
668
+ if (result.error) {
669
+ return createToolResponse(formatResendError(result.error));
670
+ }
671
+ return createToolResponse({
672
+ success: true,
673
+ message: "Domain created. Configure DNS records to verify.",
674
+ ...result.data,
675
+ });
676
+ }
677
+ catch (error) {
678
+ return createToolResponse(formatResendError(error));
679
+ }
680
+ },
681
+ };
682
+ }
683
+ function createUpdateDomainTool(resend) {
684
+ return {
685
+ name: "update_domain",
686
+ description: "Update domain settings like tracking options and TLS enforcement.",
687
+ inputSchema: {
688
+ type: "object",
689
+ properties: {
690
+ id: {
691
+ type: "string",
692
+ description: "The domain ID",
693
+ },
694
+ openTracking: {
695
+ type: "boolean",
696
+ description: "Enable open tracking",
697
+ },
698
+ clickTracking: {
699
+ type: "boolean",
700
+ description: "Enable click tracking",
701
+ },
702
+ tls: {
703
+ type: "string",
704
+ enum: ["enforced", "opportunistic"],
705
+ description: "TLS setting for email delivery",
706
+ },
707
+ },
708
+ required: ["id"],
709
+ },
710
+ annotations: {
711
+ title: "Update Domain",
712
+ readOnlyHint: false,
713
+ destructiveHint: false,
714
+ idempotentHint: true,
715
+ openWorldHint: false,
716
+ },
717
+ tier: "secondary",
718
+ scopes: ["write"],
719
+ execute: async (args) => {
720
+ const parseResult = updateDomainSchema.safeParse(args);
721
+ if (!parseResult.success) {
722
+ return handleValidationError(parseResult);
723
+ }
724
+ try {
725
+ const { id, ...updateData } = parseResult.data;
726
+ const result = await withRateLimitAndRetry(() => resend.domains.update({ id, ...updateData }));
727
+ if (result.error) {
728
+ return createToolResponse(formatResendError(result.error));
729
+ }
730
+ return createToolResponse({
731
+ success: true,
732
+ message: "Domain updated successfully",
733
+ ...result.data,
734
+ });
735
+ }
736
+ catch (error) {
737
+ return createToolResponse(formatResendError(error));
738
+ }
739
+ },
740
+ };
741
+ }
742
+ function createVerifyDomainTool(resend) {
743
+ return {
744
+ name: "verify_domain",
745
+ description: "Trigger DNS verification for a domain. Ensure DNS records are configured first.",
746
+ inputSchema: {
747
+ type: "object",
748
+ properties: {
749
+ id: {
750
+ type: "string",
751
+ description: "The domain ID to verify",
752
+ },
753
+ },
754
+ required: ["id"],
755
+ },
756
+ annotations: {
757
+ title: "Verify Domain",
758
+ readOnlyHint: false,
759
+ destructiveHint: false,
760
+ idempotentHint: true,
761
+ openWorldHint: false,
762
+ },
763
+ tier: "secondary",
764
+ scopes: ["write"],
765
+ execute: async (args) => {
766
+ const parseResult = verifyDomainSchema.safeParse(args);
767
+ if (!parseResult.success) {
768
+ return handleValidationError(parseResult);
769
+ }
770
+ try {
771
+ const { id } = parseResult.data;
772
+ const result = await withRateLimitAndRetry(() => resend.domains.verify(id));
773
+ if (result.error) {
774
+ return createToolResponse(formatResendError(result.error));
775
+ }
776
+ return createToolResponse({
777
+ success: true,
778
+ message: "Domain verification initiated",
779
+ ...result.data,
780
+ });
781
+ }
782
+ catch (error) {
783
+ return createToolResponse(formatResendError(error));
784
+ }
785
+ },
786
+ };
787
+ }
788
+ // ============================================================================
789
+ // Tool Factories - Secondary Tools (Email)
790
+ // ============================================================================
791
+ function createUpdateEmailTool(resend) {
792
+ return {
793
+ name: "update_email",
794
+ description: "Update a scheduled email's send time. Only works for emails that haven't been sent yet.",
795
+ inputSchema: {
796
+ type: "object",
797
+ properties: {
798
+ id: {
799
+ type: "string",
800
+ description: "The email ID",
801
+ },
802
+ scheduledAt: {
803
+ type: "string",
804
+ description: "New scheduled time (ISO 8601 format)",
805
+ },
806
+ },
807
+ required: ["id", "scheduledAt"],
808
+ },
809
+ annotations: {
810
+ title: "Update Email",
811
+ readOnlyHint: false,
812
+ destructiveHint: false,
813
+ idempotentHint: true,
814
+ openWorldHint: false,
815
+ },
816
+ tier: "secondary",
817
+ scopes: ["write"],
818
+ execute: async (args) => {
819
+ const parseResult = updateEmailSchema.safeParse(args);
820
+ if (!parseResult.success) {
821
+ return handleValidationError(parseResult);
822
+ }
823
+ try {
824
+ const { id, scheduledAt } = parseResult.data;
825
+ const result = await withRateLimitAndRetry(() => resend.emails.update({ id, scheduledAt }));
826
+ if (result.error) {
827
+ return createToolResponse(formatResendError(result.error));
828
+ }
829
+ return createToolResponse({
830
+ success: true,
831
+ message: "Email schedule updated",
832
+ ...result.data,
833
+ });
834
+ }
835
+ catch (error) {
836
+ return createToolResponse(formatResendError(error));
837
+ }
838
+ },
839
+ };
840
+ }
841
+ function createCancelEmailTool(resend) {
842
+ return {
843
+ name: "cancel_email",
844
+ description: "Cancel a scheduled email. Only works for emails that haven't been sent yet.",
845
+ inputSchema: {
846
+ type: "object",
847
+ properties: {
848
+ id: {
849
+ type: "string",
850
+ description: "The email ID to cancel",
851
+ },
852
+ },
853
+ required: ["id"],
854
+ },
855
+ annotations: {
856
+ title: "Cancel Email",
857
+ readOnlyHint: false,
858
+ destructiveHint: true,
859
+ idempotentHint: true,
860
+ openWorldHint: false,
861
+ },
862
+ tier: "secondary",
863
+ scopes: ["write"],
864
+ execute: async (args) => {
865
+ const parseResult = cancelEmailSchema.safeParse(args);
866
+ if (!parseResult.success) {
867
+ return handleValidationError(parseResult);
868
+ }
869
+ try {
870
+ const { id } = parseResult.data;
871
+ const result = await withRateLimitAndRetry(() => resend.emails.cancel(id));
872
+ if (result.error) {
873
+ return createToolResponse(formatResendError(result.error));
874
+ }
875
+ return createToolResponse({
876
+ success: true,
877
+ message: "Email cancelled successfully",
878
+ ...result.data,
879
+ });
880
+ }
881
+ catch (error) {
882
+ return createToolResponse(formatResendError(error));
883
+ }
884
+ },
885
+ };
886
+ }
887
+ // ============================================================================
888
+ // Tool Factories - Secondary Tools (Contact)
889
+ // ============================================================================
890
+ function createListContactsTool(resend) {
891
+ return {
892
+ name: "list_contacts",
893
+ description: "List all contacts in an audience.",
894
+ inputSchema: {
895
+ type: "object",
896
+ properties: {
897
+ audienceId: {
898
+ type: "string",
899
+ description: "The audience ID to list contacts from",
900
+ },
901
+ },
902
+ required: ["audienceId"],
903
+ },
904
+ annotations: {
905
+ title: "List Contacts",
906
+ readOnlyHint: true,
907
+ destructiveHint: false,
908
+ idempotentHint: true,
909
+ openWorldHint: false,
910
+ },
911
+ tier: "secondary",
912
+ scopes: ["read"],
913
+ execute: async (args) => {
914
+ const parseResult = listContactsSchema.safeParse(args);
915
+ if (!parseResult.success) {
916
+ return handleValidationError(parseResult);
917
+ }
918
+ try {
919
+ const { audienceId } = parseResult.data;
920
+ const result = await withRateLimitAndRetry(() => resend.contacts.list({ audienceId }));
921
+ if (result.error) {
922
+ return createToolResponse(formatResendError(result.error));
923
+ }
924
+ return createToolResponse(result.data);
925
+ }
926
+ catch (error) {
927
+ return createToolResponse(formatResendError(error));
928
+ }
929
+ },
930
+ };
931
+ }
932
+ function createCreateContactTool(resend) {
933
+ return {
934
+ name: "create_contact",
935
+ description: "Add a new contact to an audience.",
936
+ inputSchema: {
937
+ type: "object",
938
+ properties: {
939
+ audienceId: {
940
+ type: "string",
941
+ description: "The audience ID to add the contact to",
942
+ },
943
+ email: {
944
+ type: "string",
945
+ description: "Contact email address",
946
+ },
947
+ firstName: {
948
+ type: "string",
949
+ description: "Contact first name",
950
+ },
951
+ lastName: {
952
+ type: "string",
953
+ description: "Contact last name",
954
+ },
955
+ unsubscribed: {
956
+ type: "boolean",
957
+ description: "Whether the contact is unsubscribed",
958
+ },
959
+ },
960
+ required: ["audienceId", "email"],
961
+ },
962
+ annotations: {
963
+ title: "Create Contact",
964
+ readOnlyHint: false,
965
+ destructiveHint: false,
966
+ idempotentHint: false,
967
+ openWorldHint: false,
968
+ },
969
+ tier: "secondary",
970
+ scopes: ["write"],
971
+ execute: async (args) => {
972
+ const parseResult = createContactSchema.safeParse(args);
973
+ if (!parseResult.success) {
974
+ return handleValidationError(parseResult);
975
+ }
976
+ try {
977
+ const input = parseResult.data;
978
+ const result = await withRateLimitAndRetry(() => resend.contacts.create(input));
979
+ if (result.error) {
980
+ return createToolResponse(formatResendError(result.error));
981
+ }
982
+ return createToolResponse({
983
+ success: true,
984
+ message: "Contact created successfully",
985
+ ...result.data,
986
+ });
987
+ }
988
+ catch (error) {
989
+ return createToolResponse(formatResendError(error));
990
+ }
991
+ },
992
+ };
993
+ }
994
+ function createGetContactTool(resend) {
995
+ return {
996
+ name: "get_contact",
997
+ description: "Get details of a specific contact.",
998
+ inputSchema: {
999
+ type: "object",
1000
+ properties: {
1001
+ audienceId: {
1002
+ type: "string",
1003
+ description: "The audience ID",
1004
+ },
1005
+ id: {
1006
+ type: "string",
1007
+ description: "The contact ID",
1008
+ },
1009
+ },
1010
+ required: ["audienceId", "id"],
1011
+ },
1012
+ annotations: {
1013
+ title: "Get Contact",
1014
+ readOnlyHint: true,
1015
+ destructiveHint: false,
1016
+ idempotentHint: true,
1017
+ openWorldHint: false,
1018
+ },
1019
+ tier: "secondary",
1020
+ scopes: ["read"],
1021
+ execute: async (args) => {
1022
+ const parseResult = getContactSchema.safeParse(args);
1023
+ if (!parseResult.success) {
1024
+ return handleValidationError(parseResult);
1025
+ }
1026
+ try {
1027
+ const { audienceId, id } = parseResult.data;
1028
+ const result = await withRateLimitAndRetry(() => resend.contacts.get({ audienceId, id }));
1029
+ if (result.error) {
1030
+ return createToolResponse(formatResendError(result.error));
1031
+ }
1032
+ return createToolResponse(result.data);
1033
+ }
1034
+ catch (error) {
1035
+ return createToolResponse(formatResendError(error));
1036
+ }
1037
+ },
1038
+ };
1039
+ }
1040
+ function createUpdateContactTool(resend) {
1041
+ return {
1042
+ name: "update_contact",
1043
+ description: "Update a contact's information.",
1044
+ inputSchema: {
1045
+ type: "object",
1046
+ properties: {
1047
+ audienceId: {
1048
+ type: "string",
1049
+ description: "The audience ID",
1050
+ },
1051
+ id: {
1052
+ type: "string",
1053
+ description: "The contact ID",
1054
+ },
1055
+ firstName: {
1056
+ type: "string",
1057
+ description: "Contact first name",
1058
+ },
1059
+ lastName: {
1060
+ type: "string",
1061
+ description: "Contact last name",
1062
+ },
1063
+ unsubscribed: {
1064
+ type: "boolean",
1065
+ description: "Whether the contact is unsubscribed",
1066
+ },
1067
+ },
1068
+ required: ["audienceId", "id"],
1069
+ },
1070
+ annotations: {
1071
+ title: "Update Contact",
1072
+ readOnlyHint: false,
1073
+ destructiveHint: false,
1074
+ idempotentHint: true,
1075
+ openWorldHint: false,
1076
+ },
1077
+ tier: "secondary",
1078
+ scopes: ["write"],
1079
+ execute: async (args) => {
1080
+ const parseResult = updateContactSchema.safeParse(args);
1081
+ if (!parseResult.success) {
1082
+ return handleValidationError(parseResult);
1083
+ }
1084
+ try {
1085
+ const input = parseResult.data;
1086
+ const result = await withRateLimitAndRetry(() => resend.contacts.update(input));
1087
+ if (result.error) {
1088
+ return createToolResponse(formatResendError(result.error));
1089
+ }
1090
+ return createToolResponse({
1091
+ success: true,
1092
+ message: "Contact updated successfully",
1093
+ ...result.data,
1094
+ });
1095
+ }
1096
+ catch (error) {
1097
+ return createToolResponse(formatResendError(error));
1098
+ }
1099
+ },
1100
+ };
1101
+ }
1102
+ // ============================================================================
1103
+ // Tool Factories - Secondary Tools (Template)
1104
+ // ============================================================================
1105
+ function createListTemplatesTool(resend) {
1106
+ return {
1107
+ name: "list_templates",
1108
+ description: "List all email templates.",
1109
+ inputSchema: {
1110
+ type: "object",
1111
+ properties: {},
1112
+ },
1113
+ annotations: {
1114
+ title: "List Templates",
1115
+ readOnlyHint: true,
1116
+ destructiveHint: false,
1117
+ idempotentHint: true,
1118
+ openWorldHint: false,
1119
+ },
1120
+ tier: "secondary",
1121
+ scopes: ["read"],
1122
+ execute: async (args) => {
1123
+ const parseResult = listTemplatesSchema.safeParse(args);
1124
+ if (!parseResult.success) {
1125
+ return handleValidationError(parseResult);
1126
+ }
1127
+ try {
1128
+ const result = await withRateLimitAndRetry(() => resend.templates.list());
1129
+ if (result.error) {
1130
+ return createToolResponse(formatResendError(result.error));
1131
+ }
1132
+ return createToolResponse(result.data);
1133
+ }
1134
+ catch (error) {
1135
+ return createToolResponse(formatResendError(error));
1136
+ }
1137
+ },
1138
+ };
1139
+ }
1140
+ function createCreateTemplateTool(resend) {
1141
+ return {
1142
+ name: "create_template",
1143
+ description: "Create a new email template with HTML content.",
1144
+ inputSchema: {
1145
+ type: "object",
1146
+ properties: {
1147
+ name: {
1148
+ type: "string",
1149
+ description: "Template name",
1150
+ },
1151
+ subject: {
1152
+ type: "string",
1153
+ description: "Email subject line",
1154
+ },
1155
+ html: {
1156
+ type: "string",
1157
+ description: "HTML content of the template",
1158
+ },
1159
+ },
1160
+ required: ["name", "subject", "html"],
1161
+ },
1162
+ annotations: {
1163
+ title: "Create Template",
1164
+ readOnlyHint: false,
1165
+ destructiveHint: false,
1166
+ idempotentHint: false,
1167
+ openWorldHint: false,
1168
+ },
1169
+ tier: "secondary",
1170
+ scopes: ["write"],
1171
+ execute: async (args) => {
1172
+ const parseResult = createTemplateSchema.safeParse(args);
1173
+ if (!parseResult.success) {
1174
+ return handleValidationError(parseResult);
1175
+ }
1176
+ try {
1177
+ const input = parseResult.data;
1178
+ const result = await withRateLimitAndRetry(() => Promise.resolve(resend.templates.create(input)));
1179
+ if (result.error) {
1180
+ return createToolResponse(formatResendError(result.error));
1181
+ }
1182
+ return createToolResponse({
1183
+ success: true,
1184
+ message: "Template created successfully",
1185
+ ...result.data,
1186
+ });
1187
+ }
1188
+ catch (error) {
1189
+ return createToolResponse(formatResendError(error));
1190
+ }
1191
+ },
1192
+ };
1193
+ }
1194
+ function createGetTemplateTool(resend) {
1195
+ return {
1196
+ name: "get_template",
1197
+ description: "Get details of a specific email template.",
1198
+ inputSchema: {
1199
+ type: "object",
1200
+ properties: {
1201
+ id: {
1202
+ type: "string",
1203
+ description: "The template ID",
1204
+ },
1205
+ },
1206
+ required: ["id"],
1207
+ },
1208
+ annotations: {
1209
+ title: "Get Template",
1210
+ readOnlyHint: true,
1211
+ destructiveHint: false,
1212
+ idempotentHint: true,
1213
+ openWorldHint: false,
1214
+ },
1215
+ tier: "secondary",
1216
+ scopes: ["read"],
1217
+ execute: async (args) => {
1218
+ const parseResult = getTemplateSchema.safeParse(args);
1219
+ if (!parseResult.success) {
1220
+ return handleValidationError(parseResult);
1221
+ }
1222
+ try {
1223
+ const { id } = parseResult.data;
1224
+ const result = await withRateLimitAndRetry(() => resend.templates.get(id));
1225
+ if (result.error) {
1226
+ return createToolResponse(formatResendError(result.error));
1227
+ }
1228
+ return createToolResponse(result.data);
1229
+ }
1230
+ catch (error) {
1231
+ return createToolResponse(formatResendError(error));
1232
+ }
1233
+ },
1234
+ };
1235
+ }
1236
+ function createUpdateTemplateTool(resend) {
1237
+ return {
1238
+ name: "update_template",
1239
+ description: "Update an existing email template.",
1240
+ inputSchema: {
1241
+ type: "object",
1242
+ properties: {
1243
+ id: {
1244
+ type: "string",
1245
+ description: "The template ID",
1246
+ },
1247
+ name: {
1248
+ type: "string",
1249
+ description: "New template name",
1250
+ },
1251
+ subject: {
1252
+ type: "string",
1253
+ description: "New email subject line",
1254
+ },
1255
+ html: {
1256
+ type: "string",
1257
+ description: "New HTML content",
1258
+ },
1259
+ },
1260
+ required: ["id"],
1261
+ },
1262
+ annotations: {
1263
+ title: "Update Template",
1264
+ readOnlyHint: false,
1265
+ destructiveHint: false,
1266
+ idempotentHint: true,
1267
+ openWorldHint: false,
1268
+ },
1269
+ tier: "secondary",
1270
+ scopes: ["write"],
1271
+ execute: async (args) => {
1272
+ const parseResult = updateTemplateSchema.safeParse(args);
1273
+ if (!parseResult.success) {
1274
+ return handleValidationError(parseResult);
1275
+ }
1276
+ try {
1277
+ const { id, ...updateData } = parseResult.data;
1278
+ // NOTE: Resend SDK templates.update takes (id, payload) as separate args
1279
+ const result = await withRateLimitAndRetry(() => Promise.resolve(resend.templates.update(id, updateData)));
1280
+ if (result.error) {
1281
+ return createToolResponse(formatResendError(result.error));
1282
+ }
1283
+ return createToolResponse({
1284
+ success: true,
1285
+ message: "Template updated successfully",
1286
+ ...result.data,
1287
+ });
1288
+ }
1289
+ catch (error) {
1290
+ return createToolResponse(formatResendError(error));
1291
+ }
1292
+ },
1293
+ };
1294
+ }
1295
+ function createPublishTemplateTool(resend) {
1296
+ return {
1297
+ name: "publish_template",
1298
+ description: "Publish a template to make it available for use.",
1299
+ inputSchema: {
1300
+ type: "object",
1301
+ properties: {
1302
+ id: {
1303
+ type: "string",
1304
+ description: "The template ID to publish",
1305
+ },
1306
+ },
1307
+ required: ["id"],
1308
+ },
1309
+ annotations: {
1310
+ title: "Publish Template",
1311
+ readOnlyHint: false,
1312
+ destructiveHint: false,
1313
+ idempotentHint: true,
1314
+ openWorldHint: false,
1315
+ },
1316
+ tier: "secondary",
1317
+ scopes: ["write"],
1318
+ execute: async (args) => {
1319
+ const parseResult = publishTemplateSchema.safeParse(args);
1320
+ if (!parseResult.success) {
1321
+ return handleValidationError(parseResult);
1322
+ }
1323
+ try {
1324
+ const { id } = parseResult.data;
1325
+ const result = await withRateLimitAndRetry(() => resend.templates.publish(id));
1326
+ if (result.error) {
1327
+ return createToolResponse(formatResendError(result.error));
1328
+ }
1329
+ return createToolResponse({
1330
+ success: true,
1331
+ message: "Template published successfully",
1332
+ ...result.data,
1333
+ });
1334
+ }
1335
+ catch (error) {
1336
+ return createToolResponse(formatResendError(error));
1337
+ }
1338
+ },
1339
+ };
1340
+ }
1341
+ function createDuplicateTemplateTool(resend) {
1342
+ return {
1343
+ name: "duplicate_template",
1344
+ description: "Create a copy of an existing template.",
1345
+ inputSchema: {
1346
+ type: "object",
1347
+ properties: {
1348
+ id: {
1349
+ type: "string",
1350
+ description: "The template ID to duplicate",
1351
+ },
1352
+ },
1353
+ required: ["id"],
1354
+ },
1355
+ annotations: {
1356
+ title: "Duplicate Template",
1357
+ readOnlyHint: false,
1358
+ destructiveHint: false,
1359
+ idempotentHint: false,
1360
+ openWorldHint: false,
1361
+ },
1362
+ tier: "secondary",
1363
+ scopes: ["write"],
1364
+ execute: async (args) => {
1365
+ const parseResult = duplicateTemplateSchema.safeParse(args);
1366
+ if (!parseResult.success) {
1367
+ return handleValidationError(parseResult);
1368
+ }
1369
+ try {
1370
+ const { id } = parseResult.data;
1371
+ const result = await withRateLimitAndRetry(() => Promise.resolve(resend.templates.duplicate(id)));
1372
+ if (result.error) {
1373
+ return createToolResponse(formatResendError(result.error));
1374
+ }
1375
+ return createToolResponse({
1376
+ success: true,
1377
+ message: "Template duplicated successfully",
1378
+ ...result.data,
1379
+ });
1380
+ }
1381
+ catch (error) {
1382
+ return createToolResponse(formatResendError(error));
1383
+ }
1384
+ },
1385
+ };
1386
+ }
1387
+ // ============================================================================
1388
+ // Tool Factories - Secondary Tools (Webhook)
1389
+ // ============================================================================
1390
+ function createListWebhooksTool(resend) {
1391
+ return {
1392
+ name: "list_webhooks",
1393
+ description: "List all webhooks configured for the account.",
1394
+ inputSchema: {
1395
+ type: "object",
1396
+ properties: {},
1397
+ },
1398
+ annotations: {
1399
+ title: "List Webhooks",
1400
+ readOnlyHint: true,
1401
+ destructiveHint: false,
1402
+ idempotentHint: true,
1403
+ openWorldHint: false,
1404
+ },
1405
+ tier: "secondary",
1406
+ scopes: ["read"],
1407
+ execute: async (args) => {
1408
+ const parseResult = listWebhooksSchema.safeParse(args);
1409
+ if (!parseResult.success) {
1410
+ return handleValidationError(parseResult);
1411
+ }
1412
+ try {
1413
+ const result = await withRateLimitAndRetry(() => resend.webhooks.list());
1414
+ if (result.error) {
1415
+ return createToolResponse(formatResendError(result.error));
1416
+ }
1417
+ return createToolResponse(result.data);
1418
+ }
1419
+ catch (error) {
1420
+ return createToolResponse(formatResendError(error));
1421
+ }
1422
+ },
1423
+ };
1424
+ }
1425
+ function createCreateWebhookTool(resend) {
1426
+ return {
1427
+ name: "create_webhook",
1428
+ description: "Create a new webhook to receive event notifications.",
1429
+ inputSchema: {
1430
+ type: "object",
1431
+ properties: {
1432
+ endpoint: {
1433
+ type: "string",
1434
+ description: "The URL to receive webhook events",
1435
+ },
1436
+ events: {
1437
+ type: "array",
1438
+ items: {
1439
+ type: "string",
1440
+ enum: ["email.sent", "email.delivered", "email.delivery_delayed", "email.complained", "email.bounced", "email.opened", "email.clicked"],
1441
+ },
1442
+ description: "Events to subscribe to",
1443
+ },
1444
+ },
1445
+ required: ["endpoint", "events"],
1446
+ },
1447
+ annotations: {
1448
+ title: "Create Webhook",
1449
+ readOnlyHint: false,
1450
+ destructiveHint: false,
1451
+ idempotentHint: false,
1452
+ openWorldHint: false,
1453
+ },
1454
+ tier: "secondary",
1455
+ scopes: ["write"],
1456
+ execute: async (args) => {
1457
+ const parseResult = createWebhookSchema.safeParse(args);
1458
+ if (!parseResult.success) {
1459
+ return handleValidationError(parseResult);
1460
+ }
1461
+ try {
1462
+ const input = parseResult.data;
1463
+ const result = await withRateLimitAndRetry(() => resend.webhooks.create({ endpoint: input.endpoint, events: input.events }));
1464
+ if (result.error) {
1465
+ return createToolResponse(formatResendError(result.error));
1466
+ }
1467
+ return createToolResponse({
1468
+ success: true,
1469
+ message: "Webhook created successfully",
1470
+ ...result.data,
1471
+ });
1472
+ }
1473
+ catch (error) {
1474
+ return createToolResponse(formatResendError(error));
1475
+ }
1476
+ },
1477
+ };
1478
+ }
1479
+ function createGetWebhookTool(resend) {
1480
+ return {
1481
+ name: "get_webhook",
1482
+ description: "Get details of a specific webhook.",
1483
+ inputSchema: {
1484
+ type: "object",
1485
+ properties: {
1486
+ id: {
1487
+ type: "string",
1488
+ description: "The webhook ID",
1489
+ },
1490
+ },
1491
+ required: ["id"],
1492
+ },
1493
+ annotations: {
1494
+ title: "Get Webhook",
1495
+ readOnlyHint: true,
1496
+ destructiveHint: false,
1497
+ idempotentHint: true,
1498
+ openWorldHint: false,
1499
+ },
1500
+ tier: "secondary",
1501
+ scopes: ["read"],
1502
+ execute: async (args) => {
1503
+ const parseResult = getWebhookSchema.safeParse(args);
1504
+ if (!parseResult.success) {
1505
+ return handleValidationError(parseResult);
1506
+ }
1507
+ try {
1508
+ const { id } = parseResult.data;
1509
+ const result = await withRateLimitAndRetry(() => resend.webhooks.get(id));
1510
+ if (result.error) {
1511
+ return createToolResponse(formatResendError(result.error));
1512
+ }
1513
+ return createToolResponse(result.data);
1514
+ }
1515
+ catch (error) {
1516
+ return createToolResponse(formatResendError(error));
1517
+ }
1518
+ },
1519
+ };
1520
+ }
1521
+ function createUpdateWebhookTool(resend) {
1522
+ return {
1523
+ name: "update_webhook",
1524
+ description: "Update a webhook's configuration.",
1525
+ inputSchema: {
1526
+ type: "object",
1527
+ properties: {
1528
+ id: {
1529
+ type: "string",
1530
+ description: "The webhook ID",
1531
+ },
1532
+ endpoint: {
1533
+ type: "string",
1534
+ description: "New endpoint URL",
1535
+ },
1536
+ events: {
1537
+ type: "array",
1538
+ items: {
1539
+ type: "string",
1540
+ enum: ["email.sent", "email.delivered", "email.delivery_delayed", "email.complained", "email.bounced", "email.opened", "email.clicked"],
1541
+ },
1542
+ description: "New events to subscribe to",
1543
+ },
1544
+ enabled: {
1545
+ type: "boolean",
1546
+ description: "Whether the webhook is enabled",
1547
+ },
1548
+ },
1549
+ required: ["id"],
1550
+ },
1551
+ annotations: {
1552
+ title: "Update Webhook",
1553
+ readOnlyHint: false,
1554
+ destructiveHint: false,
1555
+ idempotentHint: true,
1556
+ openWorldHint: false,
1557
+ },
1558
+ tier: "secondary",
1559
+ scopes: ["write"],
1560
+ execute: async (args) => {
1561
+ const parseResult = updateWebhookSchema.safeParse(args);
1562
+ if (!parseResult.success) {
1563
+ return handleValidationError(parseResult);
1564
+ }
1565
+ try {
1566
+ const { id, ...updateData } = parseResult.data;
1567
+ const result = await withRateLimitAndRetry(() => resend.webhooks.update(id, updateData));
1568
+ if (result.error) {
1569
+ return createToolResponse(formatResendError(result.error));
1570
+ }
1571
+ return createToolResponse({
1572
+ success: true,
1573
+ message: "Webhook updated successfully",
1574
+ ...result.data,
1575
+ });
1576
+ }
1577
+ catch (error) {
1578
+ return createToolResponse(formatResendError(error));
1579
+ }
1580
+ },
1581
+ };
1582
+ }
1583
+ // ============================================================================
1584
+ // Tool Factories - Secondary Tools (Audience)
1585
+ // ============================================================================
1586
+ function createListAudiencesTool(resend) {
1587
+ return {
1588
+ name: "list_audiences",
1589
+ description: "List all audiences (contact lists) in the account.",
1590
+ inputSchema: {
1591
+ type: "object",
1592
+ properties: {},
1593
+ },
1594
+ annotations: {
1595
+ title: "List Audiences",
1596
+ readOnlyHint: true,
1597
+ destructiveHint: false,
1598
+ idempotentHint: true,
1599
+ openWorldHint: false,
1600
+ },
1601
+ tier: "secondary",
1602
+ scopes: ["read"],
1603
+ execute: async (args) => {
1604
+ const parseResult = listAudiencesSchema.safeParse(args);
1605
+ if (!parseResult.success) {
1606
+ return handleValidationError(parseResult);
1607
+ }
1608
+ try {
1609
+ const result = await withRateLimitAndRetry(() => resend.segments.list());
1610
+ if (result.error) {
1611
+ return createToolResponse(formatResendError(result.error));
1612
+ }
1613
+ return createToolResponse(result.data);
1614
+ }
1615
+ catch (error) {
1616
+ return createToolResponse(formatResendError(error));
1617
+ }
1618
+ },
1619
+ };
1620
+ }
1621
+ function createCreateAudienceTool(resend) {
1622
+ return {
1623
+ name: "create_audience",
1624
+ description: "Create a new audience (contact list).",
1625
+ inputSchema: {
1626
+ type: "object",
1627
+ properties: {
1628
+ name: {
1629
+ type: "string",
1630
+ description: "The audience name",
1631
+ },
1632
+ },
1633
+ required: ["name"],
1634
+ },
1635
+ annotations: {
1636
+ title: "Create Audience",
1637
+ readOnlyHint: false,
1638
+ destructiveHint: false,
1639
+ idempotentHint: false,
1640
+ openWorldHint: false,
1641
+ },
1642
+ tier: "secondary",
1643
+ scopes: ["write"],
1644
+ execute: async (args) => {
1645
+ const parseResult = createAudienceSchema.safeParse(args);
1646
+ if (!parseResult.success) {
1647
+ return handleValidationError(parseResult);
1648
+ }
1649
+ try {
1650
+ const input = parseResult.data;
1651
+ const result = await withRateLimitAndRetry(() => resend.segments.create(input));
1652
+ if (result.error) {
1653
+ return createToolResponse(formatResendError(result.error));
1654
+ }
1655
+ return createToolResponse({
1656
+ success: true,
1657
+ message: "Audience created successfully",
1658
+ ...result.data,
1659
+ });
1660
+ }
1661
+ catch (error) {
1662
+ return createToolResponse(formatResendError(error));
1663
+ }
1664
+ },
1665
+ };
1666
+ }
1667
+ function createGetAudienceTool(resend) {
1668
+ return {
1669
+ name: "get_audience",
1670
+ description: "Get details of a specific audience.",
1671
+ inputSchema: {
1672
+ type: "object",
1673
+ properties: {
1674
+ id: {
1675
+ type: "string",
1676
+ description: "The audience ID",
1677
+ },
1678
+ },
1679
+ required: ["id"],
1680
+ },
1681
+ annotations: {
1682
+ title: "Get Audience",
1683
+ readOnlyHint: true,
1684
+ destructiveHint: false,
1685
+ idempotentHint: true,
1686
+ openWorldHint: false,
1687
+ },
1688
+ tier: "secondary",
1689
+ scopes: ["read"],
1690
+ execute: async (args) => {
1691
+ const parseResult = getAudienceSchema.safeParse(args);
1692
+ if (!parseResult.success) {
1693
+ return handleValidationError(parseResult);
1694
+ }
1695
+ try {
1696
+ const { id } = parseResult.data;
1697
+ const result = await withRateLimitAndRetry(() => resend.segments.get(id));
1698
+ if (result.error) {
1699
+ return createToolResponse(formatResendError(result.error));
1700
+ }
1701
+ return createToolResponse(result.data);
1702
+ }
1703
+ catch (error) {
1704
+ return createToolResponse(formatResendError(error));
1705
+ }
1706
+ },
1707
+ };
1708
+ }
1709
+ // ============================================================================
1710
+ // Tool Factories - Tertiary Tools (Destructive)
1711
+ // ============================================================================
1712
+ function createDeleteDomainTool(resend) {
1713
+ return {
1714
+ name: "delete_domain",
1715
+ description: "Delete a domain from your account. This is a destructive operation.",
1716
+ inputSchema: {
1717
+ type: "object",
1718
+ properties: {
1719
+ id: {
1720
+ type: "string",
1721
+ description: "The domain ID to delete",
1722
+ },
1723
+ },
1724
+ required: ["id"],
1725
+ },
1726
+ annotations: {
1727
+ title: "Delete Domain",
1728
+ readOnlyHint: false,
1729
+ destructiveHint: true,
1730
+ idempotentHint: true,
1731
+ openWorldHint: false,
1732
+ },
1733
+ tier: "tertiary",
1734
+ scopes: ["admin"],
1735
+ execute: async (args) => {
1736
+ const parseResult = deleteDomainSchema.safeParse(args);
1737
+ if (!parseResult.success) {
1738
+ return handleValidationError(parseResult);
1739
+ }
1740
+ try {
1741
+ const { id } = parseResult.data;
1742
+ const result = await withRateLimitAndRetry(() => resend.domains.remove(id));
1743
+ if (result.error) {
1744
+ return createToolResponse(formatResendError(result.error));
1745
+ }
1746
+ return createToolResponse({
1747
+ success: true,
1748
+ message: "Domain deleted successfully",
1749
+ ...result.data,
1750
+ });
1751
+ }
1752
+ catch (error) {
1753
+ return createToolResponse(formatResendError(error));
1754
+ }
1755
+ },
1756
+ };
1757
+ }
1758
+ function createDeleteContactTool(resend) {
1759
+ return {
1760
+ name: "delete_contact",
1761
+ description: "Delete a contact from an audience. This is a destructive operation.",
1762
+ inputSchema: {
1763
+ type: "object",
1764
+ properties: {
1765
+ audienceId: {
1766
+ type: "string",
1767
+ description: "The audience ID containing the contact",
1768
+ },
1769
+ id: {
1770
+ type: "string",
1771
+ description: "The contact ID to delete (use either id or email)",
1772
+ },
1773
+ email: {
1774
+ type: "string",
1775
+ description: "The contact email to delete (use either id or email)",
1776
+ },
1777
+ },
1778
+ required: ["audienceId"],
1779
+ },
1780
+ annotations: {
1781
+ title: "Delete Contact",
1782
+ readOnlyHint: false,
1783
+ destructiveHint: true,
1784
+ idempotentHint: true,
1785
+ openWorldHint: false,
1786
+ },
1787
+ tier: "tertiary",
1788
+ scopes: ["admin"],
1789
+ execute: async (args) => {
1790
+ const parseResult = deleteContactSchema.safeParse(args);
1791
+ if (!parseResult.success) {
1792
+ return handleValidationError(parseResult);
1793
+ }
1794
+ try {
1795
+ const { audienceId, id, email } = parseResult.data;
1796
+ // SDK requires either id or email, not both
1797
+ const payload = id
1798
+ ? { audienceId, id }
1799
+ : { audienceId, email: email };
1800
+ const result = await withRateLimitAndRetry(() => resend.contacts.remove(payload));
1801
+ if (result.error) {
1802
+ return createToolResponse(formatResendError(result.error));
1803
+ }
1804
+ return createToolResponse({
1805
+ success: true,
1806
+ message: "Contact deleted successfully",
1807
+ ...result.data,
1808
+ });
1809
+ }
1810
+ catch (error) {
1811
+ return createToolResponse(formatResendError(error));
1812
+ }
1813
+ },
1814
+ };
1815
+ }
1816
+ function createDeleteTemplateTool(resend) {
1817
+ return {
1818
+ name: "delete_template",
1819
+ description: "Delete an email template. This is a destructive operation.",
1820
+ inputSchema: {
1821
+ type: "object",
1822
+ properties: {
1823
+ id: {
1824
+ type: "string",
1825
+ description: "The template ID to delete",
1826
+ },
1827
+ },
1828
+ required: ["id"],
1829
+ },
1830
+ annotations: {
1831
+ title: "Delete Template",
1832
+ readOnlyHint: false,
1833
+ destructiveHint: true,
1834
+ idempotentHint: true,
1835
+ openWorldHint: false,
1836
+ },
1837
+ tier: "tertiary",
1838
+ scopes: ["admin"],
1839
+ execute: async (args) => {
1840
+ const parseResult = deleteTemplateSchema.safeParse(args);
1841
+ if (!parseResult.success) {
1842
+ return handleValidationError(parseResult);
1843
+ }
1844
+ try {
1845
+ const { id } = parseResult.data;
1846
+ const result = await withRateLimitAndRetry(() => resend.templates.remove(id));
1847
+ if (result.error) {
1848
+ return createToolResponse(formatResendError(result.error));
1849
+ }
1850
+ return createToolResponse({
1851
+ success: true,
1852
+ message: "Template deleted successfully",
1853
+ ...result.data,
1854
+ });
1855
+ }
1856
+ catch (error) {
1857
+ return createToolResponse(formatResendError(error));
1858
+ }
1859
+ },
1860
+ };
1861
+ }
1862
+ function createDeleteTopicTool(resend) {
1863
+ return {
1864
+ name: "delete_topic",
1865
+ description: "Delete a topic. This is a destructive operation.",
1866
+ inputSchema: {
1867
+ type: "object",
1868
+ properties: {
1869
+ id: {
1870
+ type: "string",
1871
+ description: "The topic ID to delete",
1872
+ },
1873
+ },
1874
+ required: ["id"],
1875
+ },
1876
+ annotations: {
1877
+ title: "Delete Topic",
1878
+ readOnlyHint: false,
1879
+ destructiveHint: true,
1880
+ idempotentHint: true,
1881
+ openWorldHint: false,
1882
+ },
1883
+ tier: "tertiary",
1884
+ scopes: ["admin"],
1885
+ execute: async (args) => {
1886
+ const parseResult = deleteTopicSchema.safeParse(args);
1887
+ if (!parseResult.success) {
1888
+ return handleValidationError(parseResult);
1889
+ }
1890
+ try {
1891
+ const { id } = parseResult.data;
1892
+ const result = await withRateLimitAndRetry(() => resend.topics.remove(id));
1893
+ if (result.error) {
1894
+ return createToolResponse(formatResendError(result.error));
1895
+ }
1896
+ return createToolResponse({
1897
+ success: true,
1898
+ message: "Topic deleted successfully",
1899
+ ...result.data,
1900
+ });
1901
+ }
1902
+ catch (error) {
1903
+ return createToolResponse(formatResendError(error));
1904
+ }
1905
+ },
1906
+ };
1907
+ }
1908
+ function createDeleteWebhookTool(resend) {
1909
+ return {
1910
+ name: "delete_webhook",
1911
+ description: "Delete a webhook. This is a destructive operation.",
1912
+ inputSchema: {
1913
+ type: "object",
1914
+ properties: {
1915
+ id: {
1916
+ type: "string",
1917
+ description: "The webhook ID to delete",
1918
+ },
1919
+ },
1920
+ required: ["id"],
1921
+ },
1922
+ annotations: {
1923
+ title: "Delete Webhook",
1924
+ readOnlyHint: false,
1925
+ destructiveHint: true,
1926
+ idempotentHint: true,
1927
+ openWorldHint: false,
1928
+ },
1929
+ tier: "tertiary",
1930
+ scopes: ["admin"],
1931
+ execute: async (args) => {
1932
+ const parseResult = deleteWebhookSchema.safeParse(args);
1933
+ if (!parseResult.success) {
1934
+ return handleValidationError(parseResult);
1935
+ }
1936
+ try {
1937
+ const { id } = parseResult.data;
1938
+ const result = await withRateLimitAndRetry(() => resend.webhooks.remove(id));
1939
+ if (result.error) {
1940
+ return createToolResponse(formatResendError(result.error));
1941
+ }
1942
+ return createToolResponse({
1943
+ success: true,
1944
+ message: "Webhook deleted successfully",
1945
+ ...result.data,
1946
+ });
1947
+ }
1948
+ catch (error) {
1949
+ return createToolResponse(formatResendError(error));
1950
+ }
1951
+ },
1952
+ };
1953
+ }
1954
+ function createDeleteSegmentTool(resend) {
1955
+ return {
1956
+ name: "delete_segment",
1957
+ description: "Delete a segment. This is a destructive operation.",
1958
+ inputSchema: {
1959
+ type: "object",
1960
+ properties: {
1961
+ id: {
1962
+ type: "string",
1963
+ description: "The segment ID to delete",
1964
+ },
1965
+ },
1966
+ required: ["id"],
1967
+ },
1968
+ annotations: {
1969
+ title: "Delete Segment",
1970
+ readOnlyHint: false,
1971
+ destructiveHint: true,
1972
+ idempotentHint: true,
1973
+ openWorldHint: false,
1974
+ },
1975
+ tier: "tertiary",
1976
+ scopes: ["admin"],
1977
+ execute: async (args) => {
1978
+ const parseResult = deleteSegmentSchema.safeParse(args);
1979
+ if (!parseResult.success) {
1980
+ return handleValidationError(parseResult);
1981
+ }
1982
+ try {
1983
+ const { id } = parseResult.data;
1984
+ const result = await withRateLimitAndRetry(() => resend.segments.remove(id));
1985
+ if (result.error) {
1986
+ return createToolResponse(formatResendError(result.error));
1987
+ }
1988
+ return createToolResponse({
1989
+ success: true,
1990
+ message: "Segment deleted successfully",
1991
+ ...result.data,
1992
+ });
1993
+ }
1994
+ catch (error) {
1995
+ return createToolResponse(formatResendError(error));
1996
+ }
1997
+ },
1998
+ };
1999
+ }
2000
+ function createDeleteBroadcastTool(resend) {
2001
+ return {
2002
+ name: "delete_broadcast",
2003
+ description: "Delete a broadcast. This is a destructive operation.",
2004
+ inputSchema: {
2005
+ type: "object",
2006
+ properties: {
2007
+ id: {
2008
+ type: "string",
2009
+ description: "The broadcast ID to delete",
2010
+ },
2011
+ },
2012
+ required: ["id"],
2013
+ },
2014
+ annotations: {
2015
+ title: "Delete Broadcast",
2016
+ readOnlyHint: false,
2017
+ destructiveHint: true,
2018
+ idempotentHint: true,
2019
+ openWorldHint: false,
2020
+ },
2021
+ tier: "tertiary",
2022
+ scopes: ["admin"],
2023
+ execute: async (args) => {
2024
+ const parseResult = deleteBroadcastSchema.safeParse(args);
2025
+ if (!parseResult.success) {
2026
+ return handleValidationError(parseResult);
2027
+ }
2028
+ try {
2029
+ const { id } = parseResult.data;
2030
+ const result = await withRateLimitAndRetry(() => resend.broadcasts.remove(id));
2031
+ if (result.error) {
2032
+ return createToolResponse(formatResendError(result.error));
2033
+ }
2034
+ return createToolResponse({
2035
+ success: true,
2036
+ message: "Broadcast deleted successfully",
2037
+ ...result.data,
2038
+ });
2039
+ }
2040
+ catch (error) {
2041
+ return createToolResponse(formatResendError(error));
2042
+ }
2043
+ },
2044
+ };
2045
+ }
2046
+ function createDeleteContactPropertyTool(resend) {
2047
+ return {
2048
+ name: "delete_contact_property",
2049
+ description: "Delete a contact property. This is a destructive operation.",
2050
+ inputSchema: {
2051
+ type: "object",
2052
+ properties: {
2053
+ id: {
2054
+ type: "string",
2055
+ description: "The contact property ID to delete",
2056
+ },
2057
+ },
2058
+ required: ["id"],
2059
+ },
2060
+ annotations: {
2061
+ title: "Delete Contact Property",
2062
+ readOnlyHint: false,
2063
+ destructiveHint: true,
2064
+ idempotentHint: true,
2065
+ openWorldHint: false,
2066
+ },
2067
+ tier: "tertiary",
2068
+ scopes: ["admin"],
2069
+ execute: async (args) => {
2070
+ const parseResult = deleteContactPropertySchema.safeParse(args);
2071
+ if (!parseResult.success) {
2072
+ return handleValidationError(parseResult);
2073
+ }
2074
+ try {
2075
+ const { id } = parseResult.data;
2076
+ const result = await withRateLimitAndRetry(() => resend.contactProperties.remove(id));
2077
+ if (result.error) {
2078
+ return createToolResponse(formatResendError(result.error));
2079
+ }
2080
+ return createToolResponse({
2081
+ success: true,
2082
+ message: "Contact property deleted successfully",
2083
+ ...result.data,
2084
+ });
2085
+ }
2086
+ catch (error) {
2087
+ return createToolResponse(formatResendError(error));
2088
+ }
2089
+ },
2090
+ };
2091
+ }
2092
+ // ============================================================================
2093
+ // Tool Factories - Tertiary Tools (Batch)
2094
+ // ============================================================================
2095
+ function createSendBatchEmailsTool(resend) {
2096
+ return {
2097
+ name: "send_batch_emails",
2098
+ description: "Send up to 100 emails in a single batch request.",
2099
+ inputSchema: {
2100
+ type: "object",
2101
+ properties: {
2102
+ emails: {
2103
+ type: "array",
2104
+ description: "Array of email objects (max 100)",
2105
+ items: {
2106
+ type: "object",
2107
+ properties: {
2108
+ from: { type: "string", description: "Sender email address" },
2109
+ to: { type: ["string", "array"], description: "Recipient(s)" },
2110
+ subject: { type: "string", description: "Email subject" },
2111
+ html: { type: "string", description: "HTML content" },
2112
+ text: { type: "string", description: "Plain text content" },
2113
+ cc: { type: ["string", "array"], description: "CC recipient(s)" },
2114
+ bcc: { type: ["string", "array"], description: "BCC recipient(s)" },
2115
+ reply_to: { type: ["string", "array"], description: "Reply-to address(es)" },
2116
+ headers: { type: "object", description: "Custom headers" },
2117
+ tags: { type: "array", description: "Email tags" },
2118
+ scheduled_at: { type: "string", description: "Scheduled send time (ISO 8601)" },
2119
+ },
2120
+ required: ["from", "to", "subject"],
2121
+ },
2122
+ },
2123
+ },
2124
+ required: ["emails"],
2125
+ },
2126
+ annotations: {
2127
+ title: "Send Batch Emails",
2128
+ readOnlyHint: false,
2129
+ destructiveHint: false,
2130
+ idempotentHint: false,
2131
+ openWorldHint: true,
2132
+ },
2133
+ tier: "tertiary",
2134
+ scopes: ["write"],
2135
+ execute: async (args) => {
2136
+ const parseResult = sendBatchEmailsSchema.safeParse(args);
2137
+ if (!parseResult.success) {
2138
+ return handleValidationError(parseResult);
2139
+ }
2140
+ try {
2141
+ const { emails } = parseResult.data;
2142
+ const result = await withRateLimitAndRetry(() => resend.batch.send(emails));
2143
+ if (result.error) {
2144
+ return createToolResponse(formatResendError(result.error));
2145
+ }
2146
+ return createToolResponse({
2147
+ success: true,
2148
+ message: `Batch sent: ${emails.length} emails`,
2149
+ ...result.data,
2150
+ });
2151
+ }
2152
+ catch (error) {
2153
+ return createToolResponse(formatResendError(error));
2154
+ }
2155
+ },
2156
+ };
2157
+ }
2158
+ // ============================================================================
2159
+ // Tool Factories - Tertiary Tools (Broadcast)
2160
+ // ============================================================================
2161
+ function createListBroadcastsTool(resend) {
2162
+ return {
2163
+ name: "list_broadcasts",
2164
+ description: "List all broadcasts in the account.",
2165
+ inputSchema: {
2166
+ type: "object",
2167
+ properties: {},
2168
+ },
2169
+ annotations: {
2170
+ title: "List Broadcasts",
2171
+ readOnlyHint: true,
2172
+ destructiveHint: false,
2173
+ idempotentHint: true,
2174
+ openWorldHint: false,
2175
+ },
2176
+ tier: "tertiary",
2177
+ scopes: ["read"],
2178
+ execute: async (args) => {
2179
+ const parseResult = listBroadcastsSchema.safeParse(args);
2180
+ if (!parseResult.success) {
2181
+ return handleValidationError(parseResult);
2182
+ }
2183
+ try {
2184
+ const result = await withRateLimitAndRetry(() => resend.broadcasts.list());
2185
+ if (result.error) {
2186
+ return createToolResponse(formatResendError(result.error));
2187
+ }
2188
+ return createToolResponse(result.data);
2189
+ }
2190
+ catch (error) {
2191
+ return createToolResponse(formatResendError(error));
2192
+ }
2193
+ },
2194
+ };
2195
+ }
2196
+ function createCreateBroadcastTool(resend) {
2197
+ return {
2198
+ name: "create_broadcast",
2199
+ description: "Create a new broadcast for a segment.",
2200
+ inputSchema: {
2201
+ type: "object",
2202
+ properties: {
2203
+ name: { type: "string", description: "Broadcast name" },
2204
+ segmentId: { type: "string", description: "Target segment ID" },
2205
+ from: { type: "string", description: "Sender email address" },
2206
+ subject: { type: "string", description: "Email subject" },
2207
+ html: { type: "string", description: "HTML content" },
2208
+ text: { type: "string", description: "Plain text content" },
2209
+ replyTo: { type: ["string", "array"], description: "Reply-to address(es)" },
2210
+ previewText: { type: "string", description: "Preview text" },
2211
+ },
2212
+ required: ["segmentId", "from", "subject"],
2213
+ },
2214
+ annotations: {
2215
+ title: "Create Broadcast",
2216
+ readOnlyHint: false,
2217
+ destructiveHint: false,
2218
+ idempotentHint: false,
2219
+ openWorldHint: false,
2220
+ },
2221
+ tier: "tertiary",
2222
+ scopes: ["write"],
2223
+ execute: async (args) => {
2224
+ const parseResult = createBroadcastSchema.safeParse(args);
2225
+ if (!parseResult.success) {
2226
+ return handleValidationError(parseResult);
2227
+ }
2228
+ try {
2229
+ const input = parseResult.data;
2230
+ const result = await withRateLimitAndRetry(() => resend.broadcasts.create(input));
2231
+ if (result.error) {
2232
+ return createToolResponse(formatResendError(result.error));
2233
+ }
2234
+ return createToolResponse({
2235
+ success: true,
2236
+ message: "Broadcast created successfully",
2237
+ ...result.data,
2238
+ });
2239
+ }
2240
+ catch (error) {
2241
+ return createToolResponse(formatResendError(error));
2242
+ }
2243
+ },
2244
+ };
2245
+ }
2246
+ function createGetBroadcastTool(resend) {
2247
+ return {
2248
+ name: "get_broadcast",
2249
+ description: "Get details of a specific broadcast.",
2250
+ inputSchema: {
2251
+ type: "object",
2252
+ properties: {
2253
+ id: { type: "string", description: "The broadcast ID" },
2254
+ },
2255
+ required: ["id"],
2256
+ },
2257
+ annotations: {
2258
+ title: "Get Broadcast",
2259
+ readOnlyHint: true,
2260
+ destructiveHint: false,
2261
+ idempotentHint: true,
2262
+ openWorldHint: false,
2263
+ },
2264
+ tier: "tertiary",
2265
+ scopes: ["read"],
2266
+ execute: async (args) => {
2267
+ const parseResult = getBroadcastSchema.safeParse(args);
2268
+ if (!parseResult.success) {
2269
+ return handleValidationError(parseResult);
2270
+ }
2271
+ try {
2272
+ const { id } = parseResult.data;
2273
+ const result = await withRateLimitAndRetry(() => resend.broadcasts.get(id));
2274
+ if (result.error) {
2275
+ return createToolResponse(formatResendError(result.error));
2276
+ }
2277
+ return createToolResponse(result.data);
2278
+ }
2279
+ catch (error) {
2280
+ return createToolResponse(formatResendError(error));
2281
+ }
2282
+ },
2283
+ };
2284
+ }
2285
+ function createUpdateBroadcastTool(resend) {
2286
+ return {
2287
+ name: "update_broadcast",
2288
+ description: "Update an existing broadcast.",
2289
+ inputSchema: {
2290
+ type: "object",
2291
+ properties: {
2292
+ id: { type: "string", description: "The broadcast ID" },
2293
+ name: { type: "string", description: "Broadcast name" },
2294
+ from: { type: "string", description: "Sender email address" },
2295
+ subject: { type: "string", description: "Email subject" },
2296
+ html: { type: "string", description: "HTML content" },
2297
+ text: { type: "string", description: "Plain text content" },
2298
+ replyTo: { type: ["string", "array"], description: "Reply-to address(es)" },
2299
+ previewText: { type: "string", description: "Preview text" },
2300
+ },
2301
+ required: ["id"],
2302
+ },
2303
+ annotations: {
2304
+ title: "Update Broadcast",
2305
+ readOnlyHint: false,
2306
+ destructiveHint: false,
2307
+ idempotentHint: true,
2308
+ openWorldHint: false,
2309
+ },
2310
+ tier: "tertiary",
2311
+ scopes: ["write"],
2312
+ execute: async (args) => {
2313
+ const parseResult = updateBroadcastSchema.safeParse(args);
2314
+ if (!parseResult.success) {
2315
+ return handleValidationError(parseResult);
2316
+ }
2317
+ try {
2318
+ const { id, ...updateData } = parseResult.data;
2319
+ const result = await withRateLimitAndRetry(() => resend.broadcasts.update(id, updateData));
2320
+ if (result.error) {
2321
+ return createToolResponse(formatResendError(result.error));
2322
+ }
2323
+ return createToolResponse({
2324
+ success: true,
2325
+ message: "Broadcast updated successfully",
2326
+ ...result.data,
2327
+ });
2328
+ }
2329
+ catch (error) {
2330
+ return createToolResponse(formatResendError(error));
2331
+ }
2332
+ },
2333
+ };
2334
+ }
2335
+ function createSendBroadcastTool(resend) {
2336
+ return {
2337
+ name: "send_broadcast",
2338
+ description: "Send a broadcast immediately or schedule it.",
2339
+ inputSchema: {
2340
+ type: "object",
2341
+ properties: {
2342
+ id: { type: "string", description: "The broadcast ID to send" },
2343
+ scheduledAt: { type: "string", description: "Schedule time (ISO 8601)" },
2344
+ },
2345
+ required: ["id"],
2346
+ },
2347
+ annotations: {
2348
+ title: "Send Broadcast",
2349
+ readOnlyHint: false,
2350
+ destructiveHint: false,
2351
+ idempotentHint: false,
2352
+ openWorldHint: true,
2353
+ },
2354
+ tier: "tertiary",
2355
+ scopes: ["write"],
2356
+ execute: async (args) => {
2357
+ const parseResult = sendBroadcastSchema.safeParse(args);
2358
+ if (!parseResult.success) {
2359
+ return handleValidationError(parseResult);
2360
+ }
2361
+ try {
2362
+ const { id, scheduledAt } = parseResult.data;
2363
+ const result = await withRateLimitAndRetry(() => resend.broadcasts.send(id, scheduledAt ? { scheduledAt } : undefined));
2364
+ if (result.error) {
2365
+ return createToolResponse(formatResendError(result.error));
2366
+ }
2367
+ return createToolResponse({
2368
+ success: true,
2369
+ message: "Broadcast sent successfully",
2370
+ ...result.data,
2371
+ });
2372
+ }
2373
+ catch (error) {
2374
+ return createToolResponse(formatResendError(error));
2375
+ }
2376
+ },
2377
+ };
2378
+ }
2379
+ // ============================================================================
2380
+ // Tool Factories - Tertiary Tools (Segment)
2381
+ // ============================================================================
2382
+ function createListSegmentsTool(resend) {
2383
+ return {
2384
+ name: "list_segments",
2385
+ description: "List all segments in the account.",
2386
+ inputSchema: {
2387
+ type: "object",
2388
+ properties: {},
2389
+ },
2390
+ annotations: {
2391
+ title: "List Segments",
2392
+ readOnlyHint: true,
2393
+ destructiveHint: false,
2394
+ idempotentHint: true,
2395
+ openWorldHint: false,
2396
+ },
2397
+ tier: "tertiary",
2398
+ scopes: ["read"],
2399
+ execute: async (args) => {
2400
+ const parseResult = listSegmentsSchema.safeParse(args);
2401
+ if (!parseResult.success) {
2402
+ return handleValidationError(parseResult);
2403
+ }
2404
+ try {
2405
+ const result = await withRateLimitAndRetry(() => resend.segments.list());
2406
+ if (result.error) {
2407
+ return createToolResponse(formatResendError(result.error));
2408
+ }
2409
+ return createToolResponse(result.data);
2410
+ }
2411
+ catch (error) {
2412
+ return createToolResponse(formatResendError(error));
2413
+ }
2414
+ },
2415
+ };
2416
+ }
2417
+ function createCreateSegmentTool(resend) {
2418
+ return {
2419
+ name: "create_segment",
2420
+ description: "Create a new segment.",
2421
+ inputSchema: {
2422
+ type: "object",
2423
+ properties: {
2424
+ name: { type: "string", description: "Segment name" },
2425
+ },
2426
+ required: ["name"],
2427
+ },
2428
+ annotations: {
2429
+ title: "Create Segment",
2430
+ readOnlyHint: false,
2431
+ destructiveHint: false,
2432
+ idempotentHint: false,
2433
+ openWorldHint: false,
2434
+ },
2435
+ tier: "tertiary",
2436
+ scopes: ["write"],
2437
+ execute: async (args) => {
2438
+ const parseResult = createSegmentSchema.safeParse(args);
2439
+ if (!parseResult.success) {
2440
+ return handleValidationError(parseResult);
2441
+ }
2442
+ try {
2443
+ const input = parseResult.data;
2444
+ const result = await withRateLimitAndRetry(() => resend.segments.create(input));
2445
+ if (result.error) {
2446
+ return createToolResponse(formatResendError(result.error));
2447
+ }
2448
+ return createToolResponse({
2449
+ success: true,
2450
+ message: "Segment created successfully",
2451
+ ...result.data,
2452
+ });
2453
+ }
2454
+ catch (error) {
2455
+ return createToolResponse(formatResendError(error));
2456
+ }
2457
+ },
2458
+ };
2459
+ }
2460
+ function createGetSegmentTool(resend) {
2461
+ return {
2462
+ name: "get_segment",
2463
+ description: "Get details of a specific segment.",
2464
+ inputSchema: {
2465
+ type: "object",
2466
+ properties: {
2467
+ id: { type: "string", description: "The segment ID" },
2468
+ },
2469
+ required: ["id"],
2470
+ },
2471
+ annotations: {
2472
+ title: "Get Segment",
2473
+ readOnlyHint: true,
2474
+ destructiveHint: false,
2475
+ idempotentHint: true,
2476
+ openWorldHint: false,
2477
+ },
2478
+ tier: "tertiary",
2479
+ scopes: ["read"],
2480
+ execute: async (args) => {
2481
+ const parseResult = getSegmentSchema.safeParse(args);
2482
+ if (!parseResult.success) {
2483
+ return handleValidationError(parseResult);
2484
+ }
2485
+ try {
2486
+ const { id } = parseResult.data;
2487
+ const result = await withRateLimitAndRetry(() => resend.segments.get(id));
2488
+ if (result.error) {
2489
+ return createToolResponse(formatResendError(result.error));
2490
+ }
2491
+ return createToolResponse(result.data);
2492
+ }
2493
+ catch (error) {
2494
+ return createToolResponse(formatResendError(error));
2495
+ }
2496
+ },
2497
+ };
2498
+ }
2499
+ function createAddContactToSegmentTool(resend) {
2500
+ return {
2501
+ name: "add_contact_to_segment",
2502
+ description: "Add a contact to a segment.",
2503
+ inputSchema: {
2504
+ type: "object",
2505
+ properties: {
2506
+ segmentId: { type: "string", description: "The segment ID" },
2507
+ contactId: { type: "string", description: "The contact ID (use contactId or email)" },
2508
+ email: { type: "string", description: "The contact email (use contactId or email)" },
2509
+ },
2510
+ required: ["segmentId"],
2511
+ },
2512
+ annotations: {
2513
+ title: "Add Contact to Segment",
2514
+ readOnlyHint: false,
2515
+ destructiveHint: false,
2516
+ idempotentHint: true,
2517
+ openWorldHint: false,
2518
+ },
2519
+ tier: "tertiary",
2520
+ scopes: ["write"],
2521
+ execute: async (args) => {
2522
+ const parseResult = addContactToSegmentSchema.safeParse(args);
2523
+ if (!parseResult.success) {
2524
+ return handleValidationError(parseResult);
2525
+ }
2526
+ try {
2527
+ const { segmentId, contactId, email } = parseResult.data;
2528
+ // SDK requires either contactId or email, not both
2529
+ const payload = contactId
2530
+ ? { segmentId, contactId }
2531
+ : { segmentId, email: email };
2532
+ const result = await withRateLimitAndRetry(() => resend.contacts.segments.add(payload));
2533
+ if (result.error) {
2534
+ return createToolResponse(formatResendError(result.error));
2535
+ }
2536
+ return createToolResponse({
2537
+ success: true,
2538
+ message: "Contact added to segment successfully",
2539
+ ...result.data,
2540
+ });
2541
+ }
2542
+ catch (error) {
2543
+ return createToolResponse(formatResendError(error));
2544
+ }
2545
+ },
2546
+ };
2547
+ }
2548
+ function createRemoveContactFromSegmentTool(resend) {
2549
+ return {
2550
+ name: "remove_contact_from_segment",
2551
+ description: "Remove a contact from a segment.",
2552
+ inputSchema: {
2553
+ type: "object",
2554
+ properties: {
2555
+ segmentId: { type: "string", description: "The segment ID" },
2556
+ contactId: { type: "string", description: "The contact ID (use contactId or email)" },
2557
+ email: { type: "string", description: "The contact email (use contactId or email)" },
2558
+ },
2559
+ required: ["segmentId"],
2560
+ },
2561
+ annotations: {
2562
+ title: "Remove Contact from Segment",
2563
+ readOnlyHint: false,
2564
+ destructiveHint: false,
2565
+ idempotentHint: true,
2566
+ openWorldHint: false,
2567
+ },
2568
+ tier: "tertiary",
2569
+ scopes: ["write"],
2570
+ execute: async (args) => {
2571
+ const parseResult = removeContactFromSegmentSchema.safeParse(args);
2572
+ if (!parseResult.success) {
2573
+ return handleValidationError(parseResult);
2574
+ }
2575
+ try {
2576
+ const { segmentId, contactId, email } = parseResult.data;
2577
+ // SDK requires either contactId or email, not both
2578
+ const payload = contactId
2579
+ ? { segmentId, contactId }
2580
+ : { segmentId, email: email };
2581
+ const result = await withRateLimitAndRetry(() => resend.contacts.segments.remove(payload));
2582
+ if (result.error) {
2583
+ return createToolResponse(formatResendError(result.error));
2584
+ }
2585
+ return createToolResponse({
2586
+ success: true,
2587
+ message: "Contact removed from segment successfully",
2588
+ ...result.data,
2589
+ });
2590
+ }
2591
+ catch (error) {
2592
+ return createToolResponse(formatResendError(error));
2593
+ }
2594
+ },
2595
+ };
2596
+ }
2597
+ // ============================================================================
2598
+ // Tool Factories - Tertiary Tools (Contact Property)
2599
+ // ============================================================================
2600
+ function createListContactPropertiesTool(resend) {
2601
+ return {
2602
+ name: "list_contact_properties",
2603
+ description: "List all contact properties.",
2604
+ inputSchema: {
2605
+ type: "object",
2606
+ properties: {},
2607
+ },
2608
+ annotations: {
2609
+ title: "List Contact Properties",
2610
+ readOnlyHint: true,
2611
+ destructiveHint: false,
2612
+ idempotentHint: true,
2613
+ openWorldHint: false,
2614
+ },
2615
+ tier: "tertiary",
2616
+ scopes: ["read"],
2617
+ execute: async (args) => {
2618
+ const parseResult = listContactPropertiesSchema.safeParse(args);
2619
+ if (!parseResult.success) {
2620
+ return handleValidationError(parseResult);
2621
+ }
2622
+ try {
2623
+ const result = await withRateLimitAndRetry(() => resend.contactProperties.list());
2624
+ if (result.error) {
2625
+ return createToolResponse(formatResendError(result.error));
2626
+ }
2627
+ return createToolResponse(result.data);
2628
+ }
2629
+ catch (error) {
2630
+ return createToolResponse(formatResendError(error));
2631
+ }
2632
+ },
2633
+ };
2634
+ }
2635
+ function createCreateContactPropertyTool(resend) {
2636
+ return {
2637
+ name: "create_contact_property",
2638
+ description: "Create a new contact property.",
2639
+ inputSchema: {
2640
+ type: "object",
2641
+ properties: {
2642
+ key: { type: "string", description: "Property key" },
2643
+ type: { type: "string", enum: ["string", "number"], description: "Property type" },
2644
+ fallbackValue: { type: ["string", "number", "null"], description: "Default value" },
2645
+ },
2646
+ required: ["key", "type"],
2647
+ },
2648
+ annotations: {
2649
+ title: "Create Contact Property",
2650
+ readOnlyHint: false,
2651
+ destructiveHint: false,
2652
+ idempotentHint: false,
2653
+ openWorldHint: false,
2654
+ },
2655
+ tier: "tertiary",
2656
+ scopes: ["write"],
2657
+ execute: async (args) => {
2658
+ const parseResult = createContactPropertySchema.safeParse(args);
2659
+ if (!parseResult.success) {
2660
+ return handleValidationError(parseResult);
2661
+ }
2662
+ try {
2663
+ const input = parseResult.data;
2664
+ const result = await withRateLimitAndRetry(() => resend.contactProperties.create(input));
2665
+ if (result.error) {
2666
+ return createToolResponse(formatResendError(result.error));
2667
+ }
2668
+ return createToolResponse({
2669
+ success: true,
2670
+ message: "Contact property created successfully",
2671
+ ...result.data,
2672
+ });
2673
+ }
2674
+ catch (error) {
2675
+ return createToolResponse(formatResendError(error));
2676
+ }
2677
+ },
2678
+ };
2679
+ }
2680
+ function createGetContactPropertyTool(resend) {
2681
+ return {
2682
+ name: "get_contact_property",
2683
+ description: "Get details of a specific contact property.",
2684
+ inputSchema: {
2685
+ type: "object",
2686
+ properties: {
2687
+ id: { type: "string", description: "The contact property ID" },
2688
+ },
2689
+ required: ["id"],
2690
+ },
2691
+ annotations: {
2692
+ title: "Get Contact Property",
2693
+ readOnlyHint: true,
2694
+ destructiveHint: false,
2695
+ idempotentHint: true,
2696
+ openWorldHint: false,
2697
+ },
2698
+ tier: "tertiary",
2699
+ scopes: ["read"],
2700
+ execute: async (args) => {
2701
+ const parseResult = getContactPropertySchema.safeParse(args);
2702
+ if (!parseResult.success) {
2703
+ return handleValidationError(parseResult);
2704
+ }
2705
+ try {
2706
+ const { id } = parseResult.data;
2707
+ const result = await withRateLimitAndRetry(() => resend.contactProperties.get(id));
2708
+ if (result.error) {
2709
+ return createToolResponse(formatResendError(result.error));
2710
+ }
2711
+ return createToolResponse(result.data);
2712
+ }
2713
+ catch (error) {
2714
+ return createToolResponse(formatResendError(error));
2715
+ }
2716
+ },
2717
+ };
2718
+ }
2719
+ function createUpdateContactPropertyTool(resend) {
2720
+ return {
2721
+ name: "update_contact_property",
2722
+ description: "Update a contact property.",
2723
+ inputSchema: {
2724
+ type: "object",
2725
+ properties: {
2726
+ id: { type: "string", description: "The contact property ID" },
2727
+ fallbackValue: { type: ["string", "number", "null"], description: "New default value" },
2728
+ },
2729
+ required: ["id"],
2730
+ },
2731
+ annotations: {
2732
+ title: "Update Contact Property",
2733
+ readOnlyHint: false,
2734
+ destructiveHint: false,
2735
+ idempotentHint: true,
2736
+ openWorldHint: false,
2737
+ },
2738
+ tier: "tertiary",
2739
+ scopes: ["write"],
2740
+ execute: async (args) => {
2741
+ const parseResult = updateContactPropertySchema.safeParse(args);
2742
+ if (!parseResult.success) {
2743
+ return handleValidationError(parseResult);
2744
+ }
2745
+ try {
2746
+ const { id, ...updateData } = parseResult.data;
2747
+ const result = await withRateLimitAndRetry(() => resend.contactProperties.update({ id, ...updateData }));
2748
+ if (result.error) {
2749
+ return createToolResponse(formatResendError(result.error));
2750
+ }
2751
+ return createToolResponse({
2752
+ success: true,
2753
+ message: "Contact property updated successfully",
2754
+ ...result.data,
2755
+ });
2756
+ }
2757
+ catch (error) {
2758
+ return createToolResponse(formatResendError(error));
2759
+ }
2760
+ },
2761
+ };
2762
+ }
2763
+ // ============================================================================
2764
+ // Tool Factories - Tertiary Tools (Inbound Email)
2765
+ // ============================================================================
2766
+ function createListReceivedEmailsTool(resend) {
2767
+ return {
2768
+ name: "list_received_emails",
2769
+ description: "List all received (inbound) emails.",
2770
+ inputSchema: {
2771
+ type: "object",
2772
+ properties: {},
2773
+ },
2774
+ annotations: {
2775
+ title: "List Received Emails",
2776
+ readOnlyHint: true,
2777
+ destructiveHint: false,
2778
+ idempotentHint: true,
2779
+ openWorldHint: false,
2780
+ },
2781
+ tier: "tertiary",
2782
+ scopes: ["read"],
2783
+ execute: async (args) => {
2784
+ const parseResult = listReceivedEmailsSchema.safeParse(args);
2785
+ if (!parseResult.success) {
2786
+ return handleValidationError(parseResult);
2787
+ }
2788
+ try {
2789
+ const result = await withRateLimitAndRetry(() => resend.emails.receiving.list());
2790
+ if (result.error) {
2791
+ return createToolResponse(formatResendError(result.error));
2792
+ }
2793
+ return createToolResponse(result.data);
2794
+ }
2795
+ catch (error) {
2796
+ return createToolResponse(formatResendError(error));
2797
+ }
2798
+ },
2799
+ };
2800
+ }
2801
+ function createGetReceivedEmailTool(resend) {
2802
+ return {
2803
+ name: "get_received_email",
2804
+ description: "Get details of a specific received email.",
2805
+ inputSchema: {
2806
+ type: "object",
2807
+ properties: {
2808
+ id: { type: "string", description: "The received email ID" },
2809
+ },
2810
+ required: ["id"],
2811
+ },
2812
+ annotations: {
2813
+ title: "Get Received Email",
2814
+ readOnlyHint: true,
2815
+ destructiveHint: false,
2816
+ idempotentHint: true,
2817
+ openWorldHint: false,
2818
+ },
2819
+ tier: "tertiary",
2820
+ scopes: ["read"],
2821
+ execute: async (args) => {
2822
+ const parseResult = getReceivedEmailSchema.safeParse(args);
2823
+ if (!parseResult.success) {
2824
+ return handleValidationError(parseResult);
2825
+ }
2826
+ try {
2827
+ const { id } = parseResult.data;
2828
+ const result = await withRateLimitAndRetry(() => resend.emails.receiving.get(id));
2829
+ if (result.error) {
2830
+ return createToolResponse(formatResendError(result.error));
2831
+ }
2832
+ return createToolResponse(result.data);
2833
+ }
2834
+ catch (error) {
2835
+ return createToolResponse(formatResendError(error));
2836
+ }
2837
+ },
2838
+ };
2839
+ }
2840
+ function createListReceivedEmailAttachmentsTool(resend) {
2841
+ return {
2842
+ name: "list_received_email_attachments",
2843
+ description: "List attachments of a received email.",
2844
+ inputSchema: {
2845
+ type: "object",
2846
+ properties: {
2847
+ emailId: { type: "string", description: "The received email ID" },
2848
+ },
2849
+ required: ["emailId"],
2850
+ },
2851
+ annotations: {
2852
+ title: "List Received Email Attachments",
2853
+ readOnlyHint: true,
2854
+ destructiveHint: false,
2855
+ idempotentHint: true,
2856
+ openWorldHint: false,
2857
+ },
2858
+ tier: "tertiary",
2859
+ scopes: ["read"],
2860
+ execute: async (args) => {
2861
+ const parseResult = listReceivedEmailAttachmentsSchema.safeParse(args);
2862
+ if (!parseResult.success) {
2863
+ return handleValidationError(parseResult);
2864
+ }
2865
+ try {
2866
+ const { emailId } = parseResult.data;
2867
+ const result = await withRateLimitAndRetry(() => resend.emails.receiving.attachments.list({ emailId }));
2868
+ if (result.error) {
2869
+ return createToolResponse(formatResendError(result.error));
2870
+ }
2871
+ return createToolResponse(result.data);
2872
+ }
2873
+ catch (error) {
2874
+ return createToolResponse(formatResendError(error));
2875
+ }
2876
+ },
2877
+ };
2878
+ }
2879
+ function createGetReceivedEmailAttachmentTool(resend) {
2880
+ return {
2881
+ name: "get_received_email_attachment",
2882
+ description: "Get a specific attachment from a received email.",
2883
+ inputSchema: {
2884
+ type: "object",
2885
+ properties: {
2886
+ emailId: { type: "string", description: "The received email ID" },
2887
+ id: { type: "string", description: "The attachment ID" },
2888
+ },
2889
+ required: ["emailId", "id"],
2890
+ },
2891
+ annotations: {
2892
+ title: "Get Received Email Attachment",
2893
+ readOnlyHint: true,
2894
+ destructiveHint: false,
2895
+ idempotentHint: true,
2896
+ openWorldHint: false,
2897
+ },
2898
+ tier: "tertiary",
2899
+ scopes: ["read"],
2900
+ execute: async (args) => {
2901
+ const parseResult = getReceivedEmailAttachmentSchema.safeParse(args);
2902
+ if (!parseResult.success) {
2903
+ return handleValidationError(parseResult);
2904
+ }
2905
+ try {
2906
+ const { emailId, id } = parseResult.data;
2907
+ const result = await withRateLimitAndRetry(() => resend.emails.receiving.attachments.get({ emailId, id }));
2908
+ if (result.error) {
2909
+ return createToolResponse(formatResendError(result.error));
2910
+ }
2911
+ return createToolResponse(result.data);
2912
+ }
2913
+ catch (error) {
2914
+ return createToolResponse(formatResendError(error));
2915
+ }
2916
+ },
2917
+ };
2918
+ }
2919
+ // ============================================================================
2920
+ // Tool Factories - Tertiary Tools (Sent Email Attachments)
2921
+ // ============================================================================
2922
+ function createListEmailAttachmentsTool(resend) {
2923
+ return {
2924
+ name: "list_email_attachments",
2925
+ description: "List attachments of a sent email.",
2926
+ inputSchema: {
2927
+ type: "object",
2928
+ properties: {
2929
+ emailId: { type: "string", description: "The sent email ID" },
2930
+ },
2931
+ required: ["emailId"],
2932
+ },
2933
+ annotations: {
2934
+ title: "List Email Attachments",
2935
+ readOnlyHint: true,
2936
+ destructiveHint: false,
2937
+ idempotentHint: true,
2938
+ openWorldHint: false,
2939
+ },
2940
+ tier: "tertiary",
2941
+ scopes: ["read"],
2942
+ execute: async (args) => {
2943
+ const parseResult = listEmailAttachmentsSchema.safeParse(args);
2944
+ if (!parseResult.success) {
2945
+ return handleValidationError(parseResult);
2946
+ }
2947
+ try {
2948
+ const { emailId } = parseResult.data;
2949
+ const result = await withRateLimitAndRetry(() => resend.emails.attachments.list({ emailId }));
2950
+ if (result.error) {
2951
+ return createToolResponse(formatResendError(result.error));
2952
+ }
2953
+ return createToolResponse(result.data);
2954
+ }
2955
+ catch (error) {
2956
+ return createToolResponse(formatResendError(error));
2957
+ }
2958
+ },
2959
+ };
2960
+ }
2961
+ function createGetEmailAttachmentTool(resend) {
2962
+ return {
2963
+ name: "get_email_attachment",
2964
+ description: "Get a specific attachment from a sent email.",
2965
+ inputSchema: {
2966
+ type: "object",
2967
+ properties: {
2968
+ emailId: { type: "string", description: "The sent email ID" },
2969
+ id: { type: "string", description: "The attachment ID" },
2970
+ },
2971
+ required: ["emailId", "id"],
2972
+ },
2973
+ annotations: {
2974
+ title: "Get Email Attachment",
2975
+ readOnlyHint: true,
2976
+ destructiveHint: false,
2977
+ idempotentHint: true,
2978
+ openWorldHint: false,
2979
+ },
2980
+ tier: "tertiary",
2981
+ scopes: ["read"],
2982
+ execute: async (args) => {
2983
+ const parseResult = getEmailAttachmentSchema.safeParse(args);
2984
+ if (!parseResult.success) {
2985
+ return handleValidationError(parseResult);
2986
+ }
2987
+ try {
2988
+ const { emailId, id } = parseResult.data;
2989
+ const result = await withRateLimitAndRetry(() => resend.emails.attachments.get({ emailId, id }));
2990
+ if (result.error) {
2991
+ return createToolResponse(formatResendError(result.error));
2992
+ }
2993
+ return createToolResponse(result.data);
2994
+ }
2995
+ catch (error) {
2996
+ return createToolResponse(formatResendError(error));
2997
+ }
2998
+ },
2999
+ };
3000
+ }
3001
+ // ============================================================================
3002
+ // Tool Factories - Tertiary Tools (Topic Advanced)
3003
+ // ============================================================================
3004
+ function createGetTopicTool(resend) {
3005
+ return {
3006
+ name: "get_topic",
3007
+ description: "Get details of a specific topic.",
3008
+ inputSchema: {
3009
+ type: "object",
3010
+ properties: {
3011
+ id: { type: "string", description: "The topic ID" },
3012
+ },
3013
+ required: ["id"],
3014
+ },
3015
+ annotations: {
3016
+ title: "Get Topic",
3017
+ readOnlyHint: true,
3018
+ destructiveHint: false,
3019
+ idempotentHint: true,
3020
+ openWorldHint: false,
3021
+ },
3022
+ tier: "tertiary",
3023
+ scopes: ["read"],
3024
+ execute: async (args) => {
3025
+ const parseResult = getTopicSchema.safeParse(args);
3026
+ if (!parseResult.success) {
3027
+ return handleValidationError(parseResult);
3028
+ }
3029
+ try {
3030
+ const { id } = parseResult.data;
3031
+ const result = await withRateLimitAndRetry(() => resend.topics.get(id));
3032
+ if (result.error) {
3033
+ return createToolResponse(formatResendError(result.error));
3034
+ }
3035
+ return createToolResponse(result.data);
3036
+ }
3037
+ catch (error) {
3038
+ return createToolResponse(formatResendError(error));
3039
+ }
3040
+ },
3041
+ };
3042
+ }
3043
+ function createUpdateTopicTool(resend) {
3044
+ return {
3045
+ name: "update_topic",
3046
+ description: "Update a topic.",
3047
+ inputSchema: {
3048
+ type: "object",
3049
+ properties: {
3050
+ id: { type: "string", description: "The topic ID" },
3051
+ name: { type: "string", description: "New topic name" },
3052
+ description: { type: "string", description: "New topic description" },
3053
+ },
3054
+ required: ["id"],
3055
+ },
3056
+ annotations: {
3057
+ title: "Update Topic",
3058
+ readOnlyHint: false,
3059
+ destructiveHint: false,
3060
+ idempotentHint: true,
3061
+ openWorldHint: false,
3062
+ },
3063
+ tier: "tertiary",
3064
+ scopes: ["write"],
3065
+ execute: async (args) => {
3066
+ const parseResult = updateTopicSchema.safeParse(args);
3067
+ if (!parseResult.success) {
3068
+ return handleValidationError(parseResult);
3069
+ }
3070
+ try {
3071
+ const { id, ...updateData } = parseResult.data;
3072
+ const result = await withRateLimitAndRetry(() => resend.topics.update({ id, ...updateData }));
3073
+ if (result.error) {
3074
+ return createToolResponse(formatResendError(result.error));
3075
+ }
3076
+ return createToolResponse({
3077
+ success: true,
3078
+ message: "Topic updated successfully",
3079
+ ...result.data,
3080
+ });
3081
+ }
3082
+ catch (error) {
3083
+ return createToolResponse(formatResendError(error));
3084
+ }
3085
+ },
3086
+ };
3087
+ }
3088
+ function createGetContactTopicsTool(resend) {
3089
+ return {
3090
+ name: "get_contact_topics",
3091
+ description: "Get topic subscriptions for a contact.",
3092
+ inputSchema: {
3093
+ type: "object",
3094
+ properties: {
3095
+ id: { type: "string", description: "The contact ID (use id or email)" },
3096
+ email: { type: "string", description: "The contact email (use id or email)" },
3097
+ },
3098
+ },
3099
+ annotations: {
3100
+ title: "Get Contact Topics",
3101
+ readOnlyHint: true,
3102
+ destructiveHint: false,
3103
+ idempotentHint: true,
3104
+ openWorldHint: false,
3105
+ },
3106
+ tier: "tertiary",
3107
+ scopes: ["read"],
3108
+ execute: async (args) => {
3109
+ const parseResult = getContactTopicsSchema.safeParse(args);
3110
+ if (!parseResult.success) {
3111
+ return handleValidationError(parseResult);
3112
+ }
3113
+ try {
3114
+ const { id, email } = parseResult.data;
3115
+ const result = await withRateLimitAndRetry(() => resend.contacts.topics.list({ id, email }));
3116
+ if (result.error) {
3117
+ return createToolResponse(formatResendError(result.error));
3118
+ }
3119
+ return createToolResponse(result.data);
3120
+ }
3121
+ catch (error) {
3122
+ return createToolResponse(formatResendError(error));
3123
+ }
3124
+ },
3125
+ };
3126
+ }
3127
+ function createUpdateContactTopicsTool(resend) {
3128
+ return {
3129
+ name: "update_contact_topics",
3130
+ description: "Update topic subscriptions for a contact.",
3131
+ inputSchema: {
3132
+ type: "object",
3133
+ properties: {
3134
+ id: { type: "string", description: "The contact ID (use id or email)" },
3135
+ email: { type: "string", description: "The contact email (use id or email)" },
3136
+ topics: {
3137
+ type: "array",
3138
+ description: "Topic subscriptions to update",
3139
+ items: {
3140
+ type: "object",
3141
+ properties: {
3142
+ id: { type: "string", description: "Topic ID" },
3143
+ subscription: { type: "string", enum: ["opt_in", "opt_out"], description: "Subscription status" },
3144
+ },
3145
+ required: ["id", "subscription"],
3146
+ },
3147
+ },
3148
+ },
3149
+ required: ["topics"],
3150
+ },
3151
+ annotations: {
3152
+ title: "Update Contact Topics",
3153
+ readOnlyHint: false,
3154
+ destructiveHint: false,
3155
+ idempotentHint: true,
3156
+ openWorldHint: false,
3157
+ },
3158
+ tier: "tertiary",
3159
+ scopes: ["write"],
3160
+ execute: async (args) => {
3161
+ const parseResult = updateContactTopicsSchema.safeParse(args);
3162
+ if (!parseResult.success) {
3163
+ return handleValidationError(parseResult);
3164
+ }
3165
+ try {
3166
+ const { id, email, topics } = parseResult.data;
3167
+ const result = await withRateLimitAndRetry(() => resend.contacts.topics.update({ id, email, topics }));
3168
+ if (result.error) {
3169
+ return createToolResponse(formatResendError(result.error));
3170
+ }
3171
+ return createToolResponse({
3172
+ success: true,
3173
+ message: "Contact topics updated successfully",
3174
+ ...result.data,
3175
+ });
3176
+ }
3177
+ catch (error) {
3178
+ return createToolResponse(formatResendError(error));
3179
+ }
3180
+ },
3181
+ };
3182
+ }
3183
+ // ============================================================================
3184
+ // Tool Factories - Tertiary Tools (Contact Segments)
3185
+ // ============================================================================
3186
+ function createListContactSegmentsTool(resend) {
3187
+ return {
3188
+ name: "list_contact_segments",
3189
+ description: "List segments that a contact belongs to.",
3190
+ inputSchema: {
3191
+ type: "object",
3192
+ properties: {
3193
+ contactId: { type: "string", description: "The contact ID (use contactId or email)" },
3194
+ email: { type: "string", description: "The contact email (use contactId or email)" },
3195
+ },
3196
+ },
3197
+ annotations: {
3198
+ title: "List Contact Segments",
3199
+ readOnlyHint: true,
3200
+ destructiveHint: false,
3201
+ idempotentHint: true,
3202
+ openWorldHint: false,
3203
+ },
3204
+ tier: "tertiary",
3205
+ scopes: ["read"],
3206
+ execute: async (args) => {
3207
+ const parseResult = listContactSegmentsSchema.safeParse(args);
3208
+ if (!parseResult.success) {
3209
+ return handleValidationError(parseResult);
3210
+ }
3211
+ try {
3212
+ const data = parseResult.data;
3213
+ // SDK expects contactId or email, not both
3214
+ const payload = "contactId" in data && data.contactId
3215
+ ? { contactId: data.contactId }
3216
+ : { email: data.email };
3217
+ const result = await withRateLimitAndRetry(() => resend.contacts.segments.list(payload));
3218
+ if (result.error) {
3219
+ return createToolResponse(formatResendError(result.error));
3220
+ }
3221
+ return createToolResponse(result.data);
3222
+ }
3223
+ catch (error) {
3224
+ return createToolResponse(formatResendError(error));
3225
+ }
3226
+ },
3227
+ };
3228
+ }
3229
+ // ============================================================================
3230
+ // Public API
3231
+ // ============================================================================
3232
+ /**
3233
+ * Create all tool definitions with Resend client.
3234
+ * Returns array of ToolDefinition objects ready for registry.
3235
+ *
3236
+ * If resend is null, only the documentation search tool is returned
3237
+ * (docs-only mode when no API key is provided).
3238
+ *
3239
+ * @param resend - Resend client instance or null for docs-only mode
3240
+ * @returns Array of tool definitions
3241
+ */
3242
+ export function createToolDefinitions(resend) {
3243
+ // Docs-only mode - return only the search tool
3244
+ if (!resend) {
3245
+ return [createSearchDocsTool()];
3246
+ }
3247
+ return [
3248
+ // Core tools
3249
+ createSendEmailTool(resend),
3250
+ createGetEmailTool(resend),
3251
+ createListEmailsTool(resend),
3252
+ createListDomainsTool(resend),
3253
+ createSearchDocsTool(),
3254
+ // Secondary - Domain
3255
+ createGetDomainTool(resend),
3256
+ createCreateDomainTool(resend),
3257
+ createUpdateDomainTool(resend),
3258
+ createVerifyDomainTool(resend),
3259
+ // Secondary - Email
3260
+ createUpdateEmailTool(resend),
3261
+ createCancelEmailTool(resend),
3262
+ // Secondary - Contact
3263
+ createListContactsTool(resend),
3264
+ createCreateContactTool(resend),
3265
+ createGetContactTool(resend),
3266
+ createUpdateContactTool(resend),
3267
+ // Secondary - Template
3268
+ createListTemplatesTool(resend),
3269
+ createCreateTemplateTool(resend),
3270
+ createGetTemplateTool(resend),
3271
+ createUpdateTemplateTool(resend),
3272
+ createPublishTemplateTool(resend),
3273
+ createDuplicateTemplateTool(resend),
3274
+ // Secondary - Webhook
3275
+ createListWebhooksTool(resend),
3276
+ createCreateWebhookTool(resend),
3277
+ createGetWebhookTool(resend),
3278
+ createUpdateWebhookTool(resend),
3279
+ // Secondary - Audience
3280
+ createListAudiencesTool(resend),
3281
+ createCreateAudienceTool(resend),
3282
+ createGetAudienceTool(resend),
3283
+ // Tertiary - Destructive
3284
+ createDeleteDomainTool(resend),
3285
+ createDeleteContactTool(resend),
3286
+ createDeleteTemplateTool(resend),
3287
+ createDeleteTopicTool(resend),
3288
+ createDeleteWebhookTool(resend),
3289
+ createDeleteSegmentTool(resend),
3290
+ createDeleteBroadcastTool(resend),
3291
+ createDeleteContactPropertyTool(resend),
3292
+ // Tertiary - Batch
3293
+ createSendBatchEmailsTool(resend),
3294
+ // Tertiary - Broadcast
3295
+ createListBroadcastsTool(resend),
3296
+ createCreateBroadcastTool(resend),
3297
+ createGetBroadcastTool(resend),
3298
+ createUpdateBroadcastTool(resend),
3299
+ createSendBroadcastTool(resend),
3300
+ // Tertiary - Segment
3301
+ createListSegmentsTool(resend),
3302
+ createCreateSegmentTool(resend),
3303
+ createGetSegmentTool(resend),
3304
+ createAddContactToSegmentTool(resend),
3305
+ createRemoveContactFromSegmentTool(resend),
3306
+ // Tertiary - Contact Property
3307
+ createListContactPropertiesTool(resend),
3308
+ createCreateContactPropertyTool(resend),
3309
+ createGetContactPropertyTool(resend),
3310
+ createUpdateContactPropertyTool(resend),
3311
+ // Tertiary - Inbound Email
3312
+ createListReceivedEmailsTool(resend),
3313
+ createGetReceivedEmailTool(resend),
3314
+ createListReceivedEmailAttachmentsTool(resend),
3315
+ createGetReceivedEmailAttachmentTool(resend),
3316
+ // Tertiary - Sent Email Attachments
3317
+ createListEmailAttachmentsTool(resend),
3318
+ createGetEmailAttachmentTool(resend),
3319
+ // Tertiary - Topic Advanced
3320
+ createGetTopicTool(resend),
3321
+ createUpdateTopicTool(resend),
3322
+ createGetContactTopicsTool(resend),
3323
+ createUpdateContactTopicsTool(resend),
3324
+ // Tertiary - Contact Segments
3325
+ createListContactSegmentsTool(resend),
3326
+ ];
3327
+ }
3328
+ /**
3329
+ * Get tool names by tier.
3330
+ * Useful for verification and debugging.
3331
+ */
3332
+ export function getToolNamesByTier() {
3333
+ return {
3334
+ core: [
3335
+ "send_email",
3336
+ "get_email",
3337
+ "list_emails",
3338
+ "list_domains",
3339
+ "search_resend_documentation",
3340
+ ],
3341
+ secondary: [
3342
+ "get_domain",
3343
+ "create_domain",
3344
+ "update_domain",
3345
+ "verify_domain",
3346
+ "update_email",
3347
+ "cancel_email",
3348
+ "list_contacts",
3349
+ "create_contact",
3350
+ "get_contact",
3351
+ "update_contact",
3352
+ "list_templates",
3353
+ "create_template",
3354
+ "get_template",
3355
+ "update_template",
3356
+ "publish_template",
3357
+ "duplicate_template",
3358
+ "list_webhooks",
3359
+ "create_webhook",
3360
+ "get_webhook",
3361
+ "update_webhook",
3362
+ "list_audiences",
3363
+ "create_audience",
3364
+ "get_audience",
3365
+ ],
3366
+ tertiary: [
3367
+ // Destructive
3368
+ "delete_domain",
3369
+ "delete_contact",
3370
+ "delete_template",
3371
+ "delete_topic",
3372
+ "delete_webhook",
3373
+ "delete_segment",
3374
+ "delete_broadcast",
3375
+ "delete_contact_property",
3376
+ // Batch
3377
+ "send_batch_emails",
3378
+ // Broadcast
3379
+ "list_broadcasts",
3380
+ "create_broadcast",
3381
+ "get_broadcast",
3382
+ "update_broadcast",
3383
+ "send_broadcast",
3384
+ // Segment
3385
+ "list_segments",
3386
+ "create_segment",
3387
+ "get_segment",
3388
+ "add_contact_to_segment",
3389
+ "remove_contact_from_segment",
3390
+ // Contact Property
3391
+ "list_contact_properties",
3392
+ "create_contact_property",
3393
+ "get_contact_property",
3394
+ "update_contact_property",
3395
+ // Inbound Email
3396
+ "list_received_emails",
3397
+ "get_received_email",
3398
+ "list_received_email_attachments",
3399
+ "get_received_email_attachment",
3400
+ // Sent Email Attachments
3401
+ "list_email_attachments",
3402
+ "get_email_attachment",
3403
+ // Topic Advanced
3404
+ "get_topic",
3405
+ "update_topic",
3406
+ "get_contact_topics",
3407
+ "update_contact_topics",
3408
+ // Contact Segments
3409
+ "list_contact_segments",
3410
+ ],
3411
+ };
3412
+ }
3413
+ //# sourceMappingURL=index.js.map