feishu-mcp 0.0.8 → 0.0.9-alpha.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.
@@ -70,6 +70,7 @@ export class FeishuService {
70
70
  throw {
71
71
  status: response.status,
72
72
  err: response.data.msg || "Unknown error",
73
+ apiError: response.data
73
74
  };
74
75
  }
75
76
  this.accessToken = response.data.tenant_access_token;
@@ -86,6 +87,7 @@ export class FeishuService {
86
87
  throw {
87
88
  status: error.response.status,
88
89
  err: error.response.data?.msg || "Unknown error",
90
+ apiError: error.response.data
89
91
  };
90
92
  }
91
93
  Logger.error('获取访问令牌时发生未知错误:', error);
@@ -128,6 +130,7 @@ export class FeishuService {
128
130
  throw {
129
131
  status: error.response.status,
130
132
  err: error.response.data?.msg || "Unknown error",
133
+ apiError: error.response.data
131
134
  };
132
135
  }
133
136
  Logger.error('发送请求时发生未知错误:', error);
@@ -25,13 +25,28 @@ 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 && this.config.enabled) {
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
+ }
35
50
  /**
36
51
  * 格式化日志消息
37
52
  * @param level 日志级别
@@ -59,7 +74,7 @@ export class Logger {
59
74
  * @param logParts 日志内容部分
60
75
  */
