index.js•8.68 kB
#!/usr/bin/env node
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 { GitLabService } from './services/gitlab.js';
import { WeChatService } from './services/wechat.js';
import { config } from './config/index.js';
import { logger } from './utils/logger.js';
import { ErrorHandler, ValidationError } from './utils/errors.js';
class GitLabWeChatMCPServer {
constructor() {
const mcpConfig = config.getMCPConfig();
this.server = new Server(
{
name: mcpConfig.serverName,
version: mcpConfig.serverVersion,
},
{
capabilities: {
tools: {},
},
}
);
this.gitlabService = new GitLabService(config.getGitLabConfig());
this.wechatService = new WeChatService(config.getWeChatConfig());
this.setupToolHandlers();
logger.info('MCP服务器初始化完成');
}
setupToolHandlers() {
// 列出可用工具
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'get_gitlab_commits',
description: '获取GitLab用户在指定日期的代码提交记录',
inputSchema: {
type: 'object',
properties: {
username: {
type: 'string',
description: 'GitLab用户名(可选,默认使用配置的用户名)',
},
date: {
type: 'string',
description: '查询日期,格式:YYYY-MM-DD',
},
projectId: {
type: 'string',
description: '项目ID(可选,不指定则查询所有项目)',
},
},
required: ['date'],
},
},
{
name: 'send_to_wechat',
description: '发送消息到企业微信',
inputSchema: {
type: 'object',
properties: {
message: {
type: 'string',
description: '要发送的消息内容',
},
messageType: {
type: 'string',
enum: ['text', 'markdown'],
description: '消息类型',
default: 'text',
},
},
required: ['message'],
},
},
{
name: 'generate_daily_report',
description: '生成并发送GitLab提交记录的日报到企业微信',
inputSchema: {
type: 'object',
properties: {
username: {
type: 'string',
description: 'GitLab用户名(可选,默认使用配置的用户名)',
},
date: {
type: 'string',
description: '查询日期,格式:YYYY-MM-DD',
},
projectId: {
type: 'string',
description: '项目ID(可选,不指定则查询所有项目)',
},
},
required: ['date'],
},
},
],
};
});
// 处理工具调用
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
logger.info(`执行工具: ${name}`, args);
switch (name) {
case 'get_gitlab_commits':
return await this.handleGetGitLabCommits(args);
case 'send_to_wechat':
return await this.handleSendToWeChat(args);
case 'generate_daily_report':
return await this.handleGenerateDailyReport(args);
default:
throw new McpError(
ErrorCode.MethodNotFound,
`未知工具: ${name}`
);
}
} catch (error) {
logger.error(`工具执行失败: ${name}`, error);
if (error instanceof ValidationError) {
throw new McpError(
ErrorCode.InvalidParams,
ErrorHandler.createUserMessage(error)
);
}
throw new McpError(
ErrorCode.InternalError,
ErrorHandler.createUserMessage(error)
);
}
});
}
async handleGetGitLabCommits(args) {
// 验证参数
ErrorHandler.validateParams(args, {
date: { required: true, type: 'string', format: 'date' },
username: { required: false, type: 'string' },
projectId: { required: false, type: 'string' },
});
const { username, date, projectId } = args;
const gitlabConfig = config.getGitLabConfig();
const commits = await this.gitlabService.getCommitsByDate(
username || gitlabConfig.username,
date,
projectId
);
logger.info(`获取到 ${commits.length} 条提交记录`, { date, username: username || gitlabConfig.username });
return {
content: [
{
type: 'text',
text: JSON.stringify(commits, null, 2),
},
],
};
}
async handleSendToWeChat(args) {
// 验证参数
ErrorHandler.validateParams(args, {
message: { required: true, type: 'string' },
messageType: { required: false, type: 'string', enum: ['text', 'markdown'] },
});
const { message, messageType = 'text' } = args;
const result = await this.wechatService.sendMessage(message, messageType);
logger.info(`企业微信消息发送${result.success ? '成功' : '失败'}`, { messageType });
return {
content: [
{
type: 'text',
text: `消息发送${result.success ? '成功' : '失败'}: ${result.message}`,
},
],
};
}
async handleGenerateDailyReport(args) {
// 验证参数
ErrorHandler.validateParams(args, {
date: { required: true, type: 'string', format: 'date' },
username: { required: false, type: 'string' },
projectId: { required: false, type: 'string' },
});
const { username, date, projectId } = args;
const gitlabConfig = config.getGitLabConfig();
const actualUsername = username || gitlabConfig.username;
logger.info('开始生成日报', { date, username: actualUsername, projectId });
// 获取提交记录
const commits = await this.gitlabService.getCommitsByDate(
actualUsername,
date,
projectId
);
// 生成日报内容
const report = this.generateReportContent(commits, date, actualUsername);
// 发送到企业微信
const result = await this.wechatService.sendMessage(report, 'markdown');
logger.info(`日报生成并发送${result.success ? '成功' : '失败'}`, { commitCount: commits.length });
return {
content: [
{
type: 'text',
text: `日报生成并发送${result.success ? '成功' : '失败'}\n\n报告内容:\n${report}`,
},
],
};
}
generateReportContent(commits, date, username) {
const commitCount = commits.length;
const projects = [...new Set(commits.map(c => c.project_name))];
let report = `# ${username} 的代码提交日报\n\n`;
report += `**日期**: ${date}\n`;
report += `**提交数量**: ${commitCount}\n`;
report += `**涉及项目**: ${projects.join(', ')}\n\n`;
if (commitCount === 0) {
report += '今日无代码提交记录。';
} else {
report += '## 提交详情\n\n';
commits.forEach((commit, index) => {
report += `### ${index + 1}. ${commit.title}\n`;
report += `- **项目**: ${commit.project_name}\n`;
report += `- **时间**: ${new Date(commit.committed_date).toLocaleString('zh-CN')}\n`;
report += `- **分支**: ${commit.ref_name || 'unknown'}\n`;
if (commit.message && commit.message !== commit.title) {
report += `- **详情**: ${commit.message.replace(commit.title, '').trim()}\n`;
}
report += `- **链接**: [查看提交](${commit.web_url})\n\n`;
});
}
return report;
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('GitLab WeChat MCP Server running on stdio');
}
}
// 启动服务器
const server = new GitLabWeChatMCPServer();
server.run().catch(console.error);