mcp-server-feishu-bitable
Version:
飞书群聊机器人日报 MCP 服务器
215 lines (190 loc) • 6.14 kB
JavaScript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import axios from 'axios';
const FEISHU_WEBHOOK_URL = process.env.FEISHU_WEBHOOK_URL;
class FeishuWebhookMCPServer {
constructor() {
this.server = new Server({
name: "feishu-webhook-mcp-server",
version: "1.0.3",
}, {
capabilities: {
tools: {},
},
});
this.setupHandlers();
}
async sendToFeishu(content) {
if (!FEISHU_WEBHOOK_URL) {
throw new Error('未配置飞书 Webhook URL,请在环境变量中设置 FEISHU_WEBHOOK_URL');
}
try {
console.error('正在发送到飞书...', {
hasUrl: !!FEISHU_WEBHOOK_URL,
contentLength: content.length
});
const response = await axios.post(FEISHU_WEBHOOK_URL, {
msg_type: "text",
content: {
text: content
}
}, {
headers: {
'Content-Type': 'application/json',
}
});
console.error('飞书响应:', response.status, response.data);
return response.data;
} catch (error) {
console.error('发送到飞书失败:', error.response?.data || error.message);
if (error.response) {
throw new Error(`发送失败: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
} else {
throw new Error(`发送失败: ${error.message}`);
}
}
}
async testWebhook() {
try {
const testMessage = `🔍 连接测试 - ${new Date().toLocaleString('zh-CN')}`;
await this.sendToFeishu(testMessage);
return { success: true };
} catch (error) {
return { success: false, error: error.message };
}
}
formatDailyReport(content) {
const today = new Date();
const dateStr = today.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
weekday: 'long'
});
const timeStr = today.toLocaleTimeString('zh-CN');
return `📊 工作日报 - ${dateStr}
${content}
---
✨ 通过 Trae 自动提交
⏰ 提交时间: ${timeStr}`;
}
setupHandlers() {
// 使用正确的 schema 注册处理器
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "test_webhook",
description: "测试飞书群聊机器人连接",
inputSchema: {
type: "object",
properties: {}
}
},
{
name: "send_daily_report",
description: "发送日报到飞书群聊",
inputSchema: {
type: "object",
properties: {
content: {
type: "string",
description: "日报内容"
}
},
required: ["content"]
}
},
{
name: "send_message",
description: "发送消息到飞书群聊",
inputSchema: {
type: "object",
properties: {
content: {
type: "string",
description: "消息内容"
}
},
required: ["content"]
}
}
]
};
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "test_webhook":
const testResult = await this.testWebhook();
if (testResult.success) {
return {
content: [
{
type: "text",
text: `✅ 飞书群聊机器人连接测试成功!\n🤖 测试消息已发送到群聊\n🔗 Webhook 状态: 正常`
}
]
};
} else {
return {
content: [
{
type: "text",
text: `❌ 连接测试失败: ${testResult.error}`
}
],
isError: true
};
}
case "send_daily_report":
const formattedContent = this.formatDailyReport(args.content);
await this.sendToFeishu(formattedContent);
return {
content: [
{
type: "text",
text: `✅ 日报发送成功!\n📝 内容已发送到飞书群聊\n📄 日期: ${new Date().toLocaleDateString('zh-CN')}\n📋 预览: ${args.content.substring(0, 100)}${args.content.length > 100 ? '...' : ''}`
}
]
};
case "send_message":
await this.sendToFeishu(args.content);
return {
content: [
{
type: "text",
text: `✅ 消息发送成功!\n📝 内容: ${args.content.substring(0, 100)}${args.content.length > 100 ? '...' : ''}`
}
]
};
default:
throw new Error(`未知工具: ${name}`);
}
} catch (error) {
return {
content: [
{
type: "text",
text: `❌ 操作失败: ${error.message}`
}
],
isError: true
};
}
});
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error("飞书群聊机器人 MCP 服务器已启动");
}
}
const server = new FeishuWebhookMCPServer();
server.run().catch(console.error);