UNPKG

@kikin/mailsac-mcp

Version:

MCP server for Mailsac email testing service

642 lines 24.3 kB
#!/usr/bin/env node import { FastMCP } from "fastmcp"; import { z } from "zod"; import { Mailsac } from "@mailsac/api"; const MAILSAC_KEY = process.env.MAILSAC_KEY; if (!MAILSAC_KEY) { console.error("Error: MAILSAC_KEY environment variable is required"); process.exit(1); } const mailsac = new Mailsac({ headers: { "Mailsac-Key": MAILSAC_KEY }, }); const server = new FastMCP({ name: "Mailsac MCP Server", version: "1.0.0", instructions: "Manage your Mailsac email inboxs and addresses. Full documentation at https://mailsac.com/docs/api", }); // ===== ADDRESS MANAGEMENT TOOLS (7 endpoints) ===== server.addTool({ name: "list_addresses", description: "List all enhanced email addresses for the account", execute: async () => { const result = await mailsac.addresses.listAddresses(); return JSON.stringify(result.data); }, }); server.addTool({ name: "get_address", description: "Fetch an address or check if it is reserved", parameters: z.object({ email: z.string().describe("The email address to fetch"), }), execute: async (args) => { const result = await mailsac.addresses.getAddress(args.email); return JSON.stringify(result.data); }, }); server.addTool({ name: "create_address", description: "Reserve (create/own) a private email address", parameters: z.object({ email: z.string().describe("The email address to create"), forward: z .string() .optional() .describe("Forward incoming emails to this address"), enablews: z .boolean() .optional() .describe("Enable websocket for this address"), webhook: z.string().optional().describe("Webhook URL for incoming emails"), webhookSlack: z.string().optional().describe("Slack webhook URL"), webhookSlackToFrom: z .boolean() .optional() .describe("Include to/from in Slack notifications"), }), execute: async (args) => { const { email, ...body } = args; const result = await mailsac.addresses.createAddress(email, body); return JSON.stringify(result.data); }, }); server.addTool({ name: "update_address", description: "Update private email address forwarding and metadata", parameters: z.object({ email: z.string().describe("The email address to update"), forward: z .string() .optional() .describe("Forward incoming emails to this address"), enablews: z .boolean() .optional() .describe("Enable websocket for this address"), webhook: z.string().optional().describe("Webhook URL for incoming emails"), webhookSlack: z.string().optional().describe("Slack webhook URL"), webhookSlackToFrom: z .boolean() .optional() .describe("Include to/from in Slack notifications"), }), execute: async (args) => { const { email, ...body } = args; const result = await mailsac.addresses.updateAddress(email, body); return JSON.stringify(result.data); }, }); server.addTool({ name: "delete_address", description: "Release an enhanced email address", parameters: z.object({ email: z.string().describe("The email address to delete"), deleteAddressMessages: z .boolean() .optional() .describe("Delete all messages for this address"), }), execute: async (args) => { const queryParams = args.deleteAddressMessages ? { deleteAddressMessages: args.deleteAddressMessages } : undefined; const result = await mailsac.addresses.deleteAddress(args.email, queryParams); return JSON.stringify(result.data); }, }); server.addTool({ name: "check_address_availability", description: "Check address ownership status", parameters: z.object({ email: z.string().describe("The email address to check"), }), execute: async (args) => { const result = await mailsac.addresses.checkAvailability(args.email); return JSON.stringify(result.data); }, }); server.addTool({ name: "create_addresses_bulk", description: "Reserve multiple enhanced addresses (max 100)", parameters: z.object({ addresses: z .array(z.string()) .describe("Array of email addresses to create"), }), execute: async (args) => { const result = await mailsac.addresses.createAddresses({ addresses: args.addresses, }); return JSON.stringify(result.data); }, }); // ===== EMAIL VALIDATIONS TOOLS (2 endpoints) ===== server.addTool({ name: "validate_address", description: "Validate an email address and check if disposable", parameters: z.object({ email: z.string().describe("The email address to validate"), }), execute: async (args) => { const result = await mailsac.emailValidation.validateAddress(args.email); return JSON.stringify(result.data); }, }); server.addTool({ name: "validate_addresses_bulk", description: "Validate up to 50 email addresses", parameters: z.object({ emails: z .array(z.string()) .describe("Array of email addresses to validate"), }), execute: async (args) => { const result = await mailsac.emailValidation.validateAddressesBulk({ emails: args.emails, }); return JSON.stringify(result.data); }, }); // ===== MESSAGE LISTING & COUNTING TOOLS (6 endpoints) ===== server.addTool({ name: "count_messages", description: "Count messages for an email inbox", parameters: z.object({ email: z.string().describe("The email address to count messages for"), }), execute: async (args) => { const result = await mailsac.messages.countMessages(args.email); return JSON.stringify(result.data); }, }); server.addTool({ name: "list_messages", description: "List messages for an email inbox (newest first)", parameters: z.object({ email: z.string().describe("The email address to list messages for"), until: z .string() .optional() .describe("Return messages up to this UTC date"), limit: z.number().optional().describe("Results limit"), }), execute: async (args) => { const queryParams = {}; if (args.until) queryParams.until = args.until; if (args.limit) queryParams.limit = args.limit; const result = await mailsac.messages.listMessages(args.email, queryParams); return JSON.stringify(result.data); }, }); server.addTool({ name: "list_starred_messages", description: "List starred (saved) messages on the account", execute: async () => { const result = await mailsac.messages.listStarredMessages(); return JSON.stringify(result.data); }, }); server.addTool({ name: "list_inbox_messages", description: "Get all account messages paginated (used by Inbox UI)", parameters: z.object({ limit: z.number().optional().describe("Results limit"), since: z .string() .optional() .describe("Only fetch messages since this date"), skip: z.number().optional().describe("Pagination offset"), }), execute: async (args) => { const queryParams = {}; if (args.limit) queryParams.limit = args.limit; if (args.since) queryParams.since = args.since; if (args.skip) queryParams.skip = args.skip; const result = await mailsac.messages.listInboxMessages(queryParams); return JSON.stringify(result.data); }, }); server.addTool({ name: "filter_inbox_messages", description: "Filter messages by to, from, and/or subject (logical AND)", parameters: z.object({ andSubjectIncludes: z.string().optional().describe("Text in subject line"), andFrom: z.string().optional().describe("Text in FROM envelope"), andTo: z.string().optional().describe("Text in TO envelope"), andRead: z.boolean().optional().describe("Read/unread status"), }), execute: async (args) => { const result = await mailsac.messages.filterInboxMessages(args); return JSON.stringify(result.data); }, }); server.addTool({ name: "search_inbox_messages", description: "Search messages by to, from, and subject (logical OR)", parameters: z.object({ query: z.string().optional().describe("Search term"), }), execute: async (args) => { const queryParams = {}; if (args.query) queryParams.query = args.query; const result = await mailsac.messages.searchInboxMessages(queryParams); return JSON.stringify(result.data); }, }); // ===== MESSAGE DETAILS & CONTENT TOOLS (5 endpoints) ===== server.addTool({ name: "get_message_metadata", description: "Get email message metadata with links and attachments", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), }), execute: async (args) => { const result = await mailsac.messages.getMessageMetadata(args.email, args.messageId); return JSON.stringify(result.data); }, }); server.addTool({ name: "get_full_raw_message", description: "Get entire original SMTP message", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), download: z.boolean().optional().describe("Browser download flag"), }), execute: async (args) => { const queryParams = {}; if (args.download) queryParams.download = 1; const result = await mailsac.messages.getFullRawMessage(args.email, args.messageId, queryParams); return result.data; }, }); server.addTool({ name: "get_message_headers", description: "Get parsed message headers in multiple formats", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), messageHeadersFormat: z .enum(["json", "json-ordered", "plain"]) .optional() .describe("Headers format"), download: z.boolean().optional().describe("Browser download flag"), }), execute: async (args) => { const queryParams = {}; if (args.messageHeadersFormat) queryParams.messageHeadersFormat = args.messageHeadersFormat; if (args.download) queryParams.download = 1; const result = await mailsac.messages.getHeaders(args.email, args.messageId, queryParams); return JSON.stringify(result.data); }, }); server.addTool({ name: "get_message_body_dirty", description: "Get message HTML body (dirty/unsanitized)", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), download: z.boolean().optional().describe("Browser download flag"), }), execute: async (args) => { const queryParams = {}; if (args.download) queryParams.download = 1; const result = await mailsac.messages.getBodyDirty(args.email, args.messageId, queryParams); return result.data; }, }); server.addTool({ name: "get_message_body_sanitized", description: "Get message HTML body (sanitized/safe)", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), download: z.boolean().optional().describe("Browser download flag"), }), execute: async (args) => { const queryParams = {}; if (args.download) queryParams.download = 1; const result = await mailsac.messages.getBodySanitized(args.email, args.messageId, queryParams); return result.data; }, }); server.addTool({ name: "get_message_body_plaintext", description: "Get message plaintext content", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), download: z.boolean().optional().describe("Browser download flag"), }), execute: async (args) => { const queryParams = {}; if (args.download) queryParams.download = 1; const result = await mailsac.messages.getBodyPlainText(args.email, args.messageId, queryParams); return result.data; }, }); // ===== MESSAGE MANAGEMENT TOOLS (8 endpoints) ===== server.addTool({ name: "delete_all_messages", description: "Delete all messages for an email inbox (starred messages protected)", parameters: z.object({ email: z.string().describe("The email address"), }), execute: async (args) => { const result = await mailsac.messages.deleteAllMessages(args.email); return JSON.stringify(result.data); }, }); server.addTool({ name: "delete_message", description: "Delete an individual email message", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), }), execute: async (args) => { const result = await mailsac.messages.deleteMessage(args.email, args.messageId); return JSON.stringify(result.data); }, }); server.addTool({ name: "toggle_message_star", description: "Star (save) a message to protect from auto-deletion", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), }), execute: async (args) => { const result = await mailsac.messages.toggleMessageStar(args.email, args.messageId); return JSON.stringify(result.data); }, }); server.addTool({ name: "add_message_label", description: "Add a label to a message for organization", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), label: z.string().describe("Label string to add"), }), execute: async (args) => { const result = await mailsac.messages.addMessageLabel(args.email, args.messageId, args.label); return JSON.stringify(result.data); }, }); server.addTool({ name: "delete_message_label", description: "Remove a label from a message", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), label: z.string().describe("Label string to remove"), }), execute: async (args) => { const result = await mailsac.messages.deleteMessageLabel(args.email, args.messageId, args.label); return JSON.stringify(result.data); }, }); server.addTool({ name: "set_message_folder", description: "Move message to folder (inbox, all, spam, trash)", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), folder: z.enum(["inbox", "all", "spam", "trash"]).describe("Folder name"), }), execute: async (args) => { const result = await mailsac.messages.setMessageFolder(args.email, args.messageId, args.folder); return JSON.stringify(result.data); }, }); server.addTool({ name: "set_message_read_status", description: "Set message read/unread status", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), readBoolean: z.boolean().describe("Read status (true=read, false=unread)"), }), execute: async (args) => { const result = await mailsac.messages.setMessageReadStatus(args.email, args.messageId, args.readBoolean); return JSON.stringify(result.data); }, }); // ===== DOMAIN MANAGEMENT TOOLS (4 endpoints) ===== server.addTool({ name: "list_domains", description: "List custom domains for the account", execute: async () => { const result = await mailsac.domains.listDomains(); return JSON.stringify(result.data); }, }); server.addTool({ name: "get_domain", description: "Get domain information including message count", parameters: z.object({ domain: z.string().describe("Domain string"), }), execute: async (args) => { const result = await mailsac.domains.getDomain(args.domain); return JSON.stringify(result.data); }, }); server.addTool({ name: "list_domain_messages", description: "List messages across any inboxes of a domain", parameters: z.object({ domain: z.string().describe("Domain string"), until: z .string() .optional() .describe("Return messages up to this UTC date"), limit: z.number().optional().describe("Results limit"), }), execute: async (args) => { const queryParams = {}; if (args.until) queryParams.until = args.until; if (args.limit) queryParams.limit = args.limit; const result = await mailsac.messages.listDomainMessages(args.domain, queryParams); return JSON.stringify(result.data); }, }); server.addTool({ name: "delete_all_domain_messages", description: "Delete all messages for a domain (including starred)", parameters: z.object({ domain: z.string().describe("Domain string"), }), execute: async (args) => { const result = await mailsac.messages.deleteAllDomainMessages(args.domain); return JSON.stringify(result.data); }, }); // ===== USER ACCOUNT TOOLS (2 endpoints) ===== server.addTool({ name: "get_user_info", description: "Get current account information", execute: async () => { const result = await mailsac.account.user(); return JSON.stringify(result.data); }, }); server.addTool({ name: "get_account_stats", description: "Get account stats and usage information", parameters: z.object({ overrideAccountId: z.string().optional().describe("Account ID override"), }), execute: async (args) => { const queryParams = {}; if (args.overrideAccountId) queryParams.overrideAccountId = args.overrideAccountId; const result = await mailsac.account.accountStats(queryParams); return JSON.stringify(result.data); }, }); // ===== EMAIL ATTACHMENTS TOOLS (2 endpoints) ===== server.addTool({ name: "list_message_attachments", description: "List attachment metadata for an email message", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), }), execute: async (args) => { const result = await mailsac.attachments.listMessageAttachments(args.email, args.messageId); return JSON.stringify(result.data); }, }); server.addTool({ name: "download_attachment", description: "Download an email message attachment as file", parameters: z.object({ email: z.string().describe("The email address"), messageId: z.string().describe("Unique message identifier"), attachmentIdentifier: z .string() .describe("MD5 sum, content-id, or filename"), }), execute: async (args) => { const result = await mailsac.attachments.downloadAttachment(args.email, args.messageId, args.attachmentIdentifier); return `Binary file data (${result.status} ${result.statusText})`; }, }); // ===== EMAIL STATS TOOLS (3 available endpoints) ===== server.addTool({ name: "list_top_public_addresses", description: "List top public disposable email addresses by message volume", parameters: z.object({ startDate: z.string().optional().describe("Start date filter"), endDate: z.string().optional().describe("End date filter"), skip: z.number().optional().describe("Pagination offset"), limit: z.number().optional().describe("Results limit"), }), execute: async (args) => { const queryParams = {}; if (args.startDate) queryParams.startDate = args.startDate; if (args.endDate) queryParams.endDate = args.endDate; if (args.skip) queryParams.skip = args.skip; if (args.limit) queryParams.limit = args.limit; const result = await mailsac.messageStats.listTopPublicAddresses(queryParams); return JSON.stringify(result.data); }, }); server.addTool({ name: "list_top_public_senders", description: "List top sender email addresses for public messages", parameters: z.object({ startDate: z.string().optional().describe("Start date filter"), endDate: z.string().optional().describe("End date filter"), skip: z.number().optional().describe("Pagination offset"), limit: z.number().optional().describe("Results limit"), }), execute: async (args) => { const queryParams = {}; if (args.startDate) queryParams.startDate = args.startDate; if (args.endDate) queryParams.endDate = args.endDate; if (args.skip) queryParams.skip = args.skip; if (args.limit) queryParams.limit = args.limit; const result = await mailsac.messageStats.listTopPublicSenders(queryParams); return JSON.stringify(result.data); }, }); server.addTool({ name: "list_top_public_domains", description: "List top public domains receiving disposable messages", parameters: z.object({ startDate: z.string().optional().describe("Start date filter"), endDate: z.string().optional().describe("End date filter"), skip: z.number().optional().describe("Pagination offset"), limit: z.number().optional().describe("Results limit"), }), execute: async (args) => { const queryParams = {}; if (args.startDate) queryParams.startDate = args.startDate; if (args.endDate) queryParams.endDate = args.endDate; if (args.skip) queryParams.skip = args.skip; if (args.limit) queryParams.limit = args.limit; const result = await mailsac.messageStats.listTopPublicDomains(queryParams); return JSON.stringify(result.data); }, }); // ===== WEBSOCKET/WEBHOOK DOCUMENTATION TOOLS (2 endpoints) ===== server.addTool({ name: "websocket_info", description: "Get WebSocket connection information and documentation", execute: async () => { return JSON.stringify({ endpoint: "wss://sock.mailsac.com/incoming-messages", usage: "Connect with ?key=YOUR_API_KEY&addresses=email1@domain.com,email2@domain.com", description: "Real-time email delivery via WebSocket connection", example: "wss://sock.mailsac.com/incoming-messages?key=k_eoj1mn7x5y61w0egs25j6xrv&addresses=test@mailsac.com", }); }, }); server.addTool({ name: "webhook_info", description: "Get webhook configuration information and documentation", execute: async () => { return JSON.stringify({ description: "Webhooks are configured per email address via the update_address tool", configuration: "Set webhook URL in the 'webhook' field when creating/updating addresses", slackSupport: "Slack webhooks supported via 'webhookSlack' field", payload: "Webhook receives EmailMessageWebhook objects as JSON POST", expectedResponse: "Webhook endpoint should return HTTP 200 status", }); }, }); server.start({ transportType: "stdio", }); //# sourceMappingURL=index.js.map