feishu-mcp 0.0.12 → 0.0.14

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 CHANGED
@@ -1,90 +1,191 @@
1
1
  # 飞书 MCP 服务器
2
2
 
3
- 为 [Cursor](https://cursor.sh/)、[Windsurf](https://codeium.com/windsurf)、[Cline](https://cline.bot/) 和其他 AI 驱动的编码工具提供访问飞书文档的能力,基于 [Model Context Protocol](https://modelcontextprotocol.io/introduction) 服务器实现。
4
-
5
- 当 Cursor 能够访问飞书文档数据时,它可以更准确地理解和处理文档内容,比其他方法(如复制粘贴文本)更加高效。
6
-
7
- ## 核心功能
8
-
9
- ### 文档管理
10
- - **创建飞书文档**:支持在指定文件夹中创建新的飞书文档
11
-
12
- ### 文档内容操作
13
- - **获取文档信息**:
14
- - 获取文档基本信息(标题、版本等)
15
- - 获取文档区块结构和层级
16
- - 获取特定区块的详细内容
17
- - **获取文档纯文本内容**:支持提取文档的完整纯文本内容,便于分析和处理
18
- - **编辑文档内容**:
19
- - **文本块操作**:
20
- - 创建和更新带有丰富样式的文本块(粗体、斜体、下划线、删除线、行内代码)
21
- - 支持文本颜色设置(灰色、棕色、橙色、黄色、绿色、蓝色、紫色)
22
- - 支持文本对齐方式调整(左对齐、居中、右对齐)
23
- - **标题块操作**:创建从一级到九级的不同级别标题
24
- - **代码块操作**:
25
- - 创建多种编程语言的代码块
26
- - 支持代码语法高亮
27
- - 支持自动换行设置
28
- - **列表操作**:
29
- - 创建有序列表(编号列表)
30
- - 创建无序列表(项目符号列表)
31
- - **批量内容创建**:支持在单次操作中创建多个不同类型的内容块
32
-
33
- ### 计划中的功能
34
- - **高级内容插入**:
35
- - 表格插入:支持行列结构化数据
36
- - 插入图表:支持各类数据可视化图表
37
- - 插入流程图:支持流程图和思维导图
38
- - 插入公式:支持数学公式和科学符号
39
- - 图表、流程图的内容识别和解析
40
-
41
- 快速开始,详见[配置](#配置)部分:
42
-
43
- ```bash
44
- npx feishu-mcp --feishu-app-id=<你的飞书应用ID> --feishu-app-secret=<你的飞书应用密钥>
45
- ```
46
3
 
47
- ## 工作原理
4
+ [![npm version](https://img.shields.io/npm/v/feishu-mcp?color=blue&label=npm)](https://www.npmjs.com/package/feishu-mcp)
5
+ [![smithery badge](https://smithery.ai/badge/@cso1z/feishu-mcp)](https://smithery.ai/server/@cso1z/feishu-mcp)
6
+ [![wechat](https://img.shields.io/badge/交流群-wechat-brightgreen?logo=wechat)](#group-qr)
7
+ [![MIT License](https://img.shields.io/badge/license-MIT-green)](./LICENSE)
48
8
 
49
- 1. Cursor Agent 模式下打开编辑器。
50
- 2. 粘贴飞书文档的链接。
51
- 3. 要求 Cursor 基于飞书文档执行操作——例如,分析文档内容或创建相关代码。
52
- 4. Cursor 将从飞书获取相关元数据并使用它来辅助编写代码。
9
+ 为 [Cursor](https://cursor.sh/)、[Windsurf](https://codeium.com/windsurf)、[Cline](https://cline.bot/) 和其他 AI 驱动的编码工具提供访问飞书文档的能力,基于 [Model Context Protocol](https://modelcontextprotocol.io/introduction) 服务器实现。
53
10
 
54
- 这个 MCP 服务器专为 Cursor 设计。在响应来自[飞书 API](https://open.feishu.cn/document/home/introduction-to-lark-open-platform/overview) 的内容之前,它会简化和转换响应,确保只向模型提供最相关的文档信息。
55
- ## 安装
11
+ 本项目让 AI 编码工具能够直接获取和理解飞书文档的结构化内容,显著提升文档处理的智能化和效率。
12
+
13
+ **完整覆盖飞书文档的真实使用流程,助你高效利用文档资源:**
14
+ 1. **文件夹目录获取**:快速获取和浏览飞书文档文件夹下的所有文档,便于整体管理和查找。
15
+ 2. **内容获取与理解**:支持结构化、分块、富文本等多维度内容读取,AI 能精准理解文档上下文。
16
+ 3. **智能创建与编辑**:可自动创建新文档、批量生成和编辑内容,满足多样化写作需求。
17
+ 4. **高效检索与搜索**:内置关键字搜索,帮助你在大量文档中迅速找到目标信息。
18
+
19
+ 本项目让你在飞书文档的日常使用流程中实现智能获取、编辑和搜索,提升内容处理效率和体验。
20
+
21
+ > ⭐ **Star 本项目,第一时间获取最新功能和重要更新!** 关注项目可以让你不错过任何新特性、修复和优化,助你持续高效使用。你的支持也将帮助我们更好地完善和发展项目。⭐
22
+
23
+ ---
24
+
25
+ ## 🛠️ 工具功能详情
26
+
27
+ | 功能类别 | 工具名称 | 描述 | 使用场景 | 状态 |
28
+ |---------|--------------------------------------------------------------|-------------|---------------|------|
29
+ | **文档管理** | `create_feishu_document` | 创建新的飞书文档 | 从零开始创建文档 | ✅ 已完成 |
30
+ | | `get_feishu_document_info` | 获取文档基本信息 | 验证文档存在性和权限 | ✅ 已完成 |
31
+ | | `get_feishu_document_content` | 获取文档纯文本内容 | 内容分析和处理 | ✅ 已完成 |
32
+ | | `get_feishu_document_blocks` | 获取文档块结构 | 了解文档层级结构 | ✅ 已完成 |
33
+ | | `get_feishu_block_content` | 获取特定块内容 | 检查块属性和格式 | ✅ 已完成 |
34
+ | **内容编辑** | `batch_create_feishu_blocks` | 批量创建多个块 | 高效创建连续内容 | ✅ 已完成 |
35
+ | | `update_feishu_block_text` | 更新块文本内容 | 修改现有内容 | ✅ 已完成 |
36
+ | | `create_feishu_text_block` | 创建单个文本块 | 精确样式控制的文本创建 | ✅ 已完成 |
37
+ | | `create_feishu_code_block` | 创建代码块 | 技术文档和代码示例 | ✅ 已完成 |
38
+ | | `create_feishu_heading_block` | 创建标题块 | 章节标题和层级结构 | ✅ 已完成 |
39
+ | | `create_feishu_list_block` | 创建列表块 | 有序和无序列表创建 | ✅ 已完成 |
40
+ | | `delete_feishu_document_blocks` | 删除文档块 | 清理和重构文档内容 | ✅ 已完成 |
41
+ | **文件夹管理** | `get_feishu_root_folder_info` | 获取根文件夹信息 | 获取基础文件夹信息 | ✅ 已完成 |
42
+ | | `get_feishu_folder_files` | 获取文件夹文件列表 | 浏览文件夹内容 | ✅ 已完成 |
43
+ | | `create_feishu_folder` | 创建新文件夹 | 组织文档结构 | ✅ 已完成 |
44
+ | **搜索功能** | `search_feishu_documents` | 搜索文档 | 查找特定内容 | ✅ 已完成 |
45
+ | **工具功能** | `convert_feishu_wiki_to_document_id` | Wiki链接转换 | 将Wiki链接转为文档ID | ✅ 已完成 |
46
+ | | `get_feishu_image_resource` | 获取图片资源 | 下载文档中的图片 | ✅ 已完成 |
47
+ | | `get_feishu_whiteboard_content` | 获取画板内容 | 获取画板中的图形元素和结构 | ✅ 已完成 |
48
+ | **高级功能** | 表格操作 | 创建和编辑表格 | 结构化数据展示 | 🚧 计划中 |
49
+ | | 图表插入 | 支持各类数据可视化图表 | 数据展示和分析 | 🚧 计划中 |
50
+ | | 流程图插入 | 支持流程图和思维导图 | 流程梳理和可视化 | 🚧 计划中 |
51
+ | 图片插入 | `create_feishu_image_block`、`upload_and_bind_image_to_block` | 支持插入本地和远程图片 | 修改文档内容 | ✅ 已完成 |
52
+ | | 公式支持 | 支持数学公式 | 学术和技术文档 | ✅ 已完成 |
53
+
54
+ ### 🎨 支持的样式功能
55
+
56
+ - **文本样式**:粗体、斜体、下划线、删除线、行内代码
57
+ - **文本颜色**:灰色、棕色、橙色、黄色、绿色、蓝色、紫色
58
+ - **对齐方式**:左对齐、居中、右对齐
59
+ - **标题级别**:支持1-9级标题
60
+ - **代码块**:支持多种编程语言语法高亮
61
+ - **列表**:有序列表(编号)、无序列表(项目符号)
62
+ - **图片**:支持本地图片和网络图片
63
+ - **公式**:在文本块中插入数学公式,支持LaTeX语法
64
+
65
+ ---
66
+
67
+ ## 🔧 飞书配置教程
68
+
69
+ **⚠️ 重要提示:在开始使用之前,必须先完成飞书应用配置,否则无法正常使用本工具。**
56
70
 
57
- ### 使用 NPM 快速运行服务器
71
+ 关于如何创建飞书应用和获取应用凭证的说明可以在[官方教程](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app)找到。
58
72
 
59
- 你可以使用 NPM 快速运行服务器,无需安装或构建仓库:
73
+ **详细的飞书应用配置步骤**:有关注册飞书应用、配置权限、添加文档访问权限的详细指南,请参阅 [手把手教程 FEISHU_CONFIG.md](FEISHU_CONFIG.md)。
60
74
 
61
- ```bash
62
- npx feishu-mcp --feishu-app-id=<你的飞书应用ID> --feishu-app-secret=<你的飞书应用密钥>
75
+ ---
63
76
 
64
- #
65
- pnpx feishu-mcp --feishu-app-id=<你的飞书应用ID> --feishu-app-secret=<你的飞书应用密钥>
77
+ ## 🏃‍♂️ 快速开始
66
78
 
67
- #
68
- yarn dlx feishu-mcp --feishu-app-id=<你的飞书应用ID> --feishu-app-secret=<你的飞书应用密钥>
79
+ ### 方式一:使用 NPM 快速运行
69
80
 
70
- # 或
71
- bunx feishu-mcp --feishu-app-id=<你的飞书应用ID> --feishu-app-secret=<你的飞书应用密钥>
81
+ ```bash
82
+ npx feishu-mcp@latest --feishu-app-id=<你的飞书应用ID> --feishu-app-secret=<你的飞书应用密钥>
72
83
  ```
73
84
 
74
- **已发布到smithery平台,可访问:https://smithery.ai/server/@cso1z/feishu-mcp**
75
-
85
+ ### 方式二:使用 Smithery 平台
86
+
87
+ **已发布到 Smithery 平台,可访问:** https://smithery.ai/server/@cso1z/feishu-mcp
88
+
89
+ ### 方式三:本地运行
90
+
91
+
92
+ #### 🌿 分支说明
93
+
94
+ 本项目采用主分支(main)+功能分支(feature/xxx)协作模式:
95
+
96
+ - **main**
97
+ 稳定主线分支,始终保持可用、可部署状态。所有已验证和正式发布的功能都会合并到 main 分支。
98
+
99
+ - **multi-user-token**
100
+
101
+ 多用户隔离与按用户授权的 Feishu Token 获取功能开发分支。该分支支持 userKey 参数、按用户获取和缓存 Token、自定义 Token 服务等高级特性,适用于需要多用户隔离和授权场景的开发与测试。
102
+ > ⚠️ 该分支为 beta 版本,功能更新相较 main 分支可能会有延后。如有相关需求请在 issue 区留言,我会优先同步最新功能到该分支。
103
+
104
+
105
+ 1. **克隆仓库**
106
+ ```bash
107
+ git clone https://github.com/cso1z/Feishu-MCP.git
108
+ cd Feishu-MCP
109
+ ```
110
+
111
+ 2. **安装依赖**
112
+ ```bash
113
+ pnpm install
114
+ ```
115
+
116
+ 3. **配置环境变量**
117
+
118
+ **macOS/Linux:**
119
+ ```bash
120
+ cp .env.example .env
121
+ ```
122
+
123
+ **Windows:**
124
+ ```cmd
125
+ copy .env.example .env
126
+ ```
127
+
128
+ 4. **编辑 .env 文件**
129
+
130
+ 你可以通过以下任一方式编辑 .env 文件:
131
+
132
+ **方式一:使用文件管理器**
133
+ - 在项目文件夹中找到 `.env` 文件
134
+ - 双击打开(系统会自动选择文本编辑器)
135
+ - 或右键选择"打开方式" → 选择文本编辑器
136
+
137
+ **方式二:使用 VS Code**
138
+ ```bash
139
+ code .env
140
+ ```
141
+
142
+ **方式三:使用命令行编辑器**
143
+ ```bash
144
+ # macOS/Linux
145
+ nano .env
146
+
147
+ # Windows
148
+ notepad .env
149
+ ```
150
+
151
+ 填入你的飞书应用凭证:
152
+ ```env
153
+ FEISHU_APP_ID=cli_xxxxx
154
+ FEISHU_APP_SECRET=xxxxx
155
+ PORT=3333
156
+ ```
157
+
158
+ 5. **运行服务器**
159
+ ```bash
160
+ pnpm run dev
161
+ ```
162
+
163
+ ## ⚙️ 项目配置
164
+
165
+ ### 环境变量配置
166
+
167
+ | 变量名 | 必需 | 描述 | 默认值 |
168
+ |--------|------|------|-------|
169
+ | `FEISHU_APP_ID` | ✅ | 飞书应用 ID | - |
170
+ | `FEISHU_APP_SECRET` | ✅ | 飞书应用密钥 | - |
171
+ | `PORT` | ❌ | 服务器端口 | `3333` |
76
172
 
77
- 关于如何创建飞书应用和获取应用凭证的说明可以在[官方教程](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app)找到。
78
-
79
-
80
- **详细的飞书应用配置步骤**:有关注册飞书应用、配置权限、添加文档访问权限的详细指南,请参阅 [手把手教程 FEISHU_CONFIG.md](FEISHU_CONFIG.md)。
81
-
82
-
83
- ### 使用配置文件的工具的 JSON 配置
84
-
85
- 许多工具如 Windsurf、Cline 和 [Claude Desktop](https://claude.ai/download) 使用配置文件来启动服务器。
173
+ ### 命令行参数
86
174
 
87
- `feishu-mcp` 服务器可以通过在配置文件中添加以下内容来配置:
175
+ | 参数 | 描述 | 默认值 |
176
+ |------|------|-------|
177
+ | `--port` | 服务器监听端口 | `3333` |
178
+ | `--log-level` | 日志级别 (debug/info/log/warn/error/none) | `info` |
179
+ | `--feishu-app-id` | 飞书应用 ID | - |
180
+ | `--feishu-app-secret` | 飞书应用密钥 | - |
181
+ | `--feishu-base-url` | 飞书API基础URL | `https://open.feishu.cn/open-apis` |
182
+ | `--cache-enabled` | 是否启用缓存 | `true` |
183
+ | `--cache-ttl` | 缓存生存时间(秒) | `3600` |
184
+ | `--stdio` | 命令模式运行 | - |
185
+ | `--help` | 显示帮助菜单 | - |
186
+ | `--version` | 显示版本号 | - |
187
+
188
+ ### 配置文件方式(适用于 Cursor、Cline 等)
88
189
 
89
190
  ```json
90
191
  {
@@ -97,68 +198,69 @@ bunx feishu-mcp --feishu-app-id=<你的飞书应用ID> --feishu-app-secret=<你
97
198
  "FEISHU_APP_SECRET": "<你的飞书应用密钥>"
98
199
  }
99
200
  }
100
- }
201
+ },
202
+ "feishu_local": {
203
+ "url": "http://localhost:3333/sse"
204
+ }
101
205
  }
102
206
  ```
207
+ ---
103
208
 
104
- ### 从本地源代码运行服务器
209
+ ## 📝 使用贴士(重要)
105
210
 
106
- 1. 克隆仓库
107
- 2. 使用 `pnpm install` 安装依赖
108
- 3. 复制 `.env.example` 到 `.env` 并填入你的[飞书应用凭证](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app)。
109
- 4. 使用 `pnpm run dev` 运行服务器,可以使用[命令行参数](#命令行参数)部分的任何标志。
211
+ 1. ### **推荐指定文件夹**:
212
+ 新建文档时,建议主动提供飞书文件夹 token(可为具体文件夹或根文件夹),这样可以更高效地定位和管理文档。如果不确定具体的子文件夹,可以让LLM自动在你指定的文件夹下查找最合适的子目录来新建文档。
213
+
214
+ > **如何获取文件夹 token?**
215
+ > 打开飞书文件夹页面,复制链接(如 `https://.../drive/folder/xxxxxxxxxxxxxxxxxxxxxx`),token 就是链接最后的那一串字符(如 `xxxxxxxxxxxxxxxxxxxxxx`,请勿泄露真实 token)。
110
216
 
111
- ## 配置
217
+ 2. ### **图片上传路径说明**:
218
+ 本地运行 MCP 时,图片路径既支持本地绝对路径,也支持 http/https 网络图片;如在服务器环境,仅支持网络图片链接(由于cursor调用mcp时参数长度限制,暂不支持直接上传图片文件本体,请使用图片路径或链接方式上传)。
112
219
 
113
- 服务器可以使用环境变量(通过 `.env` 文件)或命令行参数进行配置。命令行参数优先于环境变量。
220
+ 3. ### **公式使用说明**:
221
+ 在文本块中可以混合使用普通文本和公式元素。公式使用LaTeX语法,如:`1+2=3`、`\frac{a}{b}`、`\sqrt{x}`等。支持在同一文本块中包含多个公式和普通文本。
114
222
 
115
- ### 环境变量
223
+ ---
116
224
 
117
- - `FEISHU_APP_ID`:你的[飞书应用 ID](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app)(必需)
118
- - `FEISHU_APP_SECRET`:你的[飞书应用密钥](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app)(必需)
119
- - `PORT`:运行服务器的端口(默认:3333)
225
+ ## 🚨 故障排查
120
226
 
121
- ### 命令行参数
227
+ ### 权限问题排查
228
+ 先对照配置问题查看: [手把手教程 FEISHU_CONFIG.md](FEISHU_CONFIG.md)。
229
+
230
+ #### 问题确认
231
+ 1. **检查应用权限**:确保应用已获得必要的文档访问权限
232
+ 2. **验证文档授权**:确认目标文档已授权给应用或应用所在的群组
233
+ 3. **检查可用范围**:确保应用发布版本的可用范围包含文档所有者
122
234
 
123
- - `--version`:显示版本号
124
- - `--feishu-app-id`:你的飞书应用 ID
125
- - `--feishu-app-secret`:你的飞书应用密钥
126
- - `--port`:运行服务器的端口
127
- - `--stdio`:在命令模式下运行服务器,而不是默认的 HTTP/SSE
128
- - `--help`:显示帮助菜单
235
+ #### 权限验证与排查
236
+ 1. 获取token:[自建应用获取 app_access_token](https://open.feishu.cn/api-explorer?apiName=app_access_token_internal&project=auth&resource=auth&version=v3)
237
+ 2. 使用第1步获取的token,验证是否有权限访问该文档:[获取文档基本信息](https://open.feishu.cn/api-explorer?apiName=get&project=docx&resource=document&version=v1)
129
238
 
130
- ## 连接到 Cursor
131
239
 
132
- ### 配置 Cursor
240
+ ### 常见问题
133
241
 
134
- 1. 打开 Cursor 设置
135
- 2. 导航到 `Settings > AI > MCP Servers`
136
- 3. 添加新服务器,URL 为 `http://localhost:3333`(或你配置的端口)
137
- 4. 点击 "Verify Connection" 确保连接成功
242
+ - **找不到应用**:检查应用是否已发布且可用范围配置正确
243
+ - **权限不足**:参考[云文档常见问题](https://open.feishu.cn/document/ukTMukTMukTM/uczNzUjL3czM14yN3MTN)
244
+ - **知识库访问问题**:参考[知识库常见问题](https://open.feishu.cn/document/server-docs/docs/wiki-v2/wiki-qa)
138
245
 
139
- ## 使用方法
246
+ ---
140
247
 
141
- 1. Cursor 中,打开 AI 面板(默认快捷键 `Cmd+K` 或 `Ctrl+K`)
142
- 2. 如果需要新建一个飞书文档编辑信息,应该明确制定一个folderToken,可以打开一个飞书文档目录如:`https://vq5xxxxx7bc.feishu.cn/drive/folder/FPKvfjdxxxxx706RnOc查找`
143
- 2. 如果需要修改飞书文档内容应该明确告知飞书文档链接,例如:`https://vq5ixxxx7bc.feishu.cn/docx/J6T0d6exxxxxxxDdc1zqwnph`
144
- 3. 询问关于文档的问题或请求基于文档内容执行操作
145
- 4. 创建编辑文档都需要权限,可以到飞书开放平台对账号进行测试`https://open.feishu.cn/api-explorer/cli_a75a8ca0ac79100c?apiName=tenant_access_token_internal&from=op_doc&project=auth&resource=auth&version=v3`
248
+ ## 💖 支持项目
146
249
 
147
- ## 文档权限与故障排查
250
+ 如果这个项目帮助到了你,请考虑:
148
251
 
149
- ### 权限类型
150
- 权限分为两种:机器人权限、文档访问权限
252
+ - ⭐ 给项目一个 Star
253
+ - 🐛 报告 Bug 和问题
254
+ - 💡 提出新功能建议
255
+ - 📖 改进文档
256
+ - 🔀 提交 Pull Request
151
257
 
152
- ### 权限验证与排查
153
- 1. 获取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)
154
- 2. 使用第1步获取的token,验证是否有权限访问该文档:[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)
258
+ 你的支持是我们前进的动力!
155
259
 
156
- ### 排查方法
157
- 在飞书开发平台测试权限正常(在开放平台调试,失败时会有充足提示信息和指导)
260
+ **<span id="group-qr">欢迎加入我们的交流群,与更多小伙伴一起交流:</span>**
158
261
 
159
- ### 文档授权
160
- 如遇到权限问题,请参考[云文档常见问题](https://open.feishu.cn/document/ukTMukTMukTM/uczNzUjL3czM14yN3MTN)、[知识库常见问题](https://open.feishu.cn/document/server-docs/docs/wiki-v2/wiki-qa),特别关注如何为应用或用户开通文档权限。
262
+ <img src="./image/group_qr.jpg" alt="飞书MCP交流群二维码" width="300" />
161
263
 
162
- ## 许可证
264
+ ## 🤝 贡献
163
265
 
164
- MIT
266
+ 欢迎提交 Issue 和 Pull Request!如果你在使用过程中遇到问题或有改进建议,也欢迎随时告诉我们。
@@ -38,7 +38,6 @@ export class SSEConnectionManager {
38
38
  clearInterval(this.keepAliveIntervalId);
39
39
  }
40
40
  this.keepAliveIntervalId = setInterval(() => {
41
- Logger.info(`[KeepAlive] Sending keepalive to ${this.connections.size} connections`);
42
41
  for (const [sessionId, connection] of this.connections.entries()) {
43
42
  if (!connection.res.writableEnded) {
44
43
  connection.res.write(': keepalive\n\n');
@@ -2,7 +2,7 @@ import { z } from 'zod';
2
2
  import { formatErrorMessage } from '../../utils/error.js';
3
3
  import { Logger } from '../../utils/logger.js';
4
4
  import { detectMimeType } from '../../utils/document.js';
5
- import { DocumentIdSchema, ParentBlockIdSchema, BlockIdSchema, IndexSchema, StartIndexSchema, EndIndexSchema, AlignSchema, AlignSchemaWithValidation, TextElementsArraySchema, CodeLanguageSchema, CodeWrapSchema, BlockConfigSchema, MediaIdSchema, MediaExtraSchema } from '../../types/feishuSchema.js';
5
+ import { DocumentIdSchema, ParentBlockIdSchema, BlockIdSchema, IndexSchema, StartIndexSchema, EndIndexSchema, AlignSchema, AlignSchemaWithValidation, TextElementsArraySchema, CodeLanguageSchema, CodeWrapSchema, BlockConfigSchema, MediaIdSchema, MediaExtraSchema, ImagePathOrUrlSchema, ImageFileNameSchema, ImageWidthSchema, ImageHeightSchema } from '../../types/feishuSchema.js';
6
6
  /**
7
7
  * 注册飞书块相关的MCP工具
8
8
  * @param server MCP服务器实例
@@ -97,12 +97,23 @@ export function registerFeishuBlockTools(server, feishuService) {
97
97
  // 批量创建所有块
98
98
  const result = await feishuService.createDocumentBlocks(documentId, parentBlockId, blockContents, index);
99
99
  Logger.info(`飞书块批量创建成功,共创建 ${blockContents.length} 个块`);
100
+ // 检查是否有图片块(block_type=27)
101
+ const imageBlocks = result.children?.filter((child) => child.block_type === 27) || [];
102
+ const hasImageBlocks = imageBlocks.length > 0;
103
+ const responseData = {
104
+ ...result,
105
+ nextIndex: index + blockContents.length,
106
+ totalBlocksCreated: blockContents.length,
107
+ ...(hasImageBlocks && {
108
+ imageBlocksInfo: {
109
+ count: imageBlocks.length,
110
+ blockIds: imageBlocks.map((block) => block.block_id),
111
+ reminder: "检测到图片块已创建!请使用 upload_and_bind_image_to_block 工具上传图片并绑定到对应的块ID。"
112
+ }
113
+ })
114
+ };
100
115
  return {
101
- content: [{ type: 'text', text: JSON.stringify({
102
- ...result,
103
- nextIndex: index + blockContents.length,
104
- totalBlocksCreated: blockContents.length
105
- }, null, 2) }],
116
+ content: [{ type: 'text', text: JSON.stringify(responseData, null, 2) }],
106
117
  };
107
118
  }
108
119
  else {
@@ -173,13 +184,24 @@ export function registerFeishuBlockTools(server, feishuService) {
173
184
  }
174
185
  if (allBatchesSuccess) {
175
186
  Logger.info(`所有批次创建成功,共创建 ${createdBlocksCount} 个块`);
187
+ // 检查所有批次中是否有图片块(block_type=27)
188
+ const allImageBlocks = [];
189
+ results.forEach(batchResult => {
190
+ const imageBlocks = batchResult.children?.filter((child) => child.block_type === 27) || [];
191
+ allImageBlocks.push(...imageBlocks);
192
+ });
193
+ const hasImageBlocks = allImageBlocks.length > 0;
194
+ const responseText = `所有飞书块创建成功,共分 ${totalBatches} 批创建了 ${createdBlocksCount} 个块。\n\n` +
195
+ `最后一批结果: ${JSON.stringify(results[results.length - 1], null, 2)}\n\n` +
196
+ `下一个索引位置: ${currentStartIndex},总创建块数: ${createdBlocksCount}` +
197
+ (hasImageBlocks ? `\n\n⚠️ 检测到 ${allImageBlocks.length} 个图片块已创建!\n` +
198
+ `图片块IDs: ${allImageBlocks.map(block => block.block_id).join(', ')}\n` +
199
+ `请使用 upload_and_bind_image_to_block 工具上传图片并绑定到对应的块ID。` : '');
176
200
  return {
177
201
  content: [
178
202
  {
179
203
  type: 'text',
180
- text: `所有飞书块创建成功,共分 ${totalBatches} 批创建了 ${createdBlocksCount} 个块。\n\n` +
181
- `最后一批结果: ${JSON.stringify(results[results.length - 1], null, 2)}\n\n` +
182
- `下一个索引位置: ${currentStartIndex},总创建块数: ${createdBlocksCount}`
204
+ text: responseText
183
205
  }
184
206
  ],
185
207
  };
@@ -424,4 +446,93 @@ export function registerFeishuBlockTools(server, feishuService) {
424
446
  };
425
447
  }
426
448
  });
449
+ // 添加创建飞书图片块工具
450
+ server.tool('create_feishu_image_block', 'Creates a complete image block in a Feishu document by uploading an image from a local path or URL and setting it to the block. This tool handles the entire 3-step process: (1) Creates an empty image block, (2) Downloads/reads the image and uploads it as media resource, (3) Sets the image content to the block. Supports local file paths and HTTP/HTTPS URLs. Use this when you want to insert images into Feishu documents. 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.', {
451
+ documentId: DocumentIdSchema,
452
+ parentBlockId: ParentBlockIdSchema,
453
+ imagePathOrUrl: ImagePathOrUrlSchema,
454
+ fileName: ImageFileNameSchema,
455
+ width: ImageWidthSchema,
456
+ height: ImageHeightSchema,
457
+ index: IndexSchema
458
+ }, async ({ documentId, parentBlockId, imagePathOrUrl, fileName, width, height, index = 0 }) => {
459
+ try {
460
+ if (!feishuService) {
461
+ return {
462
+ content: [{ type: 'text', text: 'Feishu service is not initialized. Please check the configuration' }],
463
+ };
464
+ }
465
+ Logger.info(`开始创建飞书图片块,文档ID: ${documentId},父块ID: ${parentBlockId},图片源: ${imagePathOrUrl},插入位置: ${index}`);
466
+ const result = await feishuService.createImageBlock(documentId, parentBlockId, imagePathOrUrl, {
467
+ fileName,
468
+ width,
469
+ height,
470
+ index
471
+ });
472
+ Logger.info(`飞书图片块创建成功,块ID: ${result.imageBlockId}`);
473
+ return {
474
+ content: [{
475
+ type: 'text',
476
+ text: `图片块创建成功!\n\n块ID: ${result.imageBlockId}\n文件Token: ${result.fileToken}\n文档修订ID: ${result.documentRevisionId}\n\n完整结果:\n${JSON.stringify(result, null, 2)}`
477
+ }],
478
+ };
479
+ }
480
+ catch (error) {
481
+ Logger.error(`创建飞书图片块失败:`, error);
482
+ const errorMessage = formatErrorMessage(error);
483
+ return {
484
+ content: [{ type: 'text', text: `创建飞书图片块失败: ${errorMessage}` }],
485
+ };
486
+ }
487
+ });
488
+ // 添加图片上传绑定工具
489
+ server.tool('upload_and_bind_image_to_block', 'Uploads an image from a local path or URL and binds it to an existing empty image block. This tool is used after creating image blocks with batch_create_feishu_blocks tool. It handles uploading the image media and setting the image content to the specified block ID. Supports local file paths and HTTP/HTTPS URLs.', {
490
+ documentId: DocumentIdSchema,
491
+ blockId: BlockIdSchema,
492
+ imagePathOrUrl: ImagePathOrUrlSchema,
493
+ fileName: ImageFileNameSchema,
494
+ }, async ({ documentId, blockId, imagePathOrUrl, fileName }) => {
495
+ try {
496
+ if (!feishuService) {
497
+ return {
498
+ content: [{ type: 'text', text: 'Feishu service is not initialized. Please check the configuration' }],
499
+ };
500
+ }
501
+ Logger.info(`开始上传图片并绑定到块,文档ID: ${documentId},块ID: ${blockId},图片源: ${imagePathOrUrl}`);
502
+ // 从路径或URL获取图片的Base64编码
503
+ const { base64: imageBase64, fileName: detectedFileName } = await feishuService.getImageBase64FromPathOrUrl(imagePathOrUrl);
504
+ // 使用提供的文件名或检测到的文件名
505
+ const finalFileName = fileName || detectedFileName;
506
+ // 第1步:上传图片素材
507
+ Logger.info('第1步:上传图片素材');
508
+ const uploadResult = await feishuService.uploadImageMedia(imageBase64, finalFileName, blockId);
509
+ if (!uploadResult?.file_token) {
510
+ throw new Error('上传图片素材失败:无法获取file_token');
511
+ }
512
+ Logger.info(`图片素材上传成功,file_token: ${uploadResult.file_token}`);
513
+ // 第2步:设置图片块内容
514
+ Logger.info('第2步:设置图片块内容');
515
+ const setContentResult = await feishuService.setImageBlockContent(documentId, blockId, uploadResult.file_token);
516
+ Logger.info('图片上传并绑定完成');
517
+ return {
518
+ content: [{
519
+ type: 'text',
520
+ text: `图片上传并绑定成功!\n\n块ID: ${blockId}\n文件Token: ${uploadResult.file_token}\n文档修订ID: ${setContentResult.document_revision_id}\n\n完整结果:\n${JSON.stringify({
521
+ blockId: blockId,
522
+ fileToken: uploadResult.file_token,
523
+ uploadResult: uploadResult,
524
+ setContentResult: setContentResult,
525
+ documentRevisionId: setContentResult.document_revision_id
526
+ }, null, 2)}`
527
+ }],
528
+ };
529
+ }
530
+ catch (error) {
531
+ Logger.error(`上传图片并绑定到块失败:`, error);
532
+ const errorMessage = formatErrorMessage(error);
533
+ return {
534
+ content: [{ type: 'text', text: `上传图片并绑定到块失败: ${errorMessage}` }],
535
+ };
536
+ }
537
+ });
427
538
  }
@@ -1,6 +1,6 @@
1
1
  import { formatErrorMessage } from '../../utils/error.js';
2
2
  import { Logger } from '../../utils/logger.js';
3
- import { FolderTokenSchema, FolderNameSchema, OrderBySchema, DirectionSchema } from '../../types/feishuSchema.js';
3
+ import { FolderTokenSchema, FolderNameSchema, } from '../../types/feishuSchema.js';
4
4
  /**
5
5
  * 注册飞书文件夹相关的MCP工具
6
6
  * @param server MCP服务器实例
@@ -33,17 +33,15 @@ export function registerFeishuFolderTools(server, feishuService) {
33
33
  // 添加获取文件夹中的文件清单工具
34
34
  server.tool('get_feishu_folder_files', 'Retrieves a list of files and subfolders in a specified folder. Use this to explore folder contents, view file metadata, and get URLs and tokens for further operations.', {
35
35
  folderToken: FolderTokenSchema,
36
- orderBy: OrderBySchema,
37
- direction: DirectionSchema
38
- }, async ({ folderToken, orderBy = 'EditedTime', direction = 'DESC' }) => {
36
+ }, async ({ folderToken, }) => {
39
37
  try {
40
38
  if (!feishuService) {
41
39
  return {
42
40
  content: [{ type: 'text', text: '飞书服务未初始化,请检查配置' }],
43
41
  };
44
42
  }
45
- Logger.info(`开始获取飞书文件夹中的文件清单,文件夹Token: ${folderToken},排序方式: ${orderBy},排序方向: ${direction}`);
46
- const fileList = await feishuService.getFolderFileList(folderToken, orderBy, direction);
43
+ Logger.info(`开始获取飞书文件夹中的文件清单,文件夹Token: ${folderToken}`);
44
+ const fileList = await feishuService.getFolderFileList(folderToken);
47
45
  Logger.info(`飞书文件夹中的文件清单获取成功,共 ${fileList.files?.length || 0} 个文件`);
48
46
  return {
49
47
  content: [{ type: 'text', text: JSON.stringify(fileList, null, 2) }],
@@ -1,7 +1,7 @@
1
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, BlockIdSchema, SearchKeySchema, WhiteboardIdSchema, DocumentTitleSchema, FolderTokenSchema, } from '../../types/feishuSchema.js';
5
5
  /**
6
6
  * 注册飞书相关的MCP工具
7
7
  * @param server MCP服务器实例
@@ -10,8 +10,8 @@ import { DocumentIdSchema, BlockIdSchema, SearchKeySchema, } from '../../types/f
10
10
  export function registerFeishuTools(server, feishuService) {
11
11
  // 添加创建飞书文档工具
12
12
  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".'),
13
+ title: DocumentTitleSchema,
14
+ folderToken: FolderTokenSchema,
15
15
  }, async ({ title, folderToken }) => {
16
16
  try {
17
17
  Logger.info(`开始创建飞书文档,标题: ${title}${folderToken ? `,文件夹Token: ${folderToken}` : ',使用默认文件夹'}`);
@@ -96,8 +96,26 @@ export function registerFeishuTools(server, feishuService) {
96
96
  Logger.info(`开始获取飞书文档块,文档ID: ${documentId}`);
97
97
  const blocks = await feishuService.getDocumentBlocks(documentId);
98
98
  Logger.info(`飞书文档块获取成功,共 ${blocks.length} 个块`);
99
+ // 检查是否有 block_type 为 43 的块(画板块)
100
+ const whiteboardBlocks = blocks.filter((block) => block.block_type === 43);
101
+ const hasWhiteboardBlocks = whiteboardBlocks.length > 0;
102
+ let responseText = JSON.stringify(blocks, null, 2);
103
+ if (hasWhiteboardBlocks) {
104
+ responseText += '\n\n⚠️ 检测到画板块 (block_type: 43)!\n';
105
+ responseText += `发现 ${whiteboardBlocks.length} 个画板块。画板块包含丰富的图形内容,如形状、文本、思维导图等。\n`;
106
+ responseText += '建议使用 get_feishu_whiteboard_content 工具来获取画板的具体内容和结构。\n';
107
+ responseText += '画板信息:\n';
108
+ whiteboardBlocks.forEach((block, index) => {
109
+ responseText += ` ${index + 1}. 块ID: ${block.block_id}`;
110
+ if (block.board && block.board.token) {
111
+ responseText += `, 画板ID: ${block.board.token}`;
112
+ }
113
+ responseText += '\n';
114
+ });
115
+ responseText += '请使用上述画板ID调用 get_feishu_whiteboard_content 工具。';
116
+ }
99
117
  return {
100
- content: [{ type: 'text', text: JSON.stringify(blocks, null, 2) }],
118
+ content: [{ type: 'text', text: responseText }],
101
119
  };
102
120
  }
103
121
  catch (error) {
@@ -163,4 +181,29 @@ export function registerFeishuTools(server, feishuService) {
163
181
  };
164
182
  }
165
183
  });
184
+ // 添加获取画板内容工具
185
+ 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.', {
186
+ whiteboardId: WhiteboardIdSchema,
187
+ }, async ({ whiteboardId }) => {
188
+ try {
189
+ if (!feishuService) {
190
+ return {
191
+ content: [{ type: 'text', text: 'Feishu service is not initialized. Please check the configuration' }],
192
+ };
193
+ }
194
+ Logger.info(`开始获取飞书画板内容,画板ID: ${whiteboardId}`);
195
+ const whiteboardContent = await feishuService.getWhiteboardContent(whiteboardId);
196
+ Logger.info(`飞书画板内容获取成功,节点数量: ${whiteboardContent.nodes?.length || 0}`);
197
+ return {
198
+ content: [{ type: 'text', text: JSON.stringify(whiteboardContent, null, 2) }],
199
+ };
200
+ }
201
+ catch (error) {
202
+ Logger.error(`获取飞书画板内容失败:`, error);
203
+ const errorMessage = formatErrorMessage(error);
204
+ return {
205
+ content: [{ type: 'text', text: `获取飞书画板内容失败: ${errorMessage}` }],
206
+ };
207
+ }
208
+ });
166
209
  }