@lmcl/ailo-mcp-feishu 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/feishu-handler.js +1231 -0
- package/dist/index.js +38 -0
- package/dist/mcp-server.js +93 -0
- package/package.json +28 -0
- package/src/feishu-handler.ts +1470 -0
- package/src/index.ts +46 -0
- package/src/mcp-server.ts +114 -0
- package/tsconfig.json +13 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "dotenv/config";
|
|
3
|
+
import { runMcpChannel } from "@lmcl/ailo-mcp-sdk";
|
|
4
|
+
import { FeishuHandler } from "./feishu-handler.js";
|
|
5
|
+
import { createFeishuMcpServer } from "./mcp-server.js";
|
|
6
|
+
const FEISHU_APP_ID = process.env.FEISHU_APP_ID ?? "";
|
|
7
|
+
const FEISHU_APP_SECRET = process.env.FEISHU_APP_SECRET ?? "";
|
|
8
|
+
const FEISHU_DOMAIN = process.env.FEISHU_DOMAIN === "lark" ? "lark" : "feishu";
|
|
9
|
+
if (!FEISHU_APP_ID || !FEISHU_APP_SECRET) {
|
|
10
|
+
console.error("Missing FEISHU_APP_ID or FEISHU_APP_SECRET");
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
const handler = new FeishuHandler({
|
|
14
|
+
appId: FEISHU_APP_ID,
|
|
15
|
+
appSecret: FEISHU_APP_SECRET,
|
|
16
|
+
domain: FEISHU_DOMAIN,
|
|
17
|
+
});
|
|
18
|
+
handler.setOnBotRemovedFromGroup((chatId) => {
|
|
19
|
+
console.log("[feishu] bot removed from group", chatId);
|
|
20
|
+
});
|
|
21
|
+
handler.setOnMessageRead(() => { });
|
|
22
|
+
function feishuBuildChannelPrompt() {
|
|
23
|
+
return `ID 格式:ou_xxx 是飞书用户 ID,oc_xxx 是群组 ID。
|
|
24
|
+
|
|
25
|
+
@提及:@提及格式为 @显示名(ou_xxx)。使用此格式可触发飞书强提醒。
|
|
26
|
+
|
|
27
|
+
表情:飞书仅支持 Unicode emoji(😊👍❤️),不支持 :xxx: 冒号格式。
|
|
28
|
+
|
|
29
|
+
外部用户:昵称为"外部用户N"的是非本组织成员,飞书无法获取其真实姓名。同一编号始终对应同一人。昵称可通过 set_nickname 工具更新。
|
|
30
|
+
|
|
31
|
+
转发限制:私聊消息只能发给曾与你发起过私聊的用户。`;
|
|
32
|
+
}
|
|
33
|
+
const mcpServer = createFeishuMcpServer(handler);
|
|
34
|
+
runMcpChannel({
|
|
35
|
+
handler,
|
|
36
|
+
buildChannelPrompt: feishuBuildChannelPrompt,
|
|
37
|
+
mcpServer,
|
|
38
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 飞书通道 MCP 服务:stdio 传输,暴露飞书特有工具供 AI 直接调用。
|
|
3
|
+
*/
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
export function createFeishuMcpServer(handler) {
|
|
7
|
+
const server = new McpServer({
|
|
8
|
+
name: "feishu",
|
|
9
|
+
version: "0.1.0",
|
|
10
|
+
});
|
|
11
|
+
server.registerTool("send_message", {
|
|
12
|
+
description: "向飞书聊天发送消息。chat_id 使用信号中的 chat_id 标签值(ou_xxx 是私聊用户,oc_xxx 是群聊)。",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
chat_id: z.string().describe("目标聊天 ID(ou_xxx 私聊 / oc_xxx 群聊)"),
|
|
15
|
+
text: z.string().describe("消息内容"),
|
|
16
|
+
},
|
|
17
|
+
}, async ({ chat_id, text }) => {
|
|
18
|
+
try {
|
|
19
|
+
await handler.sendText(chat_id, text);
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: "text", text: `消息已发送到 ${chat_id}` }],
|
|
22
|
+
isError: false,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: `发送失败: ${err.message}` }],
|
|
28
|
+
isError: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
server.registerTool("read_doc", {
|
|
33
|
+
description: "读取飞书云文档内容(含图片引用)。传入文档 URL(如 feishu.cn/docx/xxx)。新版文档中的图片会以 [图片 N](url) 形式返回。",
|
|
34
|
+
inputSchema: {
|
|
35
|
+
url: z.string().describe("飞书云文档完整 URL"),
|
|
36
|
+
},
|
|
37
|
+
}, async ({ url }) => {
|
|
38
|
+
const content = await handler.fetchDocRawContent(url);
|
|
39
|
+
if (content === null) {
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: "text", text: "无法获取文档内容(可能无权限或链接无效)" }],
|
|
42
|
+
isError: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: "text", text: content }],
|
|
47
|
+
isError: false,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
server.registerTool("set_nickname", {
|
|
51
|
+
description: "更新飞书用户的昵称映射。用于给外部用户设置可识别的名称。",
|
|
52
|
+
inputSchema: {
|
|
53
|
+
sender_id: z.string().describe("飞书用户 open_id(ou_xxx)"),
|
|
54
|
+
nickname: z.string().describe("新昵称"),
|
|
55
|
+
},
|
|
56
|
+
}, async ({ sender_id, nickname }) => {
|
|
57
|
+
try {
|
|
58
|
+
await handler.onCommand("set_nickname", { sender_id, nickname });
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: "text", text: `已将 ${sender_id} 的昵称设为 ${nickname}` }],
|
|
61
|
+
isError: false,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
return {
|
|
66
|
+
content: [{ type: "text", text: `设置失败: ${err.message}` }],
|
|
67
|
+
isError: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
server.registerTool("add_reaction", {
|
|
72
|
+
description: "给飞书消息贴表情回应。仅支持 Unicode emoji。",
|
|
73
|
+
inputSchema: {
|
|
74
|
+
message_id: z.string().describe("消息 ID"),
|
|
75
|
+
emoji_type: z.string().describe("emoji 标识(如 OK、ThumbsUp、Heart)"),
|
|
76
|
+
},
|
|
77
|
+
}, async ({ message_id, emoji_type }) => {
|
|
78
|
+
try {
|
|
79
|
+
await handler.onCommand("add_reaction", { message_id, emoji_type });
|
|
80
|
+
return {
|
|
81
|
+
content: [{ type: "text", text: `已对消息 ${message_id} 贴上 ${emoji_type}` }],
|
|
82
|
+
isError: false,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
return {
|
|
87
|
+
content: [{ type: "text", text: `贴表情失败: ${err.message}` }],
|
|
88
|
+
isError: true,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
return server;
|
|
93
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lmcl/ailo-mcp-feishu",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Ailo 飞书/Lark 通道 MCP",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"ailo-mcp-feishu": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "tsx src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@lmcl/ailo-mcp-sdk": "^0.0.1",
|
|
17
|
+
"@larksuiteoapi/node-sdk": "^1.56.1",
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
19
|
+
"dotenv": "^16.4.5",
|
|
20
|
+
"form-data": "^4.0.0",
|
|
21
|
+
"zod": "^4.3.6"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.10.0",
|
|
25
|
+
"tsx": "^4.19.0",
|
|
26
|
+
"typescript": "^5.7.0"
|
|
27
|
+
}
|
|
28
|
+
}
|