Skip to main content
Glama
index.ts13.9 kB
#!/usr/bin/env node import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js'; // Get API key from environment const API_KEY = process.env.GETMAILER_API_KEY; const API_URL = process.env.GETMAILER_API_URL || 'https://getmailer.app'; if (!API_KEY) { console.error('GETMAILER_API_KEY environment variable is required'); process.exit(1); } // API helper async function apiRequest<T>( endpoint: string, options: RequestInit = {} ): Promise<T> { const url = `${API_URL}${endpoint}`; const response = await fetch(url, { ...options, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${API_KEY}`, ...options.headers, }, }); if (!response.ok) { let errorMessage = response.statusText; try { const errorData = await response.json(); errorMessage = errorData.error || errorData.message || errorMessage; } catch { // Ignore } throw new Error(`API Error: ${errorMessage}`); } return response.json(); } // Create server const server = new Server( { name: 'getmailer-mcp', version: '1.0.0', }, { capabilities: { tools: {}, }, } ); // Define tools server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'send_email', description: 'Send a transactional email via GetMailer', inputSchema: { type: 'object' as const, properties: { from: { type: 'string', description: 'Sender email address (must be from a verified domain)', }, to: { type: 'array', items: { type: 'string' }, description: 'Recipient email address(es)', }, subject: { type: 'string', description: 'Email subject line', }, html: { type: 'string', description: 'HTML content of the email', }, text: { type: 'string', description: 'Plain text content of the email', }, cc: { type: 'array', items: { type: 'string' }, description: 'CC recipients (optional)', }, bcc: { type: 'array', items: { type: 'string' }, description: 'BCC recipients (optional)', }, replyTo: { type: 'string', description: 'Reply-to address (optional)', }, templateId: { type: 'string', description: 'Template ID to use instead of html/text (optional)', }, variables: { type: 'object', description: 'Template variables as key-value pairs (optional)', }, }, required: ['from', 'to', 'subject'], }, }, { name: 'list_emails', description: 'List sent emails with status information', inputSchema: { type: 'object' as const, properties: { limit: { type: 'number', description: 'Number of emails to return (default: 20)', }, cursor: { type: 'string', description: 'Pagination cursor for next page', }, }, }, }, { name: 'get_email', description: 'Get details of a specific email including delivery events', inputSchema: { type: 'object' as const, properties: { id: { type: 'string', description: 'Email ID', }, }, required: ['id'], }, }, { name: 'list_templates', description: 'List available email templates', inputSchema: { type: 'object' as const, properties: {}, }, }, { name: 'create_template', description: 'Create a new email template', inputSchema: { type: 'object' as const, properties: { name: { type: 'string', description: 'Template name', }, subject: { type: 'string', description: 'Email subject (can include {{variables}})', }, html: { type: 'string', description: 'HTML content (can include {{variables}})', }, text: { type: 'string', description: 'Plain text content (optional)', }, }, required: ['name', 'subject', 'html'], }, }, { name: 'list_domains', description: 'List verified sending domains', inputSchema: { type: 'object' as const, properties: {}, }, }, { name: 'add_domain', description: 'Add a new sending domain (returns DNS records to configure)', inputSchema: { type: 'object' as const, properties: { domain: { type: 'string', description: 'Domain name to add (e.g., example.com)', }, }, required: ['domain'], }, }, { name: 'verify_domain', description: 'Check if a domain has been verified', inputSchema: { type: 'object' as const, properties: { id: { type: 'string', description: 'Domain ID', }, }, required: ['id'], }, }, { name: 'get_analytics', description: 'Get email analytics and statistics', inputSchema: { type: 'object' as const, properties: { type: { type: 'string', enum: ['summary', 'daily'], description: 'Type of analytics (summary or daily)', }, days: { type: 'number', description: 'Number of days for daily stats (default: 30)', }, }, }, }, { name: 'list_suppression', description: 'List suppressed email addresses (bounced, complained, or manually added)', inputSchema: { type: 'object' as const, properties: { limit: { type: 'number', description: 'Number of entries to return (default: 50)', }, }, }, }, { name: 'add_to_suppression', description: 'Add email addresses to the suppression list', inputSchema: { type: 'object' as const, properties: { emails: { type: 'array', items: { type: 'string' }, description: 'Email addresses to suppress', }, reason: { type: 'string', enum: ['MANUAL', 'BOUNCE', 'COMPLAINT'], description: 'Reason for suppression (default: MANUAL)', }, }, required: ['emails'], }, }, { name: 'create_batch', description: 'Create a batch email job to send to multiple recipients', inputSchema: { type: 'object' as const, properties: { name: { type: 'string', description: 'Batch job name', }, from: { type: 'string', description: 'Sender email address', }, subject: { type: 'string', description: 'Email subject (can include {{variables}})', }, html: { type: 'string', description: 'HTML content (can include {{variables}})', }, text: { type: 'string', description: 'Plain text content (optional)', }, templateId: { type: 'string', description: 'Template ID to use instead of html/text (optional)', }, recipients: { type: 'array', items: { type: 'object', properties: { to: { type: 'string' }, variables: { type: 'object' }, }, required: ['to'], }, description: 'Array of recipients with optional per-recipient variables', }, replyTo: { type: 'string', description: 'Reply-to address (optional)', }, }, required: ['name', 'from', 'recipients'], }, }, { name: 'list_batches', description: 'List batch email jobs', inputSchema: { type: 'object' as const, properties: {}, }, }, { name: 'get_batch', description: 'Get batch job status and progress', inputSchema: { type: 'object' as const, properties: { id: { type: 'string', description: 'Batch ID', }, }, required: ['id'], }, }, ], })); // Handle tool calls server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'send_email': { const result = await apiRequest<{ email: unknown; suppressed?: string[] }>( '/api/emails', { method: 'POST', body: JSON.stringify(args), } ); return { content: [ { type: 'text' as const, text: JSON.stringify(result, null, 2), }, ], }; } case 'list_emails': { const params = new URLSearchParams(); if (args?.limit) params.set('limit', String(args.limit)); if (args?.cursor) params.set('cursor', String(args.cursor)); const result = await apiRequest(`/api/emails?${params}`); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'get_email': { const result = await apiRequest(`/api/emails/${args?.id}`); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'list_templates': { const result = await apiRequest('/api/templates'); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'create_template': { const result = await apiRequest('/api/templates', { method: 'POST', body: JSON.stringify(args), }); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'list_domains': { const result = await apiRequest('/api/domains'); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'add_domain': { const result = await apiRequest('/api/domains', { method: 'POST', body: JSON.stringify({ domain: args?.domain }), }); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'verify_domain': { const result = await apiRequest('/api/domains/verify', { method: 'POST', body: JSON.stringify({ id: args?.id }), }); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'get_analytics': { const type = args?.type || 'summary'; const days = args?.days || 30; const result = await apiRequest(`/api/analytics?type=${type}&days=${days}`); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'list_suppression': { const params = new URLSearchParams(); if (args?.limit) params.set('limit', String(args.limit)); const result = await apiRequest(`/api/suppression?${params}`); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'add_to_suppression': { const result = await apiRequest('/api/suppression', { method: 'POST', body: JSON.stringify({ emails: args?.emails, reason: args?.reason || 'MANUAL', }), }); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'create_batch': { const result = await apiRequest('/api/batch', { method: 'POST', body: JSON.stringify(args), }); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'list_batches': { const result = await apiRequest('/api/batch'); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } case 'get_batch': { const result = await apiRequest(`/api/batch/${args?.id}`); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }], }; } default: throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`); } } catch (error) { const message = error instanceof Error ? error.message : 'Unknown error'; return { content: [{ type: 'text' as const, text: `Error: ${message}` }], isError: true, }; } }); // Start server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error('GetMailer MCP server running'); } main().catch((error) => { console.error('Server error:', error); process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/getplatform/getmailer-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server