feishu-wiki-mcp
# 飞书 MCP 使用指南(feishu-wiki-mcp)
本项目是**面向 MCP 客户端的飞书服务网关**,运行时通过飞书开放平台 API 提供标准化工具调用。
- 运行时:Node.js >= 20 + stdio transport(`@modelcontextprotocol/sdk`)
- 入口:`build/index.js`
- 当前版本:`1.3.1`
- 包名:`@akaknele/feishu-wiki-mcp`
- 当前可用 Tool:36 个
## 一、部署与启动方式
### 1. 开发构建与本地运行
```bash
npm install
npm run build
npm start -- --app-id <APP_ID> --app-secret <APP_SECRET>
```
### 2. OAuth 模式(用于用户授权)
适用于需要用户级权限(`user token`)的场景:
```bash
npm start -- --app-id <APP_ID> --app-secret <APP_SECRET> --oauth --port 3001
```
### 2b. 预置 Token 模式(无浏览器,适合第三方 MCP 客户端)
当第三方应用(Claude Desktop、Cursor 等)安装 MCP 无法弹出浏览器时,可提前获取 user token 后通过参数或环境变量传入,完全跳过 OAuth 授权流程:
```bash
# 命令行参数
feishu-wiki-mcp --app-id <APP_ID> --app-secret <APP_SECRET> \
--user-token <USER_ACCESS_TOKEN> \
--refresh-token <REFRESH_TOKEN>
# 或环境变量(推荐)
FEISHU_APP_ID=cli_xxx \
FEISHU_APP_SECRET=secret_xxx \
FEISHU_USER_TOKEN=u-xxx \
FEISHU_REFRESH_TOKEN=ur-xxx \
feishu-wiki-mcp
```
MCP 客户端配置示例:
```json
{
"mcpServers": {
"feishu-wiki-mcp": {
"command": "feishu-wiki-mcp",
"args": ["--app-id", "<APP_ID>", "--app-secret", "<APP_SECRET>"],
"env": {
"FEISHU_USER_TOKEN": "<USER_ACCESS_TOKEN>",
"FEISHU_REFRESH_TOKEN": "<REFRESH_TOKEN>"
}
}
}
}
```
> token 过期后会自动用 `refresh_token` 刷新;refresh_token 也过期则报错,需重新获取。
### 2c. 如何获取 User Token
预置模式需要提前拿到 `user_access_token` 和 `refresh_token`,有以下三种方式:
#### 方式一:运行一次 `--oauth`,从缓存文件提取(推荐)
在**有浏览器的机器**上完成一次授权:
```bash
feishu-wiki-mcp --app-id cli_xxx --app-secret xxx --oauth --port 3001
```
授权成功后读取缓存文件:
```bash
cat ~/.feishu-wiki-mcp-token.json
```
输出示例:
```json
{
"access_token": "u-xxx...",
"refresh_token": "ur-xxx...",
"expires_at": 1234567890000,
"refresh_expires_at": 9876543210000
}
```
将 `access_token` 和 `refresh_token` 填入环境变量即可。`refresh_token` 有效期约 30 天,MCP 会自动续期 `access_token`,正常使用无感知。
#### 方式二:飞书开放平台 API 调试台(无需写代码)
1. 打开 [open.feishu.cn](https://open.feishu.cn) → 进入你的应用
2. 左侧菜单选择 **"开发工具 → API 调试台"**
3. 右上角鉴权方式选择 **"用户身份(user_access_token)"**,点击授权登录
4. 授权完成后,调试台会自动填入 token,复制即可
#### 方式三:手动 OAuth 换 token(Shell 脚本)
适合自动化脚本场景,需要一个可访问的回调地址(本地 localhost 即可):
```bash
# 替换为你的 App ID / Secret
APP_ID="cli_xxx"
APP_SECRET="xxx"
PORT=3001
# Step 1:用浏览器打开授权 URL,完成后从地址栏取 code 参数
SCOPES="wiki:wiki docx:document drive:drive bitable:bitable im:message contact:user.id:readonly"
echo "请用浏览器访问以下地址完成授权:"
echo "https://open.feishu.cn/open-apis/authen/v1/index?app_id=${APP_ID}&redirect_uri=http%3A%2F%2Flocalhost%3A${PORT}%2Fcallback&scope=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${SCOPES}'))")"
echo ""
read -p "粘贴回调 URL 中的 code 参数值: " CODE
# Step 2:获取 app_access_token
APP_TOKEN=$(curl -s -X POST "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal" \
-H "Content-Type: application/json" \
-d "{\"app_id\":\"${APP_ID}\",\"app_secret\":\"${APP_SECRET}\"}" | jq -r .app_access_token)
# Step 3:用 code 换 user_access_token + refresh_token
curl -s -X POST "https://open.feishu.cn/open-apis/authen/v1/oidc/access_token" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${APP_TOKEN}" \
-d "{\"grant_type\":\"authorization_code\",\"code\":\"${CODE}\"}" | jq '{access_token: .data.access_token, refresh_token: .data.refresh_token}'
```
运行后输出的 `access_token` 和 `refresh_token` 即可填入环境变量。
#### Token 有效期说明
| Token | 有效期 | 过期行为 |
|-------|--------|---------|
| `user_access_token` | ~2 小时 | MCP 自动用 refresh_token 续期 |
| `refresh_token` | ~30 天 | 需重新走上述任一方式获取 |
### 3. 安装后直接运行
```bash
npm install -g @akaknele/feishu-wiki-mcp@1.3.1
feishu-wiki-mcp --app-id <APP_ID> --app-secret <APP_SECRET>
```
或使用 npx:
```bash
npx @akaknele/feishu-wiki-mcp@1.3.1 --app-id <APP_ID> --app-secret <APP_SECRET>
```
### 4. MCP 客户端接入(示例)
```json
{
"mcpServers": {
"feishu-wiki-mcp": {
"command": "feishu-wiki-mcp",
"args": ["--app-id", "<APP_ID>", "--app-secret", "<APP_SECRET>"]
}
}
}
```
OAuth 模式示例:
```json
{
"mcpServers": {
"feishu-wiki-mcp": {
"command": "feishu-wiki-mcp",
"args": ["--app-id", "<APP_ID>", "--app-secret", "<APP_SECRET>", "--oauth", "--port", "3001"]
}
}
}
```
## 二、外网网络(OAuth)要求
若在企业内网/防火墙下运行,需要放行:
- `https://open.feishu.cn`
- `https://openapi.*.feishu.cn`(飞书 API 域名)
OAuth 回调地址默认为:
- `http://localhost:3001/callback`
因此对应机器的 `3001` 端口需要可访问(对本机浏览器即可),并且回调 URL 能回传到该本机实例。
## 三、核心流程
1. 启动服务并通过参数选择 tenant 模式或 OAuth 模式
2. MCP 客户端请求对应 tool
3. 服务器内部自动获取并刷新 token(`~/.feishu-wiki-mcp-token.json`)
4. 使用 token 调用飞书接口并返回结构化 JSON
## 四、工具清单(36)
### 工具清单质量说明
每个工具都以 MCP tool schema 的实际参数定义为准,`返回值`默认为飞书 API 的 `JSON` 响应文本。
### 知识库(Wiki)
| 工具 | 用途 | 必填参数 | 可选参数 |
| --- | --- | --- | --- |
| `wiki_list_spaces` | 列出当前用户可见知识库 | 无 | `page_size`(1-50), `page_token` |
| `wiki_get_space` | 获取知识库详情 | `space_id` | 无 |
| `wiki_list_nodes` | 列出知识库子节点(默认顶层) | `space_id` | `parent_node_token`, `page_size`(1-50), `page_token` |
| `wiki_get_node` | 通过 wiki token 或文档 token 获取节点 | `token` | `obj_type`(doc/docx/sheet/mindnote/bitable/file/slides/wiki) |
| `wiki_create_node` | 创建知识库节点(文档/表格等) | `space_id`, `obj_type` | `parent_node_token`, `node_type`(origin/shortcut, 默认 origin), `title` |
| `wiki_move_node` | 在知识库内移动节点 | `space_id`, `node_token` | `target_parent_token`, `target_space_id` |
| `wiki_move_docs_to_wiki` | 将云空间文档移动进知识库 | `space_id`, `obj_type`, `obj_token` | `parent_wiki_token` |
| `wiki_update_title` | 更新节点标题 | `space_id`, `node_token`, `title` | 无 |
| `wiki_copy_node` | 复制节点(可跨库) | `space_id`, `node_token` | `target_parent_token`, `target_space_id`, `title` |
| `wiki_search` | 搜索知识库节点 | `query` | `space_id`, `page_size`, `page_token` |
| `wiki_create_node_with_markdown` | **🆕** 一步创建带 Markdown 内容的 wiki 文档(上传→转换→移入知识库) | `space_id`, `markdown` | `title`(<=27 字符), `parent_node_token` |
### 文档(Docx)
| 工具 | 用途 | 必填参数 | 可选参数 |
| --- | --- | --- | --- |
| `doc_get_raw_content` | 获取文档纯文本内容 | `document_id` | 无 |
| `doc_search` | 搜索云文档 | `search_key` | `count`(0-50), `offset`, `owner_ids`, `docs_types` |
| `doc_import` | 导入 Markdown 创建飞书文档(自动上传 → 转换 docx)。**🆕 v1.3**: 可选传入 `space_id` 直接写入知识库 | `markdown` | `file_name`(<=27 字符), `folder_token`, `space_id`(传入后自动移入知识库), `parent_wiki_token` |
| `doc_list_blocks` | 列出文档所有块 | `document_id` | `page_size`(1-500), `page_token`, `document_revision_id` |
| `doc_get_block` | 获取指定块详情 | `document_id`, `block_id` | `document_revision_id` |
| `doc_create_blocks` | 在指定父块下插入子块。**🆕 v1.3**: 补全所有 block_type 文档 + 客户端参数校验 | `document_id`, `block_id`, `children` | `index`(插入位置,默认追加) |
| `doc_update_block` | 更新指定块内容(PATCH) | `document_id`, `block_id`, `update` | 无 |
| `doc_delete_blocks` | 删除父块下指定区间的子块 | `document_id`, `block_id`, `start_index`, `end_index` | 无 |
### 多维表格(Bitable)
| 工具 | 用途 | 必填参数 | 可选参数 |
| --- | --- | --- | --- |
| `bitable_create_app` | 创建多维表格应用 | 无 | `name`, `folder_token` |
| `bitable_list_tables` | 列出应用内表 | `app_token` | `page_size`, `page_token` |
| `bitable_create_table` | 创建数据表 | `app_token`, `name` | `default_view_name`, `fields`(字段列表) |
| `bitable_list_fields` | 列出表字段 | `app_token`, `table_id` | `page_size`, `page_token` |
| `bitable_search_records` | 条件筛选记录 | `app_token`, `table_id` | `field_names`, `filter`(`conjunction`+`conditions`), `sort`, `page_size`(<=500), `page_token` |
| `bitable_create_record` | 新增记录 | `app_token`, `table_id`, `fields` | 无 |
| `bitable_update_record` | 更新记录 | `app_token`, `table_id`, `record_id`, `fields` | 无 |
### IM 与联系人
| 工具 | 用途 | 必填参数 | 可选参数 |
| --- | --- | --- | --- |
| `im_send_message` | 发送消息(文本/卡片等) | `receive_id`, `receive_id_type`, `msg_type`, `content` | 无 |
| `im_list_messages` | 获取聊天历史 | `container_id` | `container_id_type`(chat/thread,默认 chat), `start_time`, `end_time`, `sort_type`, `page_size`, `page_token` |
| `im_list_chats` | 获取用户/机器人群聊列表 | 无 | `page_size`, `page_token`, `sort_type` |
| `im_create_chat` | 创建群聊 | 无 | `name`, `description`, `chat_type`(private/public), `user_id_list`, `owner_id` |
| `im_get_chat_members` | 获取群成员 | `chat_id` | `page_size`, `page_token` |
| `contact_batch_get_user_id` | 批量通过邮箱/手机号查用户 ID | 无 | `emails`(每项 string, 最多 50), `mobiles`(每项 string, 最多 50) |
### 权限与删除
| 工具 | 用途 | 必填参数 | 可选参数 |
| --- | --- | --- | --- |
| `drive_add_permission` | 为云文档添加协作者权限 | `token`, `type`, `member_id`, `member_type`, `perm` | 无 |
| `wiki_delete_node` | 将 wiki 节点移出到云空间根目录(第一步);之后用 `drive_delete_file` 彻底删除(飞书无公开 wiki 删除 API) | `space_id`, `node_token`(wiki node token,非 obj_token) | 无 |
| `drive_upload_file` | **🆕** 上传文件到云空间(base64),获取 `file_token` 用于插入图片等 | `file_name`, `base64` | `parent_type`(默认 explorer), `parent_node` |
| `drive_delete_file` | 删除云空间文件(移至回收站) | `file_token`, `type` | 无 |
### 说明
- `fields`(Bitable 相关)通常使用字段名/系统键映射值;建议先用 `bitable_list_fields` 明确 schema 后再写入。
- `im_send_message` 的 `content` 按对应 `msg_type` 要求传入 JSON 字符串。
- `doc_import`:先上传 md 文件获取 `file_token`,再创建导入任务转换为 docx,轮询等待最多 30 秒。v1.3 新增 `space_id` + `parent_wiki_token` 参数,导入后可自动移入知识库。
- `wiki_create_node_with_markdown`:一步到位创建带内容的 wiki 文档。内部自动完成:上传 Markdown → 转换为 docx → 移入知识库。适合 AI Agent 快速创建结构化文档。
- `doc_create_blocks`:v1.3 新增客户端参数校验,block_type 与字段名不匹配时会返回明确错误提示(如 `block_type=4 需要字段 "heading2"`),避免飞书 API 返回笼统的 `invalid param`。支持的 block_type:2=text, 3-9=heading1-7, 11=bullet, 12=ordered, 14=code, 15=quote, 22=divider, 27=image, 31=table, 34=callout。
- `drive_upload_file`:上传 base64 编码的文件到云空间,返回 `file_token`,可配合 `doc_create_blocks` 的 image block(block_type=27)在文档中插入图片。
- `wiki_delete_node`:飞书无公开 wiki 删除 API。本工具将节点移出 wiki 至云空间根目录(step1),之后需通过 `drive_delete_file` 删除底层文件(step2)。需要 wiki node token,可从 `wiki_list_nodes` 返回的 `node_token` 字段获取。
## 五、安全与生产部署
### 最小可运行参数清单
### 启动参数(必备)
- `--app-id`:飞书应用 ID(必填,可用 `FEISHU_APP_ID` 环境变量代替)
- `--app-secret`:飞书应用 Secret(必填,可用 `FEISHU_APP_SECRET` 代替)
- `--oauth`:启动浏览器 OAuth 授权模式(可选)
- `--port`:OAuth 回调端口(可选,默认 `3001`)
- `--user-token`:预置用户 access token,跳过浏览器授权(可选,可用 `FEISHU_USER_TOKEN` 代替)
- `--refresh-token`:预置 refresh token,token 过期时自动刷新(可选,可用 `FEISHU_REFRESH_TOKEN` 代替)
### 推荐环境变量
- `FEISHU_APP_ID`
- `FEISHU_APP_SECRET`
- `FEISHU_USER_TOKEN`(预置模式,无需浏览器)
- `FEISHU_REFRESH_TOKEN`(配合 user token 自动续期)
- `FEISHU_OAUTH=true/false`(已废弃,建议改用 user token 模式)
#### 示例 `.env`
```bash
FEISHU_APP_ID=cli_xxx
FEISHU_APP_SECRET=secret_xxx
FEISHU_OAUTH=true
FEISHU_MCP_PORT=3001
```
#### 示例启动脚本(避免在命令行直接暴露明文)
```bash
set -a
source .env
set +a
if [ "${FEISHU_OAUTH}" = "true" ]; then
feishu-wiki-mcp --app-id "$FEISHU_APP_ID" --app-secret "$FEISHU_APP_SECRET" --oauth --port "${FEISHU_MCP_PORT:-3001}"
else
feishu-wiki-mcp --app-id "$FEISHU_APP_ID" --app-secret "$FEISHU_APP_SECRET"
fi
```
### 版本与发布一致性
- 当前代码版本:`1.3.1`(`package.json` 中 `version`)
- MCP 运行主文件:`build/index.js`
- 发布示例(建议保持一致):
```bash
npm version patch # 或 npm version 1.0.7
npm run build # 确保生成 build/index.js
npm publish --access public
# 标签建议与版本一致
git tag v1.0.7
git push --tags
```
### 安全与生产环境建议
#### 端口访问控制
- OAuth 回调默认地址固定为 `http://localhost:${port}/callback`(当前实现不支持自定义 callback host/path)。
- 生产部署中建议只对内网开放 `3001`,并通过反向代理对外暴露时加 IP 白名单/鉴权。
- 避免将该端口放到公开网段;如需公网访问,建议使用 VPN 或 SSH 隧道到内网服务端。
#### token 文件权限
- 用户 token 缓存在 `~/.feishu-wiki-mcp-token.json`。
- 建议设置严格权限:
```bash
chmod 600 ~/.feishu-wiki-mcp-token.json
chown "$USER" ~/.feishu-wiki-mcp-token.json
```
- 建议使用独立运行用户,避免多人共享 HOME 目录。
- 需要强制重新登录时,删除该文件可清除会话缓存。
#### 日志脱敏
- 运行时禁止在 shell 中开启 `set -x`,避免把 `APP_SECRET` 打印到日志。
- 当前日志仅输出错误描述,不应泄露 token 明文;如你接入统一日志系统,请开启敏感字段脱敏(如 `app_secret`、`token`)。
#### 回调地址与 HTTPS 要求
- 本地开发/单机场景:`http://localhost:<port>/callback` 是可用的。
- 生产场景若通过反向代理对外网开放,建议使用 HTTPS 并把代理层回调地址映射为该本机回调,同时在飞书应用配置中放行对应可访问域名。
- 若需自定义公网 callback(非 localhost),需修改 `doOAuthFlow` 中 `redirectUri` 逻辑并重新构建发布。
## 六、发布(如需维护 npm)
```bash
npm version patch # 或指定版本号
npm login --registry https://registry.npmjs.org
npm publish --access public
git tag v1.0.7
git push --tags
```
## 七、故障排查
- `feishu-wiki-mcp` 命令未找到:先确认全局安装成功,`npm bin -g` 在 `PATH`
- 启动报 token 错误:检查 APP_ID / APP_SECRET 是否正确、应用是否开通对应权限
- OAuth 首次无效:检查 callback URL 是否可达、端口放行是否正常、浏览器可打开授权链接
- Token 缓存文件:`~/.feishu-wiki-mcp-token.json`(每个用户一份,按需清理可强制重新登录)
## 八、当前版本行为边界
- 当前实现基于 `@modelcontextprotocol/sdk` 的 stdio transport,适配本地/远程 MCP 客户端调用
- 已实现 36 个工具,按需在服务端扩展后可追加
## 九、Changelog
### v1.3.0
- **新增 `wiki_create_node_with_markdown`**:一步到位在知识库中创建带 Markdown 内容的文档节点。内部自动完成:上传 Markdown → 转换为 docx → 移入知识库指定位置。AI Agent 只需一次调用即可完成之前需要 3 步(create_node → list_blocks → create_blocks)的操作。
- **新增 `drive_upload_file`**:支持 base64 编码文件上传到飞书云空间,返回 `file_token`,可用于在文档中插入图片等场景。
- **增强 `doc_import`**:新增 `space_id` + `parent_wiki_token` 可选参数,导入 Markdown 后自动将文档移入知识库,省去手动调用 `wiki_move_docs_to_wiki`。
- **增强 `doc_create_blocks`**:
- 补全所有 block_type 文档:新增 11=bullet、12=ordered、15=quote、22=divider 等类型的完整 JSON 示例
- 新增客户端参数校验:block_type 与字段名不匹配时返回明确错误提示(如 `block_type=4 需要字段 "heading2"`),不再依赖飞书 API 笼统的 `invalid param` 错误
### v1.2.0
- **bugfix `doc_import`**:修复创建空文档的问题。现在正确实现三步流程:① 上传 md 文件获取 `file_token` → ② 创建导入任务(md→docx)→ ③ 轮询等待,内容完整导入。
- **bugfix `wiki_delete_node`**:飞书无公开 wiki 删除端点(DELETE 返回 404)。改为两步删除工作流:本工具先将节点移出 wiki 至云空间根目录,再配合 `drive_delete_file` 彻底删除底层文件。
### v1.1.0
- 新增 5 个 Docx Blocks 操作工具:`doc_list_blocks`、`doc_get_block`、`doc_create_blocks`、`doc_update_block`、`doc_delete_blocks`,支持对飞书文档内容的完整 CRUD
- 新增 `wiki_delete_node`、`drive_delete_file` 删除工具
- OAuth 改进:支持 `--user-token` / `--refresh-token` 参数和 `FEISHU_USER_TOKEN` / `FEISHU_REFRESH_TOKEN` 环境变量,第三方 MCP 客户端无需浏览器即可授权
- 环境变量支持 `FEISHU_APP_ID` / `FEISHU_APP_SECRET`
### v1.0.7
- 初始版本,27 个工具(Wiki、Bitable、IM、权限)
TDQS
Scored across 36 tools
Most tools have distinct domain+resource targets, but wiki_create_node_with_markdown and doc_import overlap significantly (both import Markdown to wiki), and wiki_create_node vs wiki_create_node_with_markdown could confuse. The detailed descriptions help, but some boundary ambiguity remains.
All tools follow a consistent domain_verb_noun pattern in snake_case (e.g., bitable_create_app, wiki_list_nodes, im_send_message). Even longer names like wiki_move_docs_to_wiki retain the predictable prefix structure, with no mixed conventions.
With 36 tools, the set is heavy and exceeds the 25-tool threshold for appropriate count. The server is named wiki-mcp but includes many unrelated tools for IM, contacts, and bitable, making it feel over-scoped and broad rather than focused.
The core wiki lifecycle is well covered (list, get, create, move, copy, update title, delete), and document block operations add depth. However, there are notable gaps: no bitable delete record, no wiki node content update beyond title, and no full-document replacement, leaving some workflows incomplete.