email-mcp.js•3.51 kB
#!/usr/bin/env node
// email-mcp.js
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ErrorCode,
ListToolsRequestSchema,
McpError,
} from "@modelcontextprotocol/sdk/types.js";
import nodemailer from "nodemailer";
// 读取环境变量
const {
SMTP_HOST,
SMTP_PORT,
SMTP_SECURE,
SMTP_USER,
EMAIL_FROM,
EMAIL_TO,
} = process.env;
// SMTP_PASS 从系统环境变量中读取
const SMTP_PASS = process.env.SMTP_PASS;
if (!SMTP_HOST || !SMTP_PORT || !SMTP_USER || !SMTP_PASS || !EMAIL_FROM || !EMAIL_TO) {
console.error("Missing SMTP/Email envs. Required: SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, EMAIL_FROM, EMAIL_TO");
console.error(`Current values: SMTP_HOST=${SMTP_HOST}, SMTP_PORT=${SMTP_PORT}, SMTP_USER=${SMTP_USER}, SMTP_PASS=${SMTP_PASS ? '[SET]' : '[NOT SET]'}, EMAIL_FROM=${EMAIL_FROM}, EMAIL_TO=${EMAIL_TO}`);
process.exit(1);
}
// 创建 nodemailer transporter
const transporter = nodemailer.createTransport({
host: SMTP_HOST,
port: Number(SMTP_PORT),
secure: String(SMTP_SECURE || "").toLowerCase() === "true", // true -> 465, false -> 587/25
auth: {
user: SMTP_USER,
pass: SMTP_PASS,
},
});
// 定义 MCP 服务器
const server = new Server(
{
name: "email-notify",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
// 处理工具列表请求
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "send_email",
description: "Send an email notification. Provide subject and either text or html. Default recipient comes from EMAIL_TO.",
inputSchema: {
type: "object",
properties: {
subject: {
type: "string",
description: "Email subject"
},
text: {
type: "string",
description: "Plain text email content"
},
html: {
type: "string",
description: "HTML email content"
},
to: {
type: "string",
description: "Override default recipient"
},
from: {
type: "string",
description: "Override default sender"
}
},
required: ["subject"]
}
}
]
};
});
// 处理工具调用请求
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name !== "send_email") {
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${name}`
);
}
const { subject, text, html, to, from } = args;
if (!text && !html) {
return {
content: [{
type: "text",
text: "Either text or html is required"
}]
};
}
try {
const info = await transporter.sendMail({
from: from || EMAIL_FROM,
to: to || EMAIL_TO,
subject,
text,
html,
});
return {
content: [
{
type: "text",
text: `Email sent successfully. MessageId=${info.messageId || "(n/a)"}`,
},
],
};
} catch (error) {
throw new McpError(
ErrorCode.InternalError,
`Failed to send email: ${error.message}`
);
}
});
// 通过 stdio 启动
const transport = new StdioServerTransport();
server.connect(transport);