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

_By Tayyab Mughal, Founder & AI Chief · 24 August 2026 · 3 min read_

> Step-by-step guide to building and deploying a production-ready Model Context Protocol (MCP) server for transactional email using @modelcontextprotocol/server and Zod.

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.

## 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

---

_Tags: MCP, TypeScript, DevTools, Tutorial_