61
76
  static writeToFile(logParts) {
62
- if (!this.config.logToFile)
77
+ if (!this.config.enabled || !this.config.logToFile)
63
78
  return;
64
79
  try {
65
80
  // 将日志内容转换为字符串
@@ -143,7 +158,7 @@ export class Logger {
143
158
  * @param args 日志参数
144
159
  */
145
160
  static debug(...args) {
146
- if (this.config.minLevel <= LogLevel.DEBUG) {
161
+ if (this.canLog(LogLevel.DEBUG)) {
147
162
  const formattedMessage = this.formatLogMessage(LogLevel.DEBUG, args);
148
163
  console.debug(...formattedMessage);
149
164
  this.writeToFile(formattedMessage);
@@ -154,7 +169,7 @@ export class Logger {
154
169
  * @param args 日志参数
155
170
  */
156
171
  static info(...args) {
157
- if (this.config.minLevel <= LogLevel.INFO) {
172
+ if (this.canLog(LogLevel.INFO)) {
158
173
  const formattedMessage = this.formatLogMessage(LogLevel.INFO, args);
159
174
  console.info(...formattedMessage);
160
175
  this.writeToFile(formattedMessage);
@@ -165,7 +180,7 @@ export class Logger {
165
180
  * @param args 日志参数
166
181
  */
167
182
  static log(...args) {
168
- if (this.config.minLevel <= LogLevel.LOG) {
183
+ if (this.canLog(LogLevel.LOG)) {
169
184
  const formattedMessage = this.formatLogMessage(LogLevel.LOG, args);
170
185
  console.log(...formattedMessage);
171
186
  this.writeToFile(formattedMessage);
@@ -176,7 +191,7 @@ export class Logger {
176
191
  * @param args 日志参数
177
192
  */
178
193
  static warn(...args) {
179
- if (this.config.minLevel <= LogLevel.WARN) {
194
+ if (this.canLog(LogLevel.WARN)) {
180
195
  const formattedMessage = this.formatLogMessage(LogLevel.WARN, args);
181
196
  console.warn(...formattedMessage);
182
197
  this.writeToFile(formattedMessage);
@@ -187,7 +202,7 @@ export class Logger {
187
202
  * @param args 日志参数
188
203
  */
189
204
  static error(...args) {
190
- if (this.config.minLevel <= LogLevel.ERROR) {
205
+ if (this.canLog(LogLevel.ERROR)) {
191
206
  const formattedMessage = this.formatLogMessage(LogLevel.ERROR, args);
192
207
  console.error(...formattedMessage);
193
208
  this.writeToFile(formattedMessage);
@@ -202,7 +217,7 @@ export class Logger {
202
217
  * @param statusCode 响应状态码
203
218
  */
204
219
  static logApiCall(method, url, data, response, statusCode) {
205
- if (this.config.minLevel <= LogLevel.DEBUG) {
220
+ if (this.canLog(LogLevel.DEBUG)) {
206
221
  this.debug('API调用详情:');
207
222
  this.debug(`请求: ${method} ${url}`);
208
223
  // 简化请求数据记录
@@ -235,7 +250,7 @@ export class Logger {
235
250
  this.debug('响应数据: None');
236
251
  }
237
252
  }
238
- else {
253
+ else if (this.canLog(LogLevel.INFO)) {
239
254
  this.info(`API调用: ${method} ${url} - 状态码: ${statusCode}`);
240
255
  }
241
256
  }
@@ -245,6 +260,7 @@ Object.defineProperty(Logger, "config", {
245
260
  configurable: true,
246
261
  writable: true,
247
262
  value: {
263
+ enabled: true, // 默认开启日志
248
264
  minLevel: LogLevel.DEBUG, // 修改为DEBUG级别,确保捕获所有日志
249
265
  showTimestamp: true,
250
266
  showLevel: true,
package/package.json CHANGED
@@ -1,74 +1,74 @@
1
- {
2
- "name": "feishu-mcp",
3
- "version": "0.0.8",
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.9-alpha.1",
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,179 +0,0 @@
1
- /**
2
- * @deprecated 这个文件已被弃用,所有功能已迁移到BlockFactory类。
3
- * 请使用BlockFactory创建各种块内容。
4
- * 所有接口定义已迁移到blockFactory.ts文件。
5
- * 此文件仅保留为历史兼容性目的,将在后续版本中移除。
6
- */
7
- /**
8
- * 构建批量创建块的请求数据
9
- * @param blocks 块内容数组
10
- * @param index 插入位置索引
11
- * @returns 请求数据对象
12
- * @deprecated 请使用BlockFactory.buildCreateBlocksRequest
13
- */
14
- export function buildCreateBlocksRequest(blocks, index = 0) {
15
- return {
16
- children: blocks,
17
- index
18
- };
19
- }
20
- /**
21
- * 创建文本块内容
22
- * @param align 对齐方式:1左对齐,2居中,3右对齐
23
- * @returns 文本块内容对象
24
- * @deprecated 请使用BlockFactory.createTextBlock
25
- */
26
- export function createTextBlockContent(textContents, align = 1) {
27
- return {
28
- block_type: 2, // 2表示文本块
29
- text: {
30
- elements: textContents.map(content => ({
31
- text_run: {
32
- content: content.text,
33
- text_element_style: content.style || {}
34
- }
35
- })),
36
- style: {
37
- align: align // 1 居左,2 居中,3 居右
38
- }
39
- }
40
- };
41
- }
42
- /**
43
- * 创建代码块内容
44
- * @param code 代码内容
45
- * @param language 语言类型代码
46
- * @param wrap 是否自动换行
47
- * @returns 代码块内容对象
48
- * @deprecated 请使用BlockFactory.createCodeBlock
49
- */
50
- export function createCodeBlockContent(code, language = 0, wrap = false) {
51
- return {
52
- block_type: 14, // 14表示代码块
53
- code: {
54
- elements: [
55
- {
56
- text_run: {
57
- content: code,
58
- text_element_style: {
59
- bold: false,
60
- inline_code: false,
61
- italic: false,
62
- strikethrough: false,
63
- underline: false
64
- }
65
- }
66
- }
67
- ],
68
- style: {
69
- language: language,
70
- wrap: wrap
71
- }
72
- }
73
- };
74
- }
75
- /**
76
- * 创建标题块内容
77
- * @param text 标题文本
78
- * @param level 标题级别(1-9)
79
- * @param align 对齐方式:1左对齐,2居中,3右对齐
80
- * @returns 标题块内容对象
81
- * @deprecated 请使用BlockFactory.createHeadingBlock
82
- */
83
- export function createHeadingBlockContent(text, level = 1, align = 1) {
84
- // 确保标题级别在有效范围内(1-9)
85
- const safeLevel = Math.max(1, Math.min(9, level));
86
- // 根据标题级别设置block_type和对应的属性名
87
- // 飞书API中,一级标题的block_type为3,二级标题为4,以此类推
88
- const blockType = 2 + safeLevel; // 一级标题为3,二级标题为4,以此类推
89
- const headingKey = `heading${safeLevel}`; // heading1, heading2, ...
90
- // 构建块内容
91
- const blockContent = {
92
- block_type: blockType
93
- };
94
- // 设置对应级别的标题属性
95
- blockContent[headingKey] = {
96
- elements: [
97
- {
98
- text_run: {
99
- content: text,
100
- text_element_style: {}
101
- }
102
- }
103
- ],
104
- style: {
105
- align: align,
106
- folded: false
107
- }
108
- };
109
- return blockContent;
110
- }
111
- /**
112
- * 创建列表块内容(有序或无序)
113
- * @param text 列表项文本
114
- * @param isOrdered 是否为有序列表
115
- * @param align 对齐方式:1左对齐,2居中,3右对齐
116
- * @returns 列表块内容对象
117
- * @deprecated 请使用BlockFactory.createListBlock
118
- */
119
- export function createListBlockContent(text, isOrdered = false, align = 1) {
120
- // 确保 align 值在合法范围内(1-3)
121
- const safeAlign = (align === 1 || align === 2 || align === 3) ? align : 1;
122
- // 有序列表是 block_type: 13,无序列表是 block_type: 12
123
- const blockType = isOrdered ? 13 : 12;
124
- const propertyKey = isOrdered ? "ordered" : "bullet";
125
- // 构建块内容
126
- const blockContent = {
127
- block_type: blockType
128
- };
129
- // 设置列表属性
130
- blockContent[propertyKey] = {
131
- elements: [
132
- {
133
- text_run: {
134
- content: text,
135
- text_element_style: {}
136
- }
137
- }
138
- ],
139
- style: {
140
- align: safeAlign,
141
- folded: false
142
- }
143
- };
144
- return blockContent;
145
- }
146
- /**
147
- * 处理Markdown语法转换
148
- * @param textContents 文本内容数组
149
- * @returns 处理后的文本内容数组
150
- * @deprecated 应当避免使用Markdown语法,请直接使用TextElementStyle设置样式
151
- */
152
- export function processMarkdownSyntax(textContents) {
153
- return textContents.map(content => {
154
- let { text, style = {} } = content;
155
- // 创建一个新的style对象,避免修改原始对象
156
- const newStyle = { ...style };
157
- // 处理粗体 **text**
158
- if (text.match(/\*\*([^*]+)\*\*/g)) {
159
- text = text.replace(/\*\*([^*]+)\*\*/g, "$1");
160
- newStyle.bold = true;
161
- }
162
- // 处理斜体 *text*
163
- if (text.match(/(?<!\*)\*([^*]+)\*(?!\*)/g)) {
164
- text = text.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, "$1");
165
- newStyle.italic = true;
166
- }
167
- // 处理删除线 ~~text~~
168
- if (text.match(/~~([^~]+)~~/g)) {
169
- text = text.replace(/~~([^~]+)~~/g, "$1");
170
- newStyle.strikethrough = true;
171
- }
172
- // 处理行内代码 `code`
173
- if (text.match(/`([^`]+)`/g)) {
174
- text = text.replace(/`([^`]+)`/g, "$1");
175
- newStyle.inline_code = true;
176
- }
177
- return { text, style: newStyle };
178
- });
179
- }