效果演示
向大模型索要数据,并自动发送到指定邮箱
最后收到邮件的结果截图
先推荐2个mcp网站
mcp中文文档:MCP中文简介 – MCP 中文站(Model Context Protocol 中文)
mcp server收录站:https://mcp.so/
手搓的配套视频我放到文章底部
前置准备
我这边以node来做演示,node js环境点此下载,这个一定要有,没有现场装,啪的一下很快
// 检查node环境
node -v
// 检查npm环境
npm -v
// 检查npx环境
npx -v
// 配置淘宝源
npm config set registry https://registry.npmmirror.com
初始化mcp项目
# 创建一个文件夹(可手动创建)
mkdir first-mcp-server
cd first-mcp-server
# 初始化 npm 项目
npm init -y
# 安装mcp sdk依赖
npm install @modelcontextprotocol/sdk @anthropic-ai/sdk dotenv
npm install -D typescript @types/node
# 创建 TypeScript 配置
npx tsc --init
# 创建必要的文件
mkdir src
touch src/index.ts
加入如下代码
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server({
name: "first-mcp-server",
version: "0.0.1",
}, {
capabilities: {
tools: {}
}
});
// List available tools 一定要有,否则无法接入mcp-client
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "测试方法",
description: "这是一个测试方法描述",
inputSchema: {
type: "object",
properties: {
property1: {
type: "string",
description: "属性1",
},
property2: {
type: "string",
description: "属性2",
},
property3: {
type: "number",
description: "属性3,非必填",
},
},
required: ["property1", "property2"],
},
},
],
};
});
// 启动服务
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("First MCP Server running on stdio");
}
// 异常捕获
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});
tsconfig.json改为如下
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"]
}
package.json加入如下代码
{
"type": "module",
"scripts": {
"build": "tsc",
"start": "node build/client.js"
}
}
编译构建
打开命令行执行 npm run build
,构建后会生成build/index.js
文件
cherry-studio
接入
注意:cherry-studio
需要安装bun和uv,否则可能会报错
点击保存后会与你的mcp-代码建立连接,连接完成如下:
如果你做到了和我上面一样,那么接下来我们来实现发邮件的功能,代码如下:
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListToolsRequestSchema,
CallToolRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import * as nodemailer from 'nodemailer';
const server = new Server({
name: "email-mcp-server",
version: "0.0.1",
}, {
capabilities: {
tools: {}
}
});
// 环境变量配置
const EMAIL_HOST = process.env.EMAIL_HOST || 'smtp.qq.com';
const EMAIL_PORT = parseInt(process.env.EMAIL_PORT || '465');
const EMAIL_USER = process.env.EMAIL_USER;
const EMAIL_PASS = process.env.EMAIL_PASS;
if (!EMAIL_USER || !EMAIL_PASS) {
console.error("EMAIL_USER or EMAIL_PASS environment variable is not set");
process.exit(1);
}
// 创建邮件传输器
const transporter = nodemailer.createTransport({
host: EMAIL_HOST,
port: EMAIL_PORT,
secure: true,
auth: {
user: EMAIL_USER,
pass: EMAIL_PASS,
},
});
// List available tools 一定要有,否则无法接入mcp-client
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "send-email",
description: "发送邮件,支持HTML内容、表格和附件",
inputSchema: {
type: "object",
properties: {
to: {
type: "string",
description: "收件人邮箱,多个收件人用逗号分隔",
},
cc: {
type: "string",
description: "抄送邮箱,多个抄送用逗号分隔",
},
subject: {
type: "string",
description: "邮件主题",
},
html: {
type: "string",
description: "邮件HTML内容,支持表格等HTML标签",
},
attachments: {
type: "array",
description: "附件列表",
items: {
type: "object",
properties: {
filename: { type: "string" },
path: { type: "string" }
}
}
}
},
required: ["to", "subject", "html"],
},
},
],
};
});
// 处理发送邮件请求
server.setRequestHandler(CallToolRequestSchema, async (request) => {
try {
if (!request.params.name || !request.params.arguments) {
return {
success: false,
error: "Tool name and arguments are required"
};
}
if (request.params.name === "send-email") {
const args = request.params.arguments as {
to: string;
cc?: string;
subject: string;
html: string;
attachments?: Array<{ filename: string; path: string }>;
};
if (!args.to || !args.subject || !args.html) {
return {
success: false,
error: "Required fields missing: to, subject, and html are required"
};
}
const mailOptions = {
from: EMAIL_USER,
to: args.to,
cc: args.cc,
subject: args.subject,
html: args.html,
attachments: args.attachments
};
const info = await transporter.sendMail(mailOptions);
return {
success: true,
data: {
}
};
}
return {
success: false,
error: `Unknown tool: ${request.params.name}`
};
} catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error occurred"
};
}
});
// 启动服务
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("First MCP Server running on stdio");
}
// 异常捕获
main().catch((error) => {
console.error("Fatal error in main():", error);
process.exit(1);
});
这里增加了一个发送邮件的nodemailer
依赖,所以需要npm安装一下
npm install --save @types/nodemailer
然后再次执行构建 npm run build
,构建后去cherry-studio
简单修改下属性点击保存
这里有几个参数我给个示例
EMAIL_HOST=smtp.qq.com
EMAIL_PORT=465
[email protected]
EMAIL_PASS=lrjlmbyslnxxxx
注意EMAIL_PASS
需要手动去开启邮箱的smtp服务,开启后会有一个码,开启位置如下:
然后问大模型问题就可以了
最后附一下视频: