import { z } from 'zod'; import type { SendGridClient } from '../client/sendgrid-client.js'; const ListContactsInput = z.object({ page_size: z.number().min(1).max(100).default(50).describe('Number of contacts per page (1-100)'), page_token: z.string().optional().describe('Pagination cursor from previous response'), }); const GetContactInput = z.object({ contact_id: z.string().describe('SendGrid contact ID'), }); const CreateContactsInput = z.object({ contacts: z.array(z.object({ email: z.string().email().describe('Contact email address (required)'), first_name: z.string().optional(), last_name: z.string().optional(), custom_fields: z.record(z.unknown()).optional().describe('Custom field values'), list_ids: z.array(z.string()).optional().describe('List IDs to add contact to'), })).describe('Array of contacts to create or update'), }); const UpdateContactInput = z.object({ contact_id: z.string().describe('SendGrid contact ID'), email: z.string().email().optional(), first_name: z.string().optional(), last_name: z.string().optional(), custom_fields: z.record(z.unknown()).optional(), list_ids: z.array(z.string()).optional(), }); const DeleteContactInput = z.object({ contact_id: z.string().describe('SendGrid contact ID to delete'), }); export default [ { name: 'sendgrid_list_contacts', description: 'List marketing contacts from SendGrid with cursor-based pagination. Returns email, name, custom fields, list associations, and metadata. Use when browsing contacts, searching for specific contacts, or exporting contact data. Supports up to 100 contacts per page. Use page_token from response for next page.', inputSchema: { type: 'object' as const, properties: { page_size: { type: 'number', description: 'Number of contacts per page (1-100)', default: 50 }, page_token: { type: 'string', description: 'Pagination cursor from previous response' }, }, }, handler: async (input: unknown, client: SendGridClient) => { const validated = ListContactsInput.parse(input); const result = await client.listContacts(validated); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; }, }, { name: 'sendgrid_get_contact', description: 'Retrieve detailed information for a specific contact by ID. Returns all contact fields including email, name, custom fields, list memberships, created/updated timestamps. Use when you need full details for a known contact ID.', inputSchema: { type: 'object' as const, properties: { contact_id: { type: 'string', description: 'SendGrid contact ID' }, }, required: ['contact_id'], }, handler: async (input: unknown, client: SendGridClient) => { const validated = GetContactInput.parse(input); const result = await client.getContact(validated.contact_id); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; }, }, { name: 'sendgrid_create_contact', description: 'Create new contacts or update existing ones (upsert by email). Accepts array of contact objects with email (required), first_name, last_name, custom_fields, and list_ids. Use when importing contacts, adding newsletter signups, or syncing CRM data. Max 30,000 contacts per request. Operation is asynchronous for large batches.', inputSchema: { type: 'object' as const, properties: { contacts: { type: 'array', description: 'Array of contacts to create or update', items: { type: 'object', properties: { email: { type: 'string', description: 'Contact email (required)' }, first_name: { type: 'string' }, last_name: { type: 'string' }, custom_fields: { type: 'object', description: 'Custom field values' }, list_ids: { type: 'array', items: { type: 'string' }, description: 'List IDs to add contact to' }, }, required: ['email'], }, }, }, required: ['contacts'], }, handler: async (input: unknown, client: SendGridClient) => { const validated = CreateContactsInput.parse(input); const result = await client.createContacts(validated.contacts); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; }, }, { name: 'sendgrid_update_contact', description: 'Update an existing contact by ID. Can modify email, first_name, last_name, custom_fields, and list associations. Use when correcting contact information or updating contact attributes. For bulk updates, use create_contact with upsert.', inputSchema: { type: 'object' as const, properties: { contact_id: { type: 'string', description: 'SendGrid contact ID' }, email: { type: 'string', description: 'New email address' }, first_name: { type: 'string' }, last_name: { type: 'string' }, custom_fields: { type: 'object', description: 'Custom field values' }, list_ids: { type: 'array', items: { type: 'string' } }, }, required: ['contact_id'], }, handler: async (input: unknown, client: SendGridClient) => { const validated = UpdateContactInput.parse(input); const { contact_id, ...data } = validated; const result = await client.createContacts([{ ...data, email: data.email! }]); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; }, }, { name: 'sendgrid_delete_contact', description: 'Permanently delete a contact by ID. WARNING: This action cannot be undone. Contact is removed from all lists and segments. Use when removing unsubscribed contacts or complying with data deletion requests (GDPR/CCPA).', inputSchema: { type: 'object' as const, properties: { contact_id: { type: 'string', description: 'SendGrid contact ID to delete' }, }, required: ['contact_id'], }, handler: async (input: unknown, client: SendGridClient) => { const validated = DeleteContactInput.parse(input); await client.deleteContact(validated.contact_id); return { content: [{ type: 'text' as const, text: JSON.stringify({ success: true, deleted_contact_id: validated.contact_id }, null, 2) }], }; }, }, ];