@perk-net/pushplus-mcp-server
Version:
PushPlus MCP Server - 通过 Model Context Protocol 提供 PushPlus 推送消息功能,支持微信、邮箱等多渠道推送
422 lines • 19.3 kB
JavaScript
/**
* PushPlus MCP Server 主文件
* 实现 Model Context Protocol 服务器,提供 PushPlus 推送功能
*/
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
import { PushPlusClient } from './pushplus.js';
import { getConfig } from './config.js';
/**
* PushPlus MCP Server 类
*/
export class PushPlusMcpServer {
server;
pushPlusClient;
config = getConfig();
constructor() {
// 验证配置
const validation = this.config.validateConfig();
if (!validation.valid) {
throw new Error(`配置验证失败:\n${validation.errors.join('\n')}`);
}
// 初始化 MCP 服务器
this.server = new McpServer({
name: this.config.getMcpServerName(),
version: this.config.getMcpServerVersion()
});
// 初始化 PushPlus 客户端
this.pushPlusClient = new PushPlusClient(this.config.getPushPlusToken());
// 注册工具和资源
this.registerTools();
this.registerResources();
}
/**
* 注册 MCP 工具
*/
registerTools() {
// 发送推送消息工具
this.server.registerTool('send_push_message', {
title: '发送推送消息',
description: '通过 PushPlus 发送推送消息到微信、邮箱等渠道',
inputSchema: {
title: z.string().max(100, '消息标题最大长度100字符').describe('消息标题'),
content: z.string().describe('消息内容,支持HTML、文本、Markdown等格式'),
template: z.enum(['html', 'txt', 'json', 'markdown', 'cloudMonitor', 'jenkins', 'route', 'pay']).optional().describe('消息模板类型'),
channel: z.enum(['wechat', 'webhook', 'cp', 'mail', 'sms']).optional().describe('推送渠道'),
topic: z.string().optional().describe('群组编码,不填仅发送给自己'),
to: z.string().optional().describe('好友令牌,微信公众号渠道填写好友令牌,企业微信渠道填写企业微信用户id。多人用逗号隔开'),
pre: z.string().optional().describe('预处理编码,仅供会员使用。可提前自定义代码来修改消息内容'),
webhook: z.string().url().optional().describe('第三方webhook地址(仅当channel为webhook时使用)'),
callbackUrl: z.string().url().optional().describe('消息回调地址')
}
}, async ({ title, content, template, channel, topic, to, pre, webhook, callbackUrl }) => {
try {
const result = await this.pushPlusClient.sendMessage({
title,
content,
template: template || this.config.getDefaultTemplate(),
channel: channel || this.config.getDefaultChannel(),
topic,
to,
pre,
webhook,
callbackUrl
});
const success = result.code === 200;
const statusText = success ? '✅ HTTP请求成功' : '❌ HTTP请求失败';
let responseText = `${statusText}\n\n📊 响应详情:\n- 状态码: ${result.code}\n- 消息: ${result.msg}`;
if (result.data) {
responseText += `\n- 📋 流水号: ${result.data} (重要!可用于查询消息发送状态)`;
}
responseText += `\n- 计数: ${result.count || 0}`;
if (success) {
responseText += '\n\n⚠️ 注意:HTTP请求成功不代表消息已送达,实际发送可能需要一些时间。';
}
return {
content: [{
type: 'text',
text: responseText
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `❌ 请求失败: ${error instanceof Error ? error.message : String(error)}`
}],
isError: true
};
}
});
// 发送快速文本消息工具
this.server.registerTool('send_text_message', {
title: '发送文本消息',
description: '快速发送纯文本推送消息',
inputSchema: {
title: z.string().max(100, '消息标题最大长度100字符').describe('消息标题'),
content: z.string().describe('消息内容(纯文本)'),
topic: z.string().optional().describe('群组编码,不填仅发送给自己'),
to: z.string().optional().describe('好友令牌,多人用逗号隔开'),
pre: z.string().optional().describe('预处理编码,仅供会员使用')
}
}, async ({ title, content, topic, to, pre }) => {
try {
const result = await this.pushPlusClient.sendTextMessage(title, content, { topic, to, pre });
const success = result.code === 200;
const statusText = success ? '✅ 文本消息HTTP请求成功' : '❌ 文本消息HTTP请求失败';
let responseText = `${statusText}\n\n📊 响应详情:\n- 状态码: ${result.code}\n- 消息: ${result.msg}`;
if (result.data) {
responseText += `\n- 📋 流水号: ${result.data} (重要!可用于查询消息发送状态)`;
}
responseText += `\n- 计数: ${result.count || 0}`;
if (success) {
responseText += '\n\n⚠️ 注意:HTTP请求成功不代表消息已送达,实际发送可能需要一些时间。';
}
return {
content: [{
type: 'text',
text: responseText
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `❌ 请求失败: ${error instanceof Error ? error.message : String(error)}`
}],
isError: true
};
}
});
// 发送HTML消息工具
this.server.registerTool('send_html_message', {
title: '发送HTML消息',
description: '发送带有HTML格式的推送消息',
inputSchema: {
title: z.string().max(100, '消息标题最大长度100字符').describe('消息标题'),
content: z.string().describe('消息内容(HTML格式)'),
topic: z.string().optional().describe('群组编码,不填仅发送给自己'),
to: z.string().optional().describe('好友令牌,多人用逗号隔开'),
pre: z.string().optional().describe('预处理编码,仅供会员使用')
}
}, async ({ title, content, topic, to, pre }) => {
try {
const result = await this.pushPlusClient.sendHtmlMessage(title, content, { topic, to, pre });
const success = result.code === 200;
const statusText = success ? '✅ HTML消息HTTP请求成功' : '❌ HTML消息HTTP请求失败';
let responseText = `${statusText}\n\n📊 响应详情:\n- 状态码: ${result.code}\n- 消息: ${result.msg}`;
if (result.data) {
responseText += `\n- 📋 流水号: ${result.data} (重要!可用于查询消息发送状态)`;
}
responseText += `\n- 计数: ${result.count || 0}`;
if (success) {
responseText += '\n\n⚠️ 注意:HTTP请求成功不代表消息已送达,实际发送可能需要一些时间。';
}
return {
content: [{
type: 'text',
text: responseText
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `❌ 请求失败: ${error instanceof Error ? error.message : String(error)}`
}],
isError: true
};
}
});
// 发送Markdown消息工具
this.server.registerTool('send_markdown_message', {
title: '发送Markdown消息',
description: '发送Markdown格式的推送消息',
inputSchema: {
title: z.string().max(100, '消息标题最大长度100字符').describe('消息标题'),
content: z.string().describe('消息内容(Markdown格式)'),
topic: z.string().optional().describe('群组编码,不填仅发送给自己'),
to: z.string().optional().describe('好友令牌,多人用逗号隔开'),
pre: z.string().optional().describe('预处理编码,仅供会员使用')
}
}, async ({ title, content, topic, to, pre }) => {
try {
const result = await this.pushPlusClient.sendMarkdownMessage(title, content, { topic, to, pre });
const success = result.code === 200;
const statusText = success ? '✅ Markdown消息HTTP请求成功' : '❌ Markdown消息HTTP请求失败';
let responseText = `${statusText}\n\n📊 响应详情:\n- 状态码: ${result.code}\n- 消息: ${result.msg}`;
if (result.data) {
responseText += `\n- 📋 流水号: ${result.data} (重要!可用于查询消息发送状态)`;
}
responseText += `\n- 计数: ${result.count || 0}`;
if (success) {
responseText += '\n\n⚠️ 注意:HTTP请求成功不代表消息已送达,实际发送可能需要一些时间。';
}
return {
content: [{
type: 'text',
text: responseText
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `❌ 请求失败: ${error instanceof Error ? error.message : String(error)}`
}],
isError: true
};
}
});
// 发送JSON消息工具
this.server.registerTool('send_json_message', {
title: '发送JSON消息',
description: '发送JSON格式的推送消息',
inputSchema: {
title: z.string().max(100, '消息标题最大长度100字符').describe('消息标题'),
content: z.string().describe('消息内容(JSON格式)'),
topic: z.string().optional().describe('群组编码,不填仅发送给自己'),
to: z.string().optional().describe('好友令牌,多人用逗号隔开'),
pre: z.string().optional().describe('预处理编码,仅供会员使用')
}
}, async ({ title, content, topic, to, pre }) => {
try {
const result = await this.pushPlusClient.sendJsonMessage(title, content, { topic, to, pre });
const success = result.code === 200;
const statusText = success ? '✅ JSON消息HTTP请求成功' : '❌ JSON消息HTTP请求失败';
let responseText = `${statusText}\n\n📊 响应详情:\n- 状态码: ${result.code}\n- 消息: ${result.msg}`;
if (result.data) {
responseText += `\n- 📋 流水号: ${result.data} (重要!可用于查询消息发送状态)`;
}
responseText += `\n- 计数: ${result.count || 0}`;
if (success) {
responseText += '\n\n⚠️ 注意:HTTP请求成功不代表消息已送达,实际发送可能需要一些时间。';
}
return {
content: [{
type: 'text',
text: responseText
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `❌ 请求失败: ${error instanceof Error ? error.message : String(error)}`
}],
isError: true
};
}
});
}
/**
* 注册 MCP 资源
*/
registerResources() {
// 服务器状态资源
this.server.registerResource('server_status', 'pushplus://status', {
title: 'PushPlus MCP Server 状态',
description: '获取服务器状态和配置信息',
mimeType: 'application/json'
}, async () => {
const status = {
server: {
name: this.config.getMcpServerName(),
version: this.config.getMcpServerVersion(),
status: 'running'
},
pushplus: {
token: this.pushPlusClient.getDefaultTokenMasked(),
api_endpoint: 'https://www.pushplus.plus/send'
},
config: {
default_template: this.config.getDefaultTemplate(),
default_channel: this.config.getDefaultChannel(),
debug_mode: this.config.isDebugMode()
},
timestamp: new Date().toISOString()
};
return {
contents: [{
uri: 'pushplus://status',
mimeType: 'application/json',
text: JSON.stringify(status, null, 2)
}]
};
});
// 支持的模板类型资源
this.server.registerResource('templates', 'pushplus://templates', {
title: '支持的消息模板',
description: '获取 PushPlus 支持的所有消息模板类型',
mimeType: 'application/json'
}, async () => {
const templates = {
templates: [
{
name: 'html',
description: 'HTML格式消息,支持HTML标签和样式',
example: '<h1>标题</h1><p>内容</p>'
},
{
name: 'txt',
description: '纯文本消息,简单易读',
example: '标题\\n内容'
},
{
name: 'json',
description: 'JSON格式消息,适合结构化数据',
example: '{"title": "标题", "content": "内容"}'
},
{
name: 'markdown',
description: 'Markdown格式消息,支持Markdown语法',
example: '# 标题\\n\\n内容'
},
{
name: 'cloudMonitor',
description: '云监控消息格式,适合告警通知',
example: '告警: 服务器CPU使用率过高'
},
{
name: 'jenkins',
description: 'Jenkins消息格式,适合Jenkins通知'
},
{
name: 'route',
description: '路由消息格式,适合路由通知',
},
{
name: 'pay',
description: '支付消息格式,适合支付通知'
}
]
};
return {
contents: [{
uri: 'pushplus://templates',
mimeType: 'application/json',
text: JSON.stringify(templates, null, 2)
}]
};
});
// 支持的推送渠道资源
this.server.registerResource('channels', 'pushplus://channels', {
title: '支持的推送渠道',
description: '获取 PushPlus 支持的所有推送渠道',
mimeType: 'application/json'
}, async () => {
const channels = {
channels: [
{
name: 'wechat',
description: '微信推送,通过微信公众号发送',
default: true
},
{
name: 'webhook',
description: '第三方webhook推送',
requires: ['webhook参数']
},
{
name: 'cp',
description: '企业微信推送',
note: '需要配置企业微信应用'
},
{
name: 'mail',
description: '邮箱推送',
note: '需要绑定邮箱'
},
{
name: 'sms',
description: '短信推送',
note: '需要绑定手机号'
}
]
};
return {
contents: [{
uri: 'pushplus://channels',
mimeType: 'application/json',
text: JSON.stringify(channels, null, 2)
}]
};
});
}
/**
* 启动服务器
*/
async start() {
if (this.config.isDebugMode()) {
this.config.printConfig();
console.log('🚀 启动 PushPlus MCP Server...');
}
try {
const transport = new StdioServerTransport();
await this.server.connect(transport);
if (this.config.isDebugMode()) {
console.log('✅ PushPlus MCP Server 已启动,正在监听 stdio...');
}
}
catch (error) {
console.error('❌ 启动服务器失败:', error);
process.exit(1);
}
}
/**
* 停止服务器
*/
async stop() {
if (this.config.isDebugMode()) {
console.log('🛑 正在停止 PushPlus MCP Server...');
}
// MCP SDK 会自动处理清理工作
}
}
//# sourceMappingURL=server.js.map