From fb1026827ae238181ec82fa882e8d9b8f0738aa0 Mon Sep 17 00:00:00 2001 From: apcox1 <39457739+apcox1@users.noreply.github.com> Date: Thu, 28 Aug 2025 16:47:30 +0100 Subject: [PATCH 1/3] feat(connectors): add Resend connector with send-email tool and wire into index --- .../mcp-connectors/src/connectors/resend.ts | 117 ++++++++++++++++++ packages/mcp-connectors/src/index.ts | 3 + 2 files changed, 120 insertions(+) create mode 100644 packages/mcp-connectors/src/connectors/resend.ts diff --git a/packages/mcp-connectors/src/connectors/resend.ts b/packages/mcp-connectors/src/connectors/resend.ts new file mode 100644 index 00000000..3b0a3cbc --- /dev/null +++ b/packages/mcp-connectors/src/connectors/resend.ts @@ -0,0 +1,117 @@ +import { mcpConnectorConfig } from '@stackone/mcp-config-types'; +import { z } from 'zod'; + +const RESEND_API_BASE = 'https://api.resend.com'; + +interface ResendEmailRequest { + from: string; + to: string[]; + subject: string; + text?: string; + html?: string; + cc?: string[]; + bcc?: string[]; + reply_to?: string[]; + tags?: Array<{ name: string; value: string }>; +} + +interface ResendEmailResponse { + id: string; +} + +export const ResendConnectorConfig = mcpConnectorConfig({ + name: 'Resend', + key: 'resend', + version: '1.0.0', + logo: 'https://stackone-logos.com/api/resend/filled/svg', + credentials: z.object({ + apiKey: z + .string() + .describe( + 'Resend API Key :: re_1234567890abcdefghijklmnop :: https://resend.com/docs/api-reference/authentication' + ), + }), + setup: z.object({}), + examplePrompt: + 'Send an email to example@example.com with subject "Hello from MCP" and a short HTML body.', + tools: (tool) => ({ + SEND_EMAIL: tool({ + name: 'send-email', + description: + 'Send an email using Resend. Supports text and/or HTML bodies, CC/BCC, and tags.', + schema: z.object({ + from: z + .string() + .describe('Sender email in the format "Name " or just address'), + to: z + .union([z.string(), z.array(z.string()).nonempty()]) + .describe('Recipient email address or list of addresses'), + subject: z.string().describe('Email subject line'), + text: z.string().optional().describe('Plain text body'), + html: z.string().optional().describe('HTML body'), + cc: z.array(z.string()).optional().describe('CC recipients'), + bcc: z.array(z.string()).optional().describe('BCC recipients'), + reply_to: z + .union([z.string(), z.array(z.string()).nonempty()]) + .optional() + .describe('Reply-To address or addresses'), + tags: z + .array(z.object({ name: z.string(), value: z.string() })) + .optional() + .describe('Key/value tags to attach to the email'), + }), + handler: async (args, context) => { + try { + const { apiKey } = await context.getCredentials(); + + const payload: ResendEmailRequest = { + from: args.from, + to: Array.isArray(args.to) ? args.to : [args.to], + subject: args.subject, + ...(args.text ? { text: args.text } : {}), + ...(args.html ? { html: args.html } : {}), + ...(args.cc ? { cc: args.cc } : {}), + ...(args.bcc ? { bcc: args.bcc } : {}), + ...(args.reply_to + ? { reply_to: Array.isArray(args.reply_to) ? args.reply_to : [args.reply_to] } + : {}), + ...(args.tags ? { tags: args.tags } : {}), + }; + + if (!payload.text && !payload.html) { + throw new Error('Either text or html must be provided'); + } + + const response = await fetch(`${RESEND_API_BASE}/emails`, { + method: 'POST', + headers: { + Authorization: `Bearer ${apiKey}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(payload), + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Resend API error: ${response.status} - ${errorText}`); + } + + const data = (await response.json()) as ResendEmailResponse; + + return JSON.stringify({ + success: true, + id: data.id, + message: 'Email sent successfully', + }); + } catch (error) { + return JSON.stringify({ + success: false, + error: error instanceof Error ? error.message : 'Unknown error occurred', + }); + } + }, + }), + }), +}); + + diff --git a/packages/mcp-connectors/src/index.ts b/packages/mcp-connectors/src/index.ts index 6de387ac..64e05400 100644 --- a/packages/mcp-connectors/src/index.ts +++ b/packages/mcp-connectors/src/index.ts @@ -29,6 +29,7 @@ import { ProducthuntConnectorConfig } from './connectors/producthunt'; import { LogfireConnectorConfig } from './connectors/pydantic-logfire'; import { PylonConnectorConfig } from './connectors/pylon'; import { ReplicateConnectorConfig } from './connectors/replicate'; +import { ResendConnectorConfig } from './connectors/resend'; import { SequentialThinkingConnectorConfig } from './connectors/sequential-thinking'; import { SlackConnectorConfig } from './connectors/slack'; import { StackOneConnectorConfig } from './connectors/stackone'; @@ -72,6 +73,7 @@ export const Connectors: readonly MCPConnectorConfig[] = [ ProducthuntConnectorConfig, PylonConnectorConfig, ReplicateConnectorConfig, + ResendConnectorConfig, SequentialThinkingConnectorConfig, SlackConnectorConfig, StravaConnectorConfig, @@ -114,6 +116,7 @@ export { ProducthuntConnectorConfig, PylonConnectorConfig, ReplicateConnectorConfig, + ResendConnectorConfig, SequentialThinkingConnectorConfig, SlackConnectorConfig, StravaConnectorConfig, From 200a818eeee40cb8afa87e443abc5f2c7c8315f1 Mon Sep 17 00:00:00 2001 From: apcox1 <39457739+apcox1@users.noreply.github.com> Date: Thu, 28 Aug 2025 16:50:22 +0100 Subject: [PATCH 2/3] chore(resend): update logo to stable SVG URL --- packages/mcp-connectors/src/connectors/resend.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-connectors/src/connectors/resend.ts b/packages/mcp-connectors/src/connectors/resend.ts index 3b0a3cbc..fcd1d719 100644 --- a/packages/mcp-connectors/src/connectors/resend.ts +++ b/packages/mcp-connectors/src/connectors/resend.ts @@ -23,7 +23,7 @@ export const ResendConnectorConfig = mcpConnectorConfig({ name: 'Resend', key: 'resend', version: '1.0.0', - logo: 'https://stackone-logos.com/api/resend/filled/svg', + logo: 'https://cdn.worldvectorlogo.com/logos/resend-1.svg', credentials: z.object({ apiKey: z .string() From a7d9568258b4a0a44160032edc8806f4fdfc67cd Mon Sep 17 00:00:00 2001 From: apcox1 <39457739+apcox1@users.noreply.github.com> Date: Thu, 28 Aug 2025 20:15:50 +0100 Subject: [PATCH 3/3] style(resend): fix biome formatting issues --- packages/mcp-connectors/src/connectors/resend.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/mcp-connectors/src/connectors/resend.ts b/packages/mcp-connectors/src/connectors/resend.ts index fcd1d719..7976fa13 100644 --- a/packages/mcp-connectors/src/connectors/resend.ts +++ b/packages/mcp-connectors/src/connectors/resend.ts @@ -73,7 +73,11 @@ export const ResendConnectorConfig = mcpConnectorConfig({ ...(args.cc ? { cc: args.cc } : {}), ...(args.bcc ? { bcc: args.bcc } : {}), ...(args.reply_to - ? { reply_to: Array.isArray(args.reply_to) ? args.reply_to : [args.reply_to] } + ? { + reply_to: Array.isArray(args.reply_to) + ? args.reply_to + : [args.reply_to], + } : {}), ...(args.tags ? { tags: args.tags } : {}), }; @@ -113,5 +117,3 @@ export const ResendConnectorConfig = mcpConnectorConfig({ }), }), }); - -