#!/usr/bin/env node
import {
ListToolsRequestSchema,
CallToolRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { zodToJsonSchema } from 'zod-to-json-schema';
import { Resend } from 'resend';
import dotenv from 'dotenv';
import {
SendEmailRequestSchema,
SendBatchEmailsRequestSchema,
} from './schemas.js';
dotenv.config();
if (!process.env.RESEND_API_KEY) {
console.error(
'RESEND_API_KEY is not set. Please set it in your environment or .env file.'
);
process.exit(1);
}
if (!process.env.RESEND_FROM_EMAIL) {
console.error(
'RESEND_FROM_EMAIL is not set. Please set it in your environment or .env file.'
);
process.exit(1);
}
const resend = new Resend(process.env.RESEND_API_KEY);
const fromEmail = process.env.RESEND_FROM_EMAIL;
function createServer(): Server {
const server = new Server(
{
name: 'resend-mcp-server',
version: '0.1.0',
},
{
capabilities: {
tools: {},
},
}
);
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'resend_send_email',
description:
'Send a single email to one or more recipients. Supports HTML and plain text content, CC/BCC, reply-to, and custom tags for tracking.',
inputSchema: zodToJsonSchema(SendEmailRequestSchema),
// },
// {
// name: 'resend_send_batch_emails',
// description:
// 'Send multiple emails in a single API call (max 100). More efficient than sending individual emails when you need to notify multiple people with different content.',
// inputSchema: zodToJsonSchema(SendBatchEmailsRequestSchema),
},
],
};
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
if (!request.params) {
throw new Error('Params are required');
}
switch (request.params.name) {
case 'resend_send_email': {
const args = SendEmailRequestSchema.parse(request.params.arguments);
// Build email options - Resend requires html or text
const emailOptions: Parameters<typeof resend.emails.send>[0] = {
from: fromEmail,
to: args.to,
subject: args.subject,
...(args.html ? { html: args.html } : { text: args.text! }),
...(args.cc && { cc: args.cc }),
...(args.bcc && { bcc: args.bcc }),
...(args.reply_to && { replyTo: args.reply_to }),
...(args.tags && { tags: args.tags }),
};
const { data, error } = await resend.emails.send(emailOptions);
if (error) {
throw new Error(`Failed to send email: ${error.message}`);
}
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: true,
id: data?.id,
message: 'Email sent successfully',
}),
},
],
};
}
case 'resend_send_batch_emails': {
const args = SendBatchEmailsRequestSchema.parse(
request.params.arguments
);
// Build batch emails with platform from address
const batchEmails = args.emails.map((email) => {
const emailOptions: Parameters<typeof resend.emails.send>[0] = {
from: fromEmail,
to: email.to,
subject: email.subject,
...(email.html ? { html: email.html } : { text: email.text! }),
...(email.cc && { cc: email.cc }),
...(email.bcc && { bcc: email.bcc }),
...(email.reply_to && { replyTo: email.reply_to }),
...(email.tags && { tags: email.tags }),
};
return emailOptions;
});
const { data, error } = await resend.batch.send(batchEmails);
if (error) {
throw new Error(`Failed to send batch emails: ${error.message}`);
}
return {
content: [
{
type: 'text',
text: JSON.stringify({
success: true,
sent: data?.data?.length || 0,
ids: data?.data?.map((d) => d.id) || [],
message: `Successfully sent ${data?.data?.length || 0} emails`,
}),
},
],
};
}
default:
throw new Error(`Unknown tool: ${request.params.name}`);
}
} catch (error) {
console.error('Error handling request:', error);
const errorMessage =
error instanceof Error ? error.message : 'Unknown error occurred';
throw new Error(errorMessage);
}
});
return server;
}
async function runStdioServer() {
const server = createServer();
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('Resend MCP Server running on stdio');
}
async function main() {
await runStdioServer();
}
main().catch((error) => {
console.error('Fatal error in main():', error);
process.exit(1);
});