Skip to content
Writing
MCPTypeScriptDevToolsTutorial

Building a Custom TypeScript MCP Server for Email: Zero to Production in 100 Lines

Learn how to create a high-performance, type-safe TypeScript MCP server that exposes email sending, domain DNS verification, and delivery log inspection to Claude and Cursor.

Tayyab MughalFounder & AI Chief3 min read

Setting up the v2 TypeScript MCP Server SDK

Using the official @modelcontextprotocol/server package, we can define typed tools with Zod parameters and connect them over standard input/output (stdio) or HTTP.

BASH
mkdir sadasend-mcp && cd sadasend-mcp
npm init -y
npm install @modelcontextprotocol/server zod
npm install -D typescript @types/node tsx

Complete Server Implementation (server.ts)

Here is the complete production TypeScript implementation exposing email dispatch and domain reputation checking to AI assistants.

TYPESCRIPT
import { McpServer } from '@modelcontextprotocol/server';
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio.js';
import { z } from 'zod';

const server = new McpServer({
  name: 'sadasend-email-mcp',
  version: '2.0.0',
});

// Tool 1: Scoped Outbound Email Dispatch
server.tool(
  'send_transactional_email',
  'Dispatches transactional email via SadaSend with allowlist enforcement.',
  {
    to: z.string().email().describe('Destination email address'),
    subject: z.string().min(1).describe('Email subject line'),
    body: z.string().min(1).describe('Plain-text body content'),
  },
  async ({ to, subject, body }) => {
    const apiKey = process.env.SADASEND_API_KEY;
    if (!apiKey) {
      return {
        isError: true,
        content: [{ type: 'text', text: 'Configuration Error: SADASEND_API_KEY is not set.' }],
      };
    }

    const res = await fetch('https://api.sadasend.com/v1/emails', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ to, subject, text: body }),
    });

    const data = await res.json();
    if (!res.ok) {
      return {
        isError: true,
        content: [{ type: 'text', text: `Send Refused (${res.status}): ${data.message || 'Unauthorized'}` }],
      };
    }

    return {
      content: [{ type: 'text', text: `Email delivered to outbox queue. Message ID: ${data.id}` }],
    };
  }
);

// Tool 2: Inspect Sending Domain SPF/DKIM Health
server.tool(
  'check_domain_dns',
  'Inspects SPF, DKIM, and DMARC verification status for a sending domain.',
  { domain: z.string().describe('The domain name to verify (e.g. acme.com)') },
  async ({ domain }) => {
    const res = await fetch(`https://api.sadasend.com/v1/domains/${encodeURIComponent(domain)}/verify`);
    const data = await res.json();
    return {
      content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],
    };
  }
);

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error('[MCP] SadaSend Server listening on stdio');
}

main().catch(console.error);

Testing locally with the MCP Inspector

Before adding your server to Claude Desktop or Cursor, run the official MCP Inspector to interactively test tool executions and parameter validation: npx @modelcontextprotocol/inspector tsx server.ts

Early Access

Building AI agents that send email?

Join the SadaSend early access waitlist to get scoped API keys, recipient allowlists, and Model Context Protocol (MCP) servers upon launch.

Rolling out in developer batches·No credit card needed
Social Hashtags & Share
#EmailAPI#DeveloperTools#ModelContextProtocol#MCP#TypeScript#WebDev
Tayyab MughalFounder & AI Chief

Building SadaSend — transactional email with an MCP server that has a ceiling. Writes about deliverability, email infrastructure, and what happens when you hand an autonomous agent a sending credential.

Keep reading