feishu-mcp 0.0.13 → 0.0.15

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.
@@ -1,7 +1,9 @@
1
- import { z } from 'zod';
1
+ // import { z } from 'zod';
2
2
  import { formatErrorMessage } from '../../utils/error.js';
3
3
  import { Logger } from '../../utils/logger.js';
4
- import { DocumentIdSchema, BlockIdSchema, SearchKeySchema, } from '../../types/feishuSchema.js';
4
+ import { DocumentIdSchema,
5
+ // BlockIdSchema,
6
+ SearchKeySchema, WhiteboardIdSchema, DocumentTitleSchema, FolderTokenSchema, } from '../../types/feishuSchema.js';
5
7
  /**
6
8
  * 注册飞书相关的MCP工具
7
9
  * @param server MCP服务器实例
@@ -10,8 +12,8 @@ import { DocumentIdSchema, BlockIdSchema, SearchKeySchema, } from '../../types/f
10
12
  export function registerFeishuTools(server, feishuService) {
11
13
  // 添加创建飞书文档工具
12
14
  server.tool('create_feishu_document', 'Creates a new Feishu document and returns its information. Use this tool when you need to create a document from scratch with a specific title and folder location.', {
13
- title: z.string().describe('Document title (required). This will be displayed in the Feishu document list and document header.'),
14
- folderToken: z.string().describe('Folder token (required). Specifies where to create the document. Format is an alphanumeric string like "doxcnOu1ZKYH4RtX1Y5XwL5WGRh".'),
15
+ title: DocumentTitleSchema,
16
+ folderToken: FolderTokenSchema,
15
17
  }, async ({ title, folderToken }) => {
16
18
  try {
17
19
  Logger.info(`开始创建飞书文档,标题: ${title}${folderToken ? `,文件夹Token: ${folderToken}` : ',使用默认文件夹'}`);
@@ -58,31 +60,37 @@ export function registerFeishuTools(server, feishuService) {
58
60
  }
59
61
  });
60
62
  // 添加获取飞书文档内容工具
61
- server.tool('get_feishu_document_content', 'Retrieves the plain text content of a Feishu document. Ideal for content analysis, processing, or when you need to extract text without formatting. The content maintains the document structure but without styling. Note: For Feishu wiki links (https://xxx.feishu.cn/wiki/xxx) you must first use convert_feishu_wiki_to_document_id tool to obtain a compatible document ID.', {
62
- documentId: DocumentIdSchema,
63
- lang: z.number().optional().default(0).describe('Language code (optional). Default is 0 (Chinese). Use 1 for English if available.'),
64
- }, async ({ documentId, lang }) => {
65
- try {
66
- if (!feishuService) {
67
- return {
68
- content: [{ type: 'text', text: 'Feishu service is not initialized. Please check the configuration' }],
69
- };
70
- }
71
- Logger.info(`开始获取飞书文档内容,文档ID: ${documentId},语言: ${lang}`);
72
- const content = await feishuService.getDocumentContent(documentId, lang);
73
- Logger.info(`飞书文档内容获取成功,内容长度: ${content.length}字符`);
74
- return {
75
- content: [{ type: 'text', text: content }],
76
- };
77
- }
78
- catch (error) {
79
- Logger.error(`获取飞书文档内容失败:`, error);
80
- const errorMessage = formatErrorMessage(error);
81
- return {
82
- content: [{ type: 'text', text: `获取飞书文档内容失败: ${errorMessage}` }],
83
- };
84
- }
85
- });
63
+ // server.tool(
64
+ // 'get_feishu_document_content',
65
+ // 'Retrieves the plain text content of a Feishu document. Ideal for content analysis, processing, or when you need to extract text without formatting. The content maintains the document structure but without styling. Note: For Feishu wiki links (https://xxx.feishu.cn/wiki/xxx) you must first use convert_feishu_wiki_to_document_id tool to obtain a compatible document ID.',
66
+ // {
67
+ // documentId: DocumentIdSchema,
68
+ // lang: z.number().optional().default(0).describe('Language code (optional). Default is 0 (Chinese). Use 1 for English if available.'),
69
+ // },
70
+ // async ({ documentId, lang }) => {
71
+ // try {
72
+ // if (!feishuService) {
73
+ // return {
74
+ // content: [{ type: 'text', text: 'Feishu service is not initialized. Please check the configuration' }],
75
+ // };
76
+ // }
77
+ //
78
+ // Logger.info(`开始获取飞书文档内容,文档ID: ${documentId},语言: ${lang}`);
79
+ // const content = await feishuService.getDocumentContent(documentId, lang);
80
+ // Logger.info(`飞书文档内容获取成功,内容长度: ${content.length}字符`);
81
+ //
82
+ // return {
83
+ // content: [{ type: 'text', text: content }],
84
+ // };
85
+ // } catch (error) {
86
+ // Logger.error(`获取飞书文档内容失败:`, error);
87
+ // const errorMessage = formatErrorMessage(error);
88
+ // return {
89
+ // content: [{ type: 'text', text: `获取飞书文档内容失败: ${errorMessage}` }],
90
+ // };
91
+ // }
92
+ // },
93
+ // );
86
94
  // 添加获取飞书文档块工具
87
95
  server.tool('get_feishu_document_blocks', 'Retrieves the block structure information of a Feishu document. Essential to use before inserting content to understand document structure and determine correct insertion positions. Returns a detailed hierarchy of blocks with their IDs, types, and content. Note: For Feishu wiki links (https://xxx.feishu.cn/wiki/xxx) you must first use convert_feishu_wiki_to_document_id tool to obtain a compatible document ID.', {
88
96
  documentId: DocumentIdSchema,
@@ -96,8 +104,26 @@ export function registerFeishuTools(server, feishuService) {
96
104
  Logger.info(`开始获取飞书文档块,文档ID: ${documentId}`);
97
105
  const blocks = await feishuService.getDocumentBlocks(documentId);
98
106
  Logger.info(`飞书文档块获取成功,共 ${blocks.length} 个块`);
107
+ // 检查是否有 block_type 为 43 的块(画板块)
108
+ const whiteboardBlocks = blocks.filter((block) => block.block_type === 43);
109
+ const hasWhiteboardBlocks = whiteboardBlocks.length > 0;
110
+ let responseText = JSON.stringify(blocks, null, 2);
111
+ if (hasWhiteboardBlocks) {
112
+ responseText += '\n\n⚠️ 检测到画板块 (block_type: 43)!\n';
113
+ responseText += `发现 ${whiteboardBlocks.length} 个画板块。画板块包含丰富的图形内容,如形状、文本、思维导图等。\n`;
114
+ responseText += '建议使用 get_feishu_whiteboard_content 工具来获取画板的具体内容和结构。\n';
115
+ responseText += '画板信息:\n';
116
+ whiteboardBlocks.forEach((block, index) => {
117
+ responseText += ` ${index + 1}. 块ID: ${block.block_id}`;
118
+ if (block.board && block.board.token) {
119
+ responseText += `, 画板ID: ${block.board.token}`;
120
+ }
121
+ responseText += '\n';
122
+ });
123
+ responseText += '请使用上述画板ID调用 get_feishu_whiteboard_content 工具。';
124
+ }
99
125
  return {
100
- content: [{ type: 'text', text: JSON.stringify(blocks, null, 2) }],
126
+ content: [{ type: 'text', text: responseText }],
101
127
  };
102
128
  }
103
129
  catch (error) {
@@ -109,31 +135,37 @@ export function registerFeishuTools(server, feishuService) {
109
135
  }
110
136
  });
111
137
  // 添加获取块内容工具
112
- server.tool('get_feishu_block_content', 'Retrieves the detailed content and structure of a specific block in a Feishu document. Useful for inspecting block properties, formatting, and content, especially before making updates or for debugging purposes. Note: For Feishu wiki links (https://xxx.feishu.cn/wiki/xxx) you must first use convert_feishu_wiki_to_document_id tool to obtain a compatible document ID.', {
113
- documentId: DocumentIdSchema,
114
- blockId: BlockIdSchema,
115
- }, async ({ documentId, blockId }) => {
116
- try {
117
- if (!feishuService) {
118
- return {
119
- content: [{ type: 'text', text: '飞书服务未初始化,请检查配置' }],
120
- };
121
- }
122
- Logger.info(`开始获取飞书块内容,文档ID: ${documentId},块ID: ${blockId}`);
123
- const blockContent = await feishuService.getBlockContent(documentId, blockId);
124
- Logger.info(`飞书块内容获取成功,块类型: ${blockContent.block_type}`);
125
- return {
126
- content: [{ type: 'text', text: JSON.stringify(blockContent, null, 2) }],
127
- };
128
- }
129
- catch (error) {
130
- Logger.error(`获取飞书块内容失败:`, error);
131
- const errorMessage = formatErrorMessage(error);
132
- return {
133
- content: [{ type: 'text', text: `获取飞书块内容失败: ${errorMessage}` }],
134
- };
135
- }
136
- });
138
+ // server.tool(
139
+ // 'get_feishu_block_content',
140
+ // 'Retrieves the detailed content and structure of a specific block in a Feishu document. Useful for inspecting block properties, formatting, and content, especially before making updates or for debugging purposes. Note: For Feishu wiki links (https://xxx.feishu.cn/wiki/xxx) you must first use convert_feishu_wiki_to_document_id tool to obtain a compatible document ID.',
141
+ // {
142
+ // documentId: DocumentIdSchema,
143
+ // blockId: BlockIdSchema,
144
+ // },
145
+ // async ({ documentId, blockId }) => {
146
+ // try {
147
+ // if (!feishuService) {
148
+ // return {
149
+ // content: [{ type: 'text', text: '飞书服务未初始化,请检查配置' }],
150
+ // };
151
+ // }
152
+ //
153
+ // Logger.info(`开始获取飞书块内容,文档ID: ${documentId},块ID: ${blockId}`);
154
+ // const blockContent = await feishuService.getBlockContent(documentId, blockId);
155
+ // Logger.info(`飞书块内容获取成功,块类型: ${blockContent.block_type}`);
156
+ //
157
+ // return {
158
+ // content: [{ type: 'text', text: JSON.stringify(blockContent, null, 2) }],
159
+ // };
160
+ // } catch (error) {
161
+ // Logger.error(`获取飞书块内容失败:`, error);
162
+ // const errorMessage = formatErrorMessage(error);
163
+ // return {
164
+ // content: [{ type: 'text', text: `获取飞书块内容失败: ${errorMessage}` }],
165
+ // };
166
+ // }
167
+ // },
168
+ // );
137
169
  // 添加搜索文档工具
138
170
  server.tool('search_feishu_documents', 'Searches for documents in Feishu. Supports keyword-based search and returns document information including title, type, and owner. Use this tool to find specific content or related documents in your document library.', {
139
171
  searchKey: SearchKeySchema,
@@ -163,4 +195,29 @@ export function registerFeishuTools(server, feishuService) {
163
195
  };
164
196
  }
165
197
  });
198
+ // 添加获取画板内容工具
199
+ server.tool('get_feishu_whiteboard_content', 'Retrieves the content and structure of a Feishu whiteboard. This tool fetches all nodes (elements) from a whiteboard, including shapes, text, mind maps, and other graphical elements. Use this to analyze whiteboard content, extract information, or understand the structure of collaborative diagrams. The whiteboard ID can be obtained from the board.token field when getting document blocks with block_type: 43.', {
200
+ whiteboardId: WhiteboardIdSchema,
201
+ }, async ({ whiteboardId }) => {
202
+ try {
203
+ if (!feishuService) {
204
+ return {
205
+ content: [{ type: 'text', text: 'Feishu service is not initialized. Please check the configuration' }],
206
+ };
207
+ }
208
+ Logger.info(`开始获取飞书画板内容,画板ID: ${whiteboardId}`);
209
+ const whiteboardContent = await feishuService.getWhiteboardContent(whiteboardId);
210
+ Logger.info(`飞书画板内容获取成功,节点数量: ${whiteboardContent.nodes?.length || 0}`);
211
+ return {
212
+ content: [{ type: 'text', text: JSON.stringify(whiteboardContent, null, 2) }],
213
+ };
214
+ }
215
+ catch (error) {
216
+ Logger.error(`获取飞书画板内容失败:`, error);
217
+ const errorMessage = formatErrorMessage(error);
218
+ return {
219
+ content: [{ type: 'text', text: `获取飞书画板内容失败: ${errorMessage}` }],
220
+ };
221
+ }
222
+ });
166
223
  }
@@ -90,14 +90,29 @@ export class BlockFactory {
90
90
  return {
91
91
  block_type: 2, // 2表示文本块
92
92
  text: {
93
- elements: textContents.map(content => ({
94
- text_run: {
95
- content: content.text,
96
- text_element_style: BlockFactory.applyDefaultTextStyle(content.style)
93
+ elements: textContents.map(content => {
94
+ // 检查是否是公式元素
95
+ if ('equation' in content) {
96
+ return {
97
+ equation: {
98
+ content: content.equation,
99
+ text_element_style: BlockFactory.applyDefaultTextStyle(content.style)
100
+ }
101
+ };
102
+ }
103
+ else {
104
+ // 普通文本元素
105
+ return {
106
+ text_run: {
107
+ content: content.text,
108
+ text_element_style: BlockFactory.applyDefaultTextStyle(content.style)
109
+ }
110
+ };
97
111
  }
98
- })),
112
+ }),
99
113
  style: {
100
114
  align: align, // 1 居左,2 居中,3 居右
115
+ folded: false
101
116
  }
102
117
  }
103
118
  };
@@ -221,7 +221,7 @@ export class FeishuApiService extends BaseApiService {
221
221
  * 更新块文本内容
222
222
  * @param documentId 文档ID或URL
223
223
  * @param blockId 块ID
224
- * @param textElements 文本元素数组
224
+ * @param textElements 文本元素数组,支持普通文本和公式元素
225
225
  * @returns 更新结果
226
226
  */
227
227
  async updateBlockTextContent(documentId, blockId, textElements) {
@@ -229,12 +229,24 @@ export class FeishuApiService extends BaseApiService {
229
229
  const docId = ParamUtils.processDocumentId(documentId);
230
230
  const endpoint = `/docx/v1/documents/${docId}/blocks/${blockId}?document_revision_id=-1`;
231
231
  Logger.debug(`准备请求API端点: ${endpoint}`);
232
- const elements = textElements.map(item => ({
233
- text_run: {
234
- content: item.text,
235
- text_element_style: BlockFactory.applyDefaultTextStyle(item.style)
232
+ const elements = textElements.map(item => {
233
+ if (item.equation !== undefined) {
234
+ return {
235
+ equation: {
236
+ content: item.equation,
237
+ text_element_style: BlockFactory.applyDefaultTextStyle(item.style)
238
+ }
239
+ };
240
+ }
241
+ else {
242
+ return {
243
+ text_run: {
244
+ content: item.text || '',
245
+ text_element_style: BlockFactory.applyDefaultTextStyle(item.style)
246
+ }
247
+ };
236
248
  }
237
- }));
249
+ });
238
250
  const data = {
239
251
  update_text_elements: {
240
252
  elements: elements
@@ -305,17 +317,27 @@ export class FeishuApiService extends BaseApiService {
305
317
  * 创建文本块
306
318
  * @param documentId 文档ID或URL
307
319
  * @param parentBlockId 父块ID
308
- * @param textContents 文本内容数组
320
+ * @param textContents 文本内容数组,支持普通文本和公式元素
309
321
  * @param align 对齐方式,1为左对齐,2为居中,3为右对齐
310
322
  * @param index 插入位置索引
311
323
  * @returns 创建结果
312
324
  */
313
325
  async createTextBlock(documentId, parentBlockId, textContents, align = 1, index = 0) {
314
- // 处理文本内容样式
315
- const processedTextContents = textContents.map(item => ({
316
- text: item.text,
317
- style: BlockFactory.applyDefaultTextStyle(item.style)
318
- }));
326
+ // 处理文本内容样式,支持普通文本和公式元素
327
+ const processedTextContents = textContents.map(item => {
328
+ if (item.equation !== undefined) {
329
+ return {
330
+ equation: item.equation,
331
+ style: BlockFactory.applyDefaultTextStyle(item.style)
332
+ };
333
+ }
334
+ else {
335
+ return {
336
+ text: item.text || '',
337
+ style: BlockFactory.applyDefaultTextStyle(item.style)
338
+ };
339
+ }
340
+ });
319
341
  const blockContent = this.blockFactory.createTextBlock({
320
342
  textContents: processedTextContents,
321
343
  align
@@ -501,12 +523,22 @@ export class FeishuApiService extends BaseApiService {
501
523
  case BlockType.TEXT:
502
524
  if ('text' in options && options.text) {
503
525
  const textOptions = options.text;
504
- // 处理文本样式,应用默认样式
526
+ // 处理文本样式,应用默认样式,支持普通文本和公式元素
505
527
  const textStyles = textOptions.textStyles || [];
506
- const processedTextStyles = textStyles.map((item) => ({
507
- text: item.text,
508
- style: BlockFactory.applyDefaultTextStyle(item.style)
509
- }));
528
+ const processedTextStyles = textStyles.map((item) => {
529
+ if (item.equation !== undefined) {
530
+ return {
531
+ equation: item.equation,
532
+ style: BlockFactory.applyDefaultTextStyle(item.style)
533
+ };
534
+ }
535
+ else {
536
+ return {
537
+ text: item.text || '',
538
+ style: BlockFactory.applyDefaultTextStyle(item.style)
539
+ };
540
+ }
541
+ });
510
542
  blockConfig.options = {
511
543
  textContents: processedTextStyles,
512
544
  align: textOptions.align || 1
@@ -566,12 +598,22 @@ export class FeishuApiService extends BaseApiService {
566
598
  if ('text' in options) {
567
599
  blockConfig.type = BlockType.TEXT;
568
600
  const textOptions = options.text;
569
- // 处理文本样式,应用默认样式
601
+ // 处理文本样式,应用默认样式,支持普通文本和公式元素
570
602
  const textStyles = textOptions.textStyles || [];
571
- const processedTextStyles = textStyles.map((item) => ({
572
- text: item.text,
573
- style: BlockFactory.applyDefaultTextStyle(item.style)
574
- }));
603
+ const processedTextStyles = textStyles.map((item) => {
604
+ if (item.equation !== undefined) {
605
+ return {
606
+ equation: item.equation,
607
+ style: BlockFactory.applyDefaultTextStyle(item.style)
608
+ };
609
+ }
610
+ else {
611
+ return {
612
+ text: item.text || '',
613
+ style: BlockFactory.applyDefaultTextStyle(item.style)
614
+ };
615
+ }
616
+ });
575
617
  blockConfig.options = {
576
618
  textContents: processedTextStyles,
577
619
  align: textOptions.align || 1
@@ -922,6 +964,32 @@ export class FeishuApiService extends BaseApiService {
922
964
  return 'image/png'; // 默认PNG
923
965
  }
924
966
  }
967
+ /**
968
+ * 获取画板内容
969
+ * @param whiteboardId 画板ID或URL
970
+ * @returns 画板节点数据
971
+ */
972
+ async getWhiteboardContent(whiteboardId) {
973
+ try {
974
+ // 从URL中提取画板ID
975
+ let normalizedWhiteboardId = whiteboardId;
976
+ if (whiteboardId.includes('feishu.cn/board/')) {
977
+ // 从URL中提取画板ID
978
+ const matches = whiteboardId.match(/board\/([^\/\?]+)/);
979
+ if (matches) {
980
+ normalizedWhiteboardId = matches[1];
981
+ }
982
+ }
983
+ const endpoint = `/board/v1/whiteboards/${normalizedWhiteboardId}/nodes`;
984
+ Logger.info(`开始获取画板内容,画板ID: ${normalizedWhiteboardId}`);
985
+ const response = await this.get(endpoint);
986
+ Logger.info(`画板内容获取成功,节点数量: ${response.nodes?.length || 0}`);
987
+ return response;
988
+ }
989
+ catch (error) {
990
+ this.handleApiError(error, '获取画板内容失败');
991
+ }
992
+ }
925
993
  /**
926
994
  * 从路径或URL获取图片的Base64编码
927
995
  * @param imagePathOrUrl 图片路径或URL
@@ -16,6 +16,7 @@ export const IndexSchema = z.number().describe('Insertion position index (requir
16
16
  '0 means to insert as the first content block after the title.\n' +
17
17
  'If children is empty or missing, use 0 to insert the first content block.\n' +
18
18
  'For nested blocks, index is relative to the parent block\'s children.\n' +
19
+ '**index must satisfy 0 ≤ index ≤ parentBlock.children.length, otherwise the API will return an error.**\n' +
19
20
  'Note: The title block itself is not part of the children array and cannot be operated on with index.' +
20
21
  'Specifies where the block should be inserted. Use 0 to insert at the beginning. ' +
21
22
  'Use get_feishu_document_blocks tool to understand document structure if unsure. ' +
@@ -53,11 +54,17 @@ export const TextStylePropertiesSchema = {
53
54
  };
54
55
  // 文本样式对象定义
55
56
  export const TextStyleSchema = z.object(TextStylePropertiesSchema).optional().describe('Text style settings. Explicitly set style properties instead of relying on Markdown syntax conversion.');
56
- // 文本内容单元定义
57
- export const TextElementSchema = z.object({
58
- text: z.string().describe('Text content. Provide plain text without markdown syntax; use style object for formatting.'),
59
- style: TextStyleSchema
60
- });
57
+ // 文本内容单元定义 - 支持普通文本和公式元素
58
+ export const TextElementSchema = z.union([
59
+ z.object({
60
+ text: z.string().describe('Text content. Provide plain text without markdown syntax; use style object for formatting.'),
61
+ style: TextStyleSchema
62
+ }).describe('Regular text element with optional styling.'),
63
+ z.object({
64
+ equation: z.string().describe('Mathematical equation content. The formula or expression to display. Format: LaTeX.'),
65
+ style: TextStyleSchema
66
+ }).describe('Mathematical equation element with optional styling.')
67
+ ]);
61
68
  // 文本内容数组定义
62
69
  export const TextElementsArraySchema = z.array(TextElementSchema).describe('Array of text content objects. A block can contain multiple text segments with different styles. Example: [{text:"Hello",style:{bold:true}},{text:" World",style:{italic:true}}]');
63
70
  // 代码块语言参数定义
@@ -74,10 +81,7 @@ export const CodeLanguageSchema = z.number().optional().default(1).describe("Pro
74
81
  export const CodeWrapSchema = z.boolean().optional().default(false).describe('Whether to enable automatic line wrapping. Default is false.');
75
82
  // 文本样式段落定义 - 用于批量创建块工具
76
83
  export const TextStyleBlockSchema = z.object({
77
- textStyles: z.array(z.object({
78
- text: z.string().describe('Text segment content. The actual text to display.'),
79
- style: TextStyleSchema
80
- })).describe('Array of text content objects with styles. A block can contain multiple text segments with different styles. Example: [{text:"Hello",style:{bold:true}},{text:" World",style:{italic:true}}]'),
84
+ textStyles: z.array(TextElementSchema).describe('Array of text content objects with styles. A block can contain multiple text segments with different styles, including both regular text and equations. Example: [{text:"Hello",style:{bold:true}},{equation:"1+2=3",style:{}}]'),
81
85
  align: z.number().optional().default(1).describe('Text alignment: 1 for left (default), 2 for center, 3 for right.'),
82
86
  });
83
87
  // 代码块内容定义 - 用于批量创建块工具
@@ -101,11 +105,16 @@ export const ListBlockSchema = z.object({
101
105
  // 块类型枚举 - 用于批量创建块工具
102
106
  export const BlockTypeEnum = z.string().describe("Block type (required). Supports: 'text', 'code', 'heading', 'list', 'image', as well as 'heading1' through 'heading9'. " +
103
107
  "For headings, we recommend using 'heading' with level property, but 'heading1'-'heading9' are also supported. " +
104
- "For images, use 'image' to create empty image blocks that can be filled later.");
108
+ "For images, use 'image' to create empty image blocks that can be filled later. " +
109
+ "For text blocks, you can include both regular text and equation elements in the same block.");
110
+ // 图片宽度参数定义
111
+ export const ImageWidthSchema = z.number().optional().describe('Image width in pixels (optional). If not provided, the original image width will be used.');
112
+ // 图片高度参数定义
113
+ export const ImageHeightSchema = z.number().optional().describe('Image height in pixels (optional). If not provided, the original image height will be used.');
105
114
  // 图片块内容定义 - 用于批量创建块工具
106
115
  export const ImageBlockSchema = z.object({
107
- width: z.number().optional().describe('Image width in pixels (optional). If not provided, default width will be used.'),
108
- height: z.number().optional().describe('Image height in pixels (optional). If not provided, default height will be used.'),
116
+ width: ImageWidthSchema,
117
+ height: ImageHeightSchema
109
118
  });
110
119
  // 块配置定义 - 用于批量创建块工具
111
120
  export const BlockConfigSchema = z.object({
@@ -141,7 +150,15 @@ export const ImagePathOrUrlSchema = z.string().describe('Image path or URL (requ
141
150
  // 图片文件名参数定义
142
151
  export const ImageFileNameSchema = z.string().optional().describe('Image file name (optional). If not provided, a default name will be generated based on the source. ' +
143
152
  'Should include the file extension, e.g., "image.png" or "photo.jpg".');
144
- // 图片宽度参数定义
145
- export const ImageWidthSchema = z.number().optional().describe('Image width in pixels (optional). If not provided, the original image width will be used.');
146
- // 图片高度参数定义
147
- export const ImageHeightSchema = z.number().optional().describe('Image height in pixels (optional). If not provided, the original image height will be used.');
153
+ // 批量图片上传绑定参数定义
154
+ export const ImagesArraySchema = z.array(z.object({
155
+ blockId: BlockIdSchema,
156
+ imagePathOrUrl: ImagePathOrUrlSchema,
157
+ fileName: ImageFileNameSchema.optional(),
158
+ })).describe('Array of image binding objects (required). Each object must include: blockId (target image block ID), imagePathOrUrl (local path or URL of the image), and optionally fileName (image file name, e.g., "image.png").');
159
+ // 画板ID参数定义
160
+ export const WhiteboardIdSchema = z.string().describe('Whiteboard ID (required). This is the token value from the board.token field when getting document blocks.\n' +
161
+ 'When you find a block with block_type: 43, the whiteboard ID is located in board.token field.\n' +
162
+ 'Example: "EPJKwvY5ghe3pVbKj9RcT2msnBX"');
163
+ // 文档标题参数定义
164
+ export const DocumentTitleSchema = z.string().describe('Document title (required). This will be displayed in the Feishu document list and document header.');
package/package.json CHANGED
@@ -1,75 +1,75 @@
1
- {
2
- "name": "feishu-mcp",
3
- "version": "0.0.13",
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.13.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
- "form-data": "^4.0.3",
51
- "remeda": "^2.20.1",
52
- "yargs": "^17.7.2",
53
- "zod": "^3.24.2"
54
- },
55
- "devDependencies": {
56
- "@types/express": "^5.0.0",
57
- "@types/jest": "^29.5.11",
58
- "@types/node": "^20.17.0",
59
- "@typescript-eslint/eslint-plugin": "^8.24.0",
60
- "@typescript-eslint/parser": "^8.24.0",
61
- "eslint": "^9.20.1",
62
- "eslint-config-prettier": "^10.0.1",
63
- "jest": "^29.7.0",
64
- "prettier": "^3.5.0",
65
- "ts-jest": "^29.2.5",
66
- "tsc-alias": "^1.8.10",
67
- "tsx": "^4.19.2",
68
- "typescript": "^5.7.3"
69
- },
70
- "pnpm": {
71
- "overrides": {
72
- "feishu-mcp": "link:"
73
- }
74
- }
75
- }
1
+ {
2
+ "name": "feishu-mcp",
3
+ "version": "0.0.15",
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.13.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
+ "form-data": "^4.0.3",
51
+ "remeda": "^2.20.1",
52
+ "yargs": "^17.7.2",
53
+ "zod": "^3.24.2"
54
+ },
55
+ "devDependencies": {
56
+ "@types/express": "^5.0.0",
57
+ "@types/jest": "^29.5.11",
58
+ "@types/node": "^20.17.0",
59
+ "@typescript-eslint/eslint-plugin": "^8.24.0",
60
+ "@typescript-eslint/parser": "^8.24.0",
61
+ "eslint": "^9.20.1",
62
+ "eslint-config-prettier": "^10.0.1",
63
+ "jest": "^29.7.0",
64
+ "prettier": "^3.5.0",
65
+ "ts-jest": "^29.2.5",
66
+ "tsc-alias": "^1.8.10",
67
+ "tsx": "^4.19.2",
68
+ "typescript": "^5.7.3"
69
+ },
70
+ "pnpm": {
71
+ "overrides": {
72
+ "feishu-mcp": "link:"
73
+ }
74
+ }
75
+ }