feishu-mcp 0.0.9-alpha.2 → 0.0.10
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/LICENSE +21 -21
- package/README.md +164 -164
- package/dist/cli.js +0 -0
- package/dist/config.js +22 -100
- package/dist/server.js +637 -39
- package/dist/services/feishu.js +0 -3
- package/dist/services/feishuBlockService.js +179 -0
- package/dist/services/feishuService.js +475 -0
- package/dist/utils/logger.js +9 -25
- package/package.json +74 -74
- package/README.en.md +0 -201
- package/dist/manager/sseConnectionManager.js +0 -104
- package/dist/mcp/feishuMcp.js +0 -67
- package/dist/mcp/tools/feishuBlockTools.js +0 -394
- package/dist/mcp/tools/feishuFolderTools.js +0 -86
- package/dist/mcp/tools/feishuTools.js +0 -138
package/dist/utils/logger.js
CHANGED
|
@@ -25,28 +25,13 @@ export class Logger {
|
|
|
25
25
|
static configure(config) {
|
|
26
26
|
this.config = { ...this.config, ...config };
|
|
27
27
|
// 确保日志目录存在
|
|
28
|
-
if (this.config.logToFile
|
|
28
|
+
if (this.config.logToFile) {
|
|
29
29
|
const logDir = path.dirname(this.config.logFilePath);
|
|
30
30
|
if (!fs.existsSync(logDir)) {
|
|
31
31
|
fs.mkdirSync(logDir, { recursive: true });
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
/**
|
|
36
|
-
* 设置日志开关
|
|
37
|
-
* @param enabled 是否启用日志
|
|
38
|
-
*/
|
|
39
|
-
static setEnabled(enabled) {
|
|
40
|
-
this.config.enabled = enabled;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* 检查日志是否可输出
|
|
44
|
-
* @param level 日志级别
|
|
45
|
-
* @returns 是否可输出
|
|
46
|
-
*/
|
|
47
|
-
static canLog(level) {
|
|
48
|
-
return this.config.enabled && level >= this.config.minLevel;
|
|
49
|
-
}
|
|
50
35
|
/**
|
|
51
36
|
* 格式化日志消息
|
|
52
37
|
* @param level 日志级别
|
|
@@ -74,7 +59,7 @@ export class Logger {
|
|
|
74
59
|
* @param logParts 日志内容部分
|
|
75
60
|
*/
|
|
76
61
|
static writeToFile(logParts) {
|
|
77
|
-
if (!this.config.
|
|
62
|
+
if (!this.config.logToFile)
|
|
78
63
|
return;
|
|
79
64
|
try {
|
|
80
65
|
// 将日志内容转换为字符串
|
|
@@ -158,7 +143,7 @@ export class Logger {
|
|
|
158
143
|
* @param args 日志参数
|
|
159
144
|
*/
|
|
160
145
|
static debug(...args) {
|
|
161
|
-
if (this.
|
|
146
|
+
if (this.config.minLevel <= LogLevel.DEBUG) {
|
|
162
147
|
const formattedMessage = this.formatLogMessage(LogLevel.DEBUG, args);
|
|
163
148
|
console.debug(...formattedMessage);
|
|
164
149
|
this.writeToFile(formattedMessage);
|
|
@@ -169,7 +154,7 @@ export class Logger {
|
|
|
169
154
|
* @param args 日志参数
|
|
170
155
|
*/
|
|
171
156
|
static info(...args) {
|
|
172
|
-
if (this.
|
|
157
|
+
if (this.config.minLevel <= LogLevel.INFO) {
|
|
173
158
|
const formattedMessage = this.formatLogMessage(LogLevel.INFO, args);
|
|
174
159
|
console.info(...formattedMessage);
|
|
175
160
|
this.writeToFile(formattedMessage);
|
|
@@ -180,7 +165,7 @@ export class Logger {
|
|
|
180
165
|
* @param args 日志参数
|
|
181
166
|
*/
|
|
182
167
|
static log(...args) {
|
|
183
|
-
if (this.
|
|
168
|
+
if (this.config.minLevel <= LogLevel.LOG) {
|
|
184
169
|
const formattedMessage = this.formatLogMessage(LogLevel.LOG, args);
|
|
185
170
|
console.log(...formattedMessage);
|
|
186
171
|
this.writeToFile(formattedMessage);
|
|
@@ -191,7 +176,7 @@ export class Logger {
|
|
|
191
176
|
* @param args 日志参数
|
|
192
177
|
*/
|
|
193
178
|
static warn(...args) {
|
|
194
|
-
if (this.
|
|
179
|
+
if (this.config.minLevel <= LogLevel.WARN) {
|
|
195
180
|
const formattedMessage = this.formatLogMessage(LogLevel.WARN, args);
|
|
196
181
|
console.warn(...formattedMessage);
|
|
197
182
|
this.writeToFile(formattedMessage);
|
|
@@ -202,7 +187,7 @@ export class Logger {
|
|
|
202
187
|
* @param args 日志参数
|
|
203
188
|
*/
|
|
204
189
|
static error(...args) {
|
|
205
|
-
if (this.
|
|
190
|
+
if (this.config.minLevel <= LogLevel.ERROR) {
|
|
206
191
|
const formattedMessage = this.formatLogMessage(LogLevel.ERROR, args);
|
|
207
192
|
console.error(...formattedMessage);
|
|
208
193
|
this.writeToFile(formattedMessage);
|
|
@@ -217,7 +202,7 @@ export class Logger {
|
|
|
217
202
|
* @param statusCode 响应状态码
|
|
218
203
|
*/
|
|
219
204
|
static logApiCall(method, url, data, response, statusCode) {
|
|
220
|
-
if (this.
|
|
205
|
+
if (this.config.minLevel <= LogLevel.DEBUG) {
|
|
221
206
|
this.debug('API调用详情:');
|
|
222
207
|
this.debug(`请求: ${method} ${url}`);
|
|
223
208
|
// 简化请求数据记录
|
|
@@ -250,7 +235,7 @@ export class Logger {
|
|
|
250
235
|
this.debug('响应数据: None');
|
|
251
236
|
}
|
|
252
237
|
}
|
|
253
|
-
else
|
|
238
|
+
else {
|
|
254
239
|
this.info(`API调用: ${method} ${url} - 状态码: ${statusCode}`);
|
|
255
240
|
}
|
|
256
241
|
}
|
|
@@ -260,7 +245,6 @@ Object.defineProperty(Logger, "config", {
|
|
|
260
245
|
configurable: true,
|
|
261
246
|
writable: true,
|
|
262
247
|
value: {
|
|
263
|
-
enabled: true, // 默认开启日志
|
|
264
248
|
minLevel: LogLevel.DEBUG, // 修改为DEBUG级别,确保捕获所有日志
|
|
265
249
|
showTimestamp: true,
|
|
266
250
|
showLevel: true,
|
package/package.json
CHANGED
|
@@ -1,74 +1,74 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "feishu-mcp",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Model Context Protocol server for Feishu integration",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"bin": {
|
|
8
|
-
"feishu-mcp": "./dist/cli.js"
|
|
9
|
-
},
|
|
10
|
-
"files": [
|
|
11
|
-
"dist",
|
|
12
|
-
"README.md"
|
|
13
|
-
],
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "tsc && tsc-alias",
|
|
16
|
-
"type-check": "tsc --noEmit",
|
|
17
|
-
"start": "node dist/index.js",
|
|
18
|
-
"start:cli": "cross-env NODE_ENV=cli node dist/index.js",
|
|
19
|
-
"start:http": "node dist/index.js",
|
|
20
|
-
"dev": "cross-env NODE_ENV=development tsx watch src/index.ts",
|
|
21
|
-
"dev:cli": "cross-env NODE_ENV=development tsx watch src/index.ts --stdio",
|
|
22
|
-
"lint": "eslint . --ext .ts",
|
|
23
|
-
"format": "prettier --write \"src/**/*.ts\"",
|
|
24
|
-
"inspect": "pnpx @modelcontextprotocol/inspector",
|
|
25
|
-
"prepare": "pnpm run build",
|
|
26
|
-
"pub:release": "pnpm build && npm publish"
|
|
27
|
-
},
|
|
28
|
-
"engines": {
|
|
29
|
-
"node": "^20.17.0"
|
|
30
|
-
},
|
|
31
|
-
"repository": {
|
|
32
|
-
"type": "git",
|
|
33
|
-
"url": "https://github.com/cso1z/Feishu-MCP.git"
|
|
34
|
-
},
|
|
35
|
-
"keywords": [
|
|
36
|
-
"feishu",
|
|
37
|
-
"lark",
|
|
38
|
-
"mcp",
|
|
39
|
-
"typescript"
|
|
40
|
-
],
|
|
41
|
-
"author": "cso1z",
|
|
42
|
-
"license": "MIT",
|
|
43
|
-
"dependencies": {
|
|
44
|
-
"@modelcontextprotocol/sdk": "^1.6.1",
|
|
45
|
-
"@types/yargs": "^17.0.33",
|
|
46
|
-
"axios": "^1.7.9",
|
|
47
|
-
"cross-env": "^7.0.3",
|
|
48
|
-
"dotenv": "^16.4.7",
|
|
49
|
-
"express": "^4.21.2",
|
|
50
|
-
"remeda": "^2.20.1",
|
|
51
|
-
"yargs": "^17.7.2",
|
|
52
|
-
"zod": "^3.24.2"
|
|
53
|
-
},
|
|
54
|
-
"devDependencies": {
|
|
55
|
-
"@types/express": "^5.0.0",
|
|
56
|
-
"@types/jest": "^29.5.11",
|
|
57
|
-
"@types/node": "^20.17.0",
|
|
58
|
-
"@typescript-eslint/eslint-plugin": "^8.24.0",
|
|
59
|
-
"@typescript-eslint/parser": "^8.24.0",
|
|
60
|
-
"eslint": "^9.20.1",
|
|
61
|
-
"eslint-config-prettier": "^10.0.1",
|
|
62
|
-
"jest": "^29.7.0",
|
|
63
|
-
"prettier": "^3.5.0",
|
|
64
|
-
"ts-jest": "^29.2.5",
|
|
65
|
-
"tsc-alias": "^1.8.10",
|
|
66
|
-
"tsx": "^4.19.2",
|
|
67
|
-
"typescript": "^5.7.3"
|
|
68
|
-
},
|
|
69
|
-
"pnpm": {
|
|
70
|
-
"overrides": {
|
|
71
|
-
"feishu-mcp": "link:"
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "feishu-mcp",
|
|
3
|
+
"version": "0.0.10",
|
|
4
|
+
"description": "Model Context Protocol server for Feishu integration",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"feishu-mcp": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc && tsc-alias",
|
|
16
|
+
"type-check": "tsc --noEmit",
|
|
17
|
+
"start": "node dist/index.js",
|
|
18
|
+
"start:cli": "cross-env NODE_ENV=cli node dist/index.js",
|
|
19
|
+
"start:http": "node dist/index.js",
|
|
20
|
+
"dev": "cross-env NODE_ENV=development tsx watch src/index.ts",
|
|
21
|
+
"dev:cli": "cross-env NODE_ENV=development tsx watch src/index.ts --stdio",
|
|
22
|
+
"lint": "eslint . --ext .ts",
|
|
23
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
24
|
+
"inspect": "pnpx @modelcontextprotocol/inspector",
|
|
25
|
+
"prepare": "pnpm run build",
|
|
26
|
+
"pub:release": "pnpm build && npm publish"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": "^20.17.0"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/cso1z/Feishu-MCP.git"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"feishu",
|
|
37
|
+
"lark",
|
|
38
|
+
"mcp",
|
|
39
|
+
"typescript"
|
|
40
|
+
],
|
|
41
|
+
"author": "cso1z",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@modelcontextprotocol/sdk": "^1.6.1",
|
|
45
|
+
"@types/yargs": "^17.0.33",
|
|
46
|
+
"axios": "^1.7.9",
|
|
47
|
+
"cross-env": "^7.0.3",
|
|
48
|
+
"dotenv": "^16.4.7",
|
|
49
|
+
"express": "^4.21.2",
|
|
50
|
+
"remeda": "^2.20.1",
|
|
51
|
+
"yargs": "^17.7.2",
|
|
52
|
+
"zod": "^3.24.2"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/express": "^5.0.0",
|
|
56
|
+
"@types/jest": "^29.5.11",
|
|
57
|
+
"@types/node": "^20.17.0",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^8.24.0",
|
|
59
|
+
"@typescript-eslint/parser": "^8.24.0",
|
|
60
|
+
"eslint": "^9.20.1",
|
|
61
|
+
"eslint-config-prettier": "^10.0.1",
|
|
62
|
+
"jest": "^29.7.0",
|
|
63
|
+
"prettier": "^3.5.0",
|
|
64
|
+
"ts-jest": "^29.2.5",
|
|
65
|
+
"tsc-alias": "^1.8.10",
|
|
66
|
+
"tsx": "^4.19.2",
|
|
67
|
+
"typescript": "^5.7.3"
|
|
68
|
+
},
|
|
69
|
+
"pnpm": {
|
|
70
|
+
"overrides": {
|
|
71
|
+
"feishu-mcp": "link:"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
package/README.en.md
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
# Feishu MCP Server
|
|
2
|
-
|
|
3
|
-
Provides access to Feishu (Lark) documents for [Cursor](https://cursor.sh/), [Windsurf](https://codeium.com/windsurf), [Cline](https://cline.bot/), and other AI-driven coding tools, implemented based on the [Model Context Protocol](https://modelcontextprotocol.io/introduction) server.
|
|
4
|
-
|
|
5
|
-
When Cursor can access Feishu document data, it can understand and process document content more accurately, making it more efficient than other methods (such as copying and pasting text).
|
|
6
|
-
|
|
7
|
-
## Core Features
|
|
8
|
-
|
|
9
|
-
### Document Management
|
|
10
|
-
- **Create Feishu Documents**: Support for creating new Feishu documents in specified folders
|
|
11
|
-
- **Folder Management**:
|
|
12
|
-
- Get root folder information
|
|
13
|
-
- View folder contents and file lists
|
|
14
|
-
- Create new folders
|
|
15
|
-
|
|
16
|
-
### Document Content Operations
|
|
17
|
-
- **Get Document Information**:
|
|
18
|
-
- Get basic document information (title, version, etc.)
|
|
19
|
-
- Get document block structure and hierarchy
|
|
20
|
-
- Get detailed content of specific blocks
|
|
21
|
-
- **Get Document Plain Text Content**: Support for extracting complete plain text content from documents for analysis and processing
|
|
22
|
-
- **Edit Document Content**:
|
|
23
|
-
- **Text Block Operations**:
|
|
24
|
-
- Create and update text blocks with rich styles (bold, italic, underline, strikethrough, inline code)
|
|
25
|
-
- Support for text color settings (gray, brown, orange, yellow, green, blue, purple)
|
|
26
|
-
- Support for text alignment adjustment (left-aligned, centered, right-aligned)
|
|
27
|
-
- **Heading Block Operations**: Create headings from level one to level nine
|
|
28
|
-
- **Code Block Operations**:
|
|
29
|
-
- Create code blocks for multiple programming languages
|
|
30
|
-
- Support for code syntax highlighting
|
|
31
|
-
- Support for automatic line wrapping settings
|
|
32
|
-
- **List Operations**:
|
|
33
|
-
- Create ordered lists (numbered lists)
|
|
34
|
-
- Create unordered lists (bullet point lists)
|
|
35
|
-
- **Block Management Operations**:
|
|
36
|
-
- Batch content creation: Support for creating multiple different types of content blocks in a single operation
|
|
37
|
-
- Delete document blocks: Support for deleting one or more consecutive document blocks
|
|
38
|
-
- **Wiki Document Support**:
|
|
39
|
-
- Convert Feishu Wiki links to compatible document IDs for use with other document operation tools
|
|
40
|
-
- **Image Resource Processing**:
|
|
41
|
-
- Download images from Feishu using media IDs
|
|
42
|
-
|
|
43
|
-
### Planned Features
|
|
44
|
-
- **Advanced Content Insertion**:
|
|
45
|
-
- Table insertion: Support for row and column structured data
|
|
46
|
-
- Insert charts: Support for various data visualization charts
|
|
47
|
-
- Insert flowcharts: Support for flowcharts and mind maps
|
|
48
|
-
- Insert formulas: Support for mathematical formulas and scientific symbols
|
|
49
|
-
- Recognition and parsing of charts and flowcharts
|
|
50
|
-
|
|
51
|
-
Quick start, see the [Configuration](#configuration) section for details:
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
npx feishu-mcp --feishu-app-id=<YOUR_FEISHU_APP_ID> --feishu-app-secret=<YOUR_FEISHU_APP_SECRET>
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
## How It Works
|
|
58
|
-
|
|
59
|
-
1. Open the editor in Cursor's Agent mode.
|
|
60
|
-
2. Paste a Feishu document link.
|
|
61
|
-
3. Ask Cursor to perform operations based on the Feishu document—for example, analyze document content or create related code.
|
|
62
|
-
4. Cursor will retrieve relevant metadata from Feishu and use it to assist in writing code.
|
|
63
|
-
|
|
64
|
-
This MCP server is designed specifically for Cursor. Before responding with content from the [Feishu API](https://open.feishu.cn/document/home/introduction-to-lark-open-platform/overview), it simplifies and transforms the responses, ensuring that only the most relevant document information is provided to the model.
|
|
65
|
-
|
|
66
|
-
## Installation
|
|
67
|
-
|
|
68
|
-
### Quickly Run the Server Using NPM
|
|
69
|
-
|
|
70
|
-
You can quickly run the server using NPM without installing or building the repository:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
npx feishu-mcp --feishu-app-id=<YOUR_FEISHU_APP_ID> --feishu-app-secret=<YOUR_FEISHU_APP_SECRET>
|
|
74
|
-
|
|
75
|
-
# or
|
|
76
|
-
pnpx feishu-mcp --feishu-app-id=<YOUR_FEISHU_APP_ID> --feishu-app-secret=<YOUR_FEISHU_APP_SECRET>
|
|
77
|
-
|
|
78
|
-
# or
|
|
79
|
-
yarn dlx feishu-mcp --feishu-app-id=<YOUR_FEISHU_APP_ID> --feishu-app-secret=<YOUR_FEISHU_APP_SECRET>
|
|
80
|
-
|
|
81
|
-
# or
|
|
82
|
-
bunx feishu-mcp --feishu-app-id=<YOUR_FEISHU_APP_ID> --feishu-app-secret=<YOUR_FEISHU_APP_SECRET>
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
**Published to the Smithery platform, available at: https://smithery.ai/server/@cso1z/feishu-mcp**
|
|
86
|
-
|
|
87
|
-
Instructions on how to create a Feishu application and obtain application credentials can be found in the [official tutorial](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app).
|
|
88
|
-
|
|
89
|
-
**Detailed Feishu application configuration steps**: For detailed guidance on registering a Feishu application, configuring permissions, and adding document access permissions, please refer to [Step-by-step tutorial FEISHU_CONFIG.md](FEISHU_CONFIG.md).
|
|
90
|
-
|
|
91
|
-
### JSON Configuration for Tools Using Configuration Files
|
|
92
|
-
|
|
93
|
-
Many tools such as Windsurf, Cline, and [Claude Desktop](https://claude.ai/download) use configuration files to start servers.
|
|
94
|
-
|
|
95
|
-
The `feishu-mcp` server can be configured by adding the following to the configuration file:
|
|
96
|
-
|
|
97
|
-
```json
|
|
98
|
-
{
|
|
99
|
-
"mcpServers": {
|
|
100
|
-
"feishu-mcp": {
|
|
101
|
-
"command": "npx",
|
|
102
|
-
"args": ["-y", "feishu-mcp", "--stdio"],
|
|
103
|
-
"env": {
|
|
104
|
-
"FEISHU_APP_ID": "<YOUR_FEISHU_APP_ID>",
|
|
105
|
-
"FEISHU_APP_SECRET": "<YOUR_FEISHU_APP_SECRET>"
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Run the Server from Local Source Code
|
|
113
|
-
|
|
114
|
-
1. Clone the repository
|
|
115
|
-
2. Install dependencies using `pnpm install`
|
|
116
|
-
3. Copy `.env.example` to `.env` and fill in your [Feishu application credentials](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app).
|
|
117
|
-
4. Run the server using `pnpm run dev`, with any flags from the [Command Line Arguments](#command-line-arguments) section.
|
|
118
|
-
|
|
119
|
-
### Run the Server Using Docker
|
|
120
|
-
|
|
121
|
-
You can use Docker to run the server, which avoids installing Node.js and other dependencies locally:
|
|
122
|
-
|
|
123
|
-
1. Build the Docker image:
|
|
124
|
-
```bash
|
|
125
|
-
docker build -t feishu-mcp .
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
2. Run the Docker container:
|
|
129
|
-
```bash
|
|
130
|
-
docker run -p 3333:3333 --env FEISHU_APP_ID=<YOUR_FEISHU_APP_ID> --env FEISHU_APP_SECRET=<YOUR_FEISHU_APP_SECRET> feishu-mcp
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Alternatively, you can use docker-compose:
|
|
134
|
-
|
|
135
|
-
1. Edit the `.env` file and add your Feishu application credentials:
|
|
136
|
-
```
|
|
137
|
-
FEISHU_APP_ID=<YOUR_FEISHU_APP_ID>
|
|
138
|
-
FEISHU_APP_SECRET=<YOUR_FEISHU_APP_SECRET>
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
2. Run docker-compose:
|
|
142
|
-
```bash
|
|
143
|
-
docker-compose up -d
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
This will start the server in the background and expose it on port 3333.
|
|
147
|
-
|
|
148
|
-
## Configuration
|
|
149
|
-
|
|
150
|
-
The server can be configured using environment variables (via the `.env` file) or command line arguments. Command line arguments take precedence over environment variables.
|
|
151
|
-
|
|
152
|
-
### Environment Variables
|
|
153
|
-
|
|
154
|
-
- `FEISHU_APP_ID`: Your [Feishu application ID](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app) (required)
|
|
155
|
-
- `FEISHU_APP_SECRET`: Your [Feishu application secret](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app) (required)
|
|
156
|
-
- `PORT`: The port to run the server on (default: 3333)
|
|
157
|
-
|
|
158
|
-
### Command Line Arguments
|
|
159
|
-
|
|
160
|
-
- `--version`: Show version number
|
|
161
|
-
- `--feishu-app-id`: Your Feishu application ID
|
|
162
|
-
- `--feishu-app-secret`: Your Feishu application secret
|
|
163
|
-
- `--port`: The port to run the server on
|
|
164
|
-
- `--stdio`: Run the server in command mode instead of the default HTTP/SSE
|
|
165
|
-
- `--help`: Show help menu
|
|
166
|
-
|
|
167
|
-
## Connecting to Cursor
|
|
168
|
-
|
|
169
|
-
### Configuring Cursor
|
|
170
|
-
|
|
171
|
-
1. Open Cursor settings
|
|
172
|
-
2. Navigate to `Settings > AI > MCP Servers`
|
|
173
|
-
3. Add a new server with the URL `http://localhost:3333` (or your configured port)
|
|
174
|
-
4. Click "Verify Connection" to ensure the connection is successful
|
|
175
|
-
|
|
176
|
-
## Usage
|
|
177
|
-
|
|
178
|
-
1. In Cursor, open the AI panel (default shortcut `Cmd+K` or `Ctrl+K`)
|
|
179
|
-
2. If you need to create a new Feishu document, you should explicitly specify a folderToken, which you can find by opening a Feishu document directory like: `https://vq5xxxxx7bc.feishu.cn/drive/folder/FPKvfjdxxxxx706RnOc`
|
|
180
|
-
3. If you need to modify Feishu document content, you should explicitly provide the Feishu document link, for example: `https://vq5ixxxx7bc.feishu.cn/docx/J6T0d6exxxxxxxDdc1zqwnph`
|
|
181
|
-
4. Ask questions about the document or request operations based on the document content
|
|
182
|
-
5. Creating and editing documents requires permissions, and you can test your account on the Feishu open platform: `https://open.feishu.cn/api-explorer/cli_a75a8ca0ac79100c?apiName=tenant_access_token_internal&from=op_doc&project=auth&resource=auth&version=v3`
|
|
183
|
-
|
|
184
|
-
## Document Permissions and Troubleshooting
|
|
185
|
-
|
|
186
|
-
### Permission Types
|
|
187
|
-
Permissions are divided into two types: robot permissions and document access permissions.
|
|
188
|
-
|
|
189
|
-
### Permission Verification and Troubleshooting
|
|
190
|
-
1. Get token: [https://open.feishu.cn/api-explorer/cli_a7582508c93ad00d?apiName=tenant_access_token_internal&project=auth&resource=auth&version=v3](https://open.feishu.cn/api-explorer/cli_a7582508c93ad00d?apiName=tenant_access_token_internal&project=auth&resource=auth&version=v3)
|
|
191
|
-
2. Using the token obtained in step 1, verify whether you have permission to access the document: [https://open.feishu.cn/api-explorer/cli_a7582508c93ad00d?apiName=get&project=docx&resource=document&version=v1](https://open.feishu.cn/api-explorer/cli_a7582508c93ad00d?apiName=get&project=docx&resource=document&version=v1)
|
|
192
|
-
|
|
193
|
-
### Troubleshooting Method
|
|
194
|
-
Test permissions normally on the Feishu development platform (when debugging on the open platform, there will be sufficient prompt information and guidance in case of failure).
|
|
195
|
-
|
|
196
|
-
### Document Authorization
|
|
197
|
-
If you encounter permission issues, please refer to [Cloud Document FAQ](https://open.feishu.cn/document/ukTMukTMukTM/uczNzUjL3czM14yN3MTN), [Knowledge Base FAQ](https://open.feishu.cn/document/server-docs/docs/wiki-v2/wiki-qa), especially focusing on how to grant document permissions to applications or users.
|
|
198
|
-
|
|
199
|
-
## License
|
|
200
|
-
|
|
201
|
-
MIT
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { Logger } from '../utils/logger.js';
|
|
2
|
-
/**
|
|
3
|
-
* SSE连接管理器 - 负责管理所有的SSE长连接和心跳机制
|
|
4
|
-
*/
|
|
5
|
-
export class SSEConnectionManager {
|
|
6
|
-
constructor() {
|
|
7
|
-
Object.defineProperty(this, "transports", {
|
|
8
|
-
enumerable: true,
|
|
9
|
-
configurable: true,
|
|
10
|
-
writable: true,
|
|
11
|
-
value: {}
|
|
12
|
-
});
|
|
13
|
-
Object.defineProperty(this, "connections", {
|
|
14
|
-
enumerable: true,
|
|
15
|
-
configurable: true,
|
|
16
|
-
writable: true,
|
|
17
|
-
value: new Map()
|
|
18
|
-
});
|
|
19
|
-
Object.defineProperty(this, "keepAliveIntervalId", {
|
|
20
|
-
enumerable: true,
|
|
21
|
-
configurable: true,
|
|
22
|
-
writable: true,
|
|
23
|
-
value: null
|
|
24
|
-
});
|
|
25
|
-
Object.defineProperty(this, "KEEP_ALIVE_INTERVAL_MS", {
|
|
26
|
-
enumerable: true,
|
|
27
|
-
configurable: true,
|
|
28
|
-
writable: true,
|
|
29
|
-
value: 1000 * 25
|
|
30
|
-
}); // 25秒心跳间隔
|
|
31
|
-
this.startGlobalKeepAlive();
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* 启动全局心跳管理
|
|
35
|
-
*/
|
|
36
|
-
startGlobalKeepAlive() {
|
|
37
|
-
if (this.keepAliveIntervalId) {
|
|
38
|
-
clearInterval(this.keepAliveIntervalId);
|
|
39
|
-
}
|
|
40
|
-
this.keepAliveIntervalId = setInterval(() => {
|
|
41
|
-
Logger.info(`[KeepAlive] Sending keepalive to ${this.connections.size} connections`);
|
|
42
|
-
for (const [sessionId, connection] of this.connections.entries()) {
|
|
43
|
-
if (!connection.res.writableEnded) {
|
|
44
|
-
connection.res.write(': keepalive\n\n');
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
// 移除已关闭的连接
|
|
48
|
-
this.removeConnection(sessionId);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}, this.KEEP_ALIVE_INTERVAL_MS);
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* 添加新的SSE连接
|
|
55
|
-
*/
|
|
56
|
-
addConnection(sessionId, transport, req, res) {
|
|
57
|
-
this.transports[sessionId] = transport;
|
|
58
|
-
this.connections.set(sessionId, { res });
|
|
59
|
-
console.info(`[SSE Connection] Client connected: ${sessionId}`);
|
|
60
|
-
req.on('close', () => {
|
|
61
|
-
this.removeConnection(sessionId);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* 移除SSE连接
|
|
66
|
-
*/
|
|
67
|
-
removeConnection(sessionId) {
|
|
68
|
-
const transport = this.transports[sessionId];
|
|
69
|
-
if (transport) {
|
|
70
|
-
try {
|
|
71
|
-
transport.close();
|
|
72
|
-
Logger.info(`[SSE Connection] Transport closed for: ${sessionId}`);
|
|
73
|
-
}
|
|
74
|
-
catch (error) {
|
|
75
|
-
Logger.error(`[SSE Connection] Error closing transport for: ${sessionId}`, error);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
delete this.transports[sessionId];
|
|
79
|
-
this.connections.delete(sessionId);
|
|
80
|
-
console.info(`[SSE Connection] Client disconnected: ${sessionId}`);
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* 获取指定sessionId的传输实例
|
|
84
|
-
*/
|
|
85
|
-
getTransport(sessionId) {
|
|
86
|
-
console.info(`[SSE Connection] Getting transport for sessionId: ${sessionId}`);
|
|
87
|
-
return this.transports[sessionId];
|
|
88
|
-
}
|
|
89
|
-
/**
|
|
90
|
-
* 关闭连接管理器
|
|
91
|
-
*/
|
|
92
|
-
shutdown() {
|
|
93
|
-
if (this.keepAliveIntervalId) {
|
|
94
|
-
clearInterval(this.keepAliveIntervalId);
|
|
95
|
-
this.keepAliveIntervalId = null;
|
|
96
|
-
}
|
|
97
|
-
// 关闭所有连接
|
|
98
|
-
Logger.info(`[SSE Connection] Shutting down all connections (${this.connections.size} active)`);
|
|
99
|
-
for (const sessionId of this.connections.keys()) {
|
|
100
|
-
this.removeConnection(sessionId);
|
|
101
|
-
}
|
|
102
|
-
Logger.info(`[SSE Connection] All connections closed`);
|
|
103
|
-
}
|
|
104
|
-
}
|
package/dist/mcp/feishuMcp.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { FeishuApiService } from '../services/feishuApiService.js';
|
|
3
|
-
import { Logger } from '../utils/logger.js';
|
|
4
|
-
import { registerFeishuTools } from './tools/feishuTools.js';
|
|
5
|
-
import { registerFeishuBlockTools } from './tools/feishuBlockTools.js';
|
|
6
|
-
import { registerFeishuFolderTools } from './tools/feishuFolderTools.js';
|
|
7
|
-
const serverInfo = {
|
|
8
|
-
name: "Feishu MCP Server",
|
|
9
|
-
version: "0.0.9-alpha",
|
|
10
|
-
};
|
|
11
|
-
const serverOptions = {
|
|
12
|
-
capabilities: { logging: {}, tools: {} },
|
|
13
|
-
};
|
|
14
|
-
/**
|
|
15
|
-
* 飞书MCP服务类
|
|
16
|
-
* 继承自McpServer,提供飞书工具注册和初始化功能
|
|
17
|
-
*/
|
|
18
|
-
export class FeishuMcp extends McpServer {
|
|
19
|
-
/**
|
|
20
|
-
* 构造函数
|
|
21
|
-
*/
|
|
22
|
-
constructor() {
|
|
23
|
-
super(serverInfo, serverOptions);
|
|
24
|
-
Object.defineProperty(this, "feishuService", {
|
|
25
|
-
enumerable: true,
|
|
26
|
-
configurable: true,
|
|
27
|
-
writable: true,
|
|
28
|
-
value: null
|
|
29
|
-
});
|
|
30
|
-
// 初始化飞书服务
|
|
31
|
-
this.initFeishuService();
|
|
32
|
-
// 注册所有工具
|
|
33
|
-
if (this.feishuService) {
|
|
34
|
-
this.registerAllTools();
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
Logger.error('无法注册飞书工具: 飞书服务初始化失败');
|
|
38
|
-
throw new Error('飞书服务初始化失败');
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* 初始化飞书API服务
|
|
43
|
-
*/
|
|
44
|
-
initFeishuService() {
|
|
45
|
-
try {
|
|
46
|
-
// 使用单例模式获取飞书服务实例
|
|
47
|
-
this.feishuService = FeishuApiService.getInstance();
|
|
48
|
-
Logger.info('飞书服务初始化成功');
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
Logger.error('飞书服务初始化失败:', error);
|
|
52
|
-
this.feishuService = null;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* 注册所有飞书MCP工具
|
|
57
|
-
*/
|
|
58
|
-
registerAllTools() {
|
|
59
|
-
if (!this.feishuService) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
// 注册所有工具
|
|
63
|
-
registerFeishuTools(this, this.feishuService);
|
|
64
|
-
registerFeishuBlockTools(this, this.feishuService);
|
|
65
|
-
registerFeishuFolderTools(this, this.feishuService);
|
|
66
|
-
}
|
|
67
|
-
}
|