UNPKG

feishu-mcp

Version:

Model Context Protocol server for Feishu integration

135 lines (134 loc) 6.55 kB
import { Logger } from '../../utils/logger.js'; import { FeishuBaseApiService } from './FeishuBaseApiService.js'; /** * 飞书知识库(Wiki)服务 * 负责知识空间及节点的查询与创建 */ export class FeishuWikiService extends FeishuBaseApiService { constructor(authService) { super(authService); } /** * 获取当前用户可见的所有知识空间列表,自动处理分页直到获取全部数据 * @param pageSize 每次分页请求的数量,默认 20 * @returns 知识空间对象数组,每项包含 space_id、name、description 等字段 */ async getAllWikiSpacesList(pageSize = 20) { try { Logger.info(`开始获取所有知识空间列表,每页数量: ${pageSize}`); const endpoint = '/wiki/v2/spaces'; let allItems = []; let pageToken = undefined; let hasMore = true; while (hasMore) { const params = { page_size: pageSize }; if (pageToken) params.page_token = pageToken; Logger.debug(`请求知识空间列表,page_token: ${pageToken || 'null'}, page_size: ${pageSize}`); const response = await this.get(endpoint, params); if (response?.items) { allItems = [...allItems, ...response.items]; hasMore = response.has_more || false; pageToken = response.page_token; Logger.debug(`当前页获取到 ${response.items.length} 个知识空间,累计 ${allItems.length} 个,hasMore: ${hasMore}`); } else { hasMore = false; Logger.warn('知识空间列表响应格式异常:', JSON.stringify(response, null, 2)); } } Logger.info(`知识空间列表获取完成,共 ${allItems.length} 个空间`); return allItems; } catch (error) { this.handleApiError(error, '获取知识空间列表失败'); } } /** * 获取指定知识空间下的所有子节点,自动处理分页直到获取全部数据 * @param spaceId 知识空间 ID * @param parentNodeToken 父节点 Token,不传则获取根节点下的直属子节点 * @param pageSize 每次分页请求的数量,默认 20 * @returns 节点对象数组,每项包含 node_token、obj_token、title、obj_type 等字段 */ async getAllWikiSpaceNodes(spaceId, parentNodeToken, pageSize = 20) { try { Logger.info(`开始获取知识空间子节点列表,space_id: ${spaceId}, parent_node_token: ${parentNodeToken || 'null'}`); const endpoint = `/wiki/v2/spaces/${spaceId}/nodes`; let allItems = []; let pageToken = undefined; let hasMore = true; while (hasMore) { const params = { page_size: pageSize }; if (parentNodeToken) params.parent_node_token = parentNodeToken; if (pageToken) params.page_token = pageToken; Logger.debug(`请求知识空间子节点列表,page_token: ${pageToken || 'null'}`); const response = await this.get(endpoint, params); if (response?.items) { allItems = [...allItems, ...response.items]; hasMore = response.has_more || false; pageToken = response.page_token; Logger.debug(`当前页获取到 ${response.items.length} 个子节点,累计 ${allItems.length} 个,hasMore: ${hasMore}`); } else { hasMore = false; Logger.warn('知识空间子节点列表响应格式异常:', JSON.stringify(response, null, 2)); } } Logger.info(`知识空间子节点列表获取完成,共 ${allItems.length} 个节点`); return allItems; } catch (error) { this.handleApiError(error, '获取知识空间子节点列表失败'); } } /** * 获取指定知识空间的详细信息 * 当 spaceId 传入 'my_library' 时,获取当前用户的"我的知识库"信息 * @param spaceId 知识空间 ID,或传入 'my_library' 获取个人知识库 * @param lang 语言参数,仅当 spaceId 为 'my_library' 时有效,默认 'en' * @returns 知识空间信息对象,包含 space_id、name、description 等字段 */ async getWikiSpaceInfo(spaceId, lang = 'en') { try { const params = {}; if (spaceId === 'my_library') params.lang = lang; const response = await this.get(`/wiki/v2/spaces/${spaceId}`, params); Logger.debug(`获取知识空间信息成功 (space_id: ${spaceId}):`, response); return response?.space || response; } catch (error) { this.handleApiError(error, `获取知识空间信息失败 (space_id: ${spaceId})`); } } /** * 在知识空间中创建一个新的文档节点(类型固定为 docx) * @param spaceId 目标知识空间 ID * @param title 节点标题 * @param parentNodeToken 父节点 Token,不传则在根目录下创建 * @returns 创建的节点信息,包含 node_token(节点 ID)和 obj_token(关联文档 ID) */ async createWikiSpaceNode(spaceId, title, parentNodeToken) { try { Logger.info(`开始创建知识空间节点,space_id: ${spaceId}, title: ${title}, parent_node_token: ${parentNodeToken || 'null(根节点)'}`); const endpoint = `/wiki/v2/spaces/${spaceId}/nodes`; const payload = { title, obj_type: 'docx', node_type: 'origin' }; if (parentNodeToken) payload.parent_node_token = parentNodeToken; const response = await this.post(endpoint, payload); if (response?.data?.node) { const node = response.data.node; Logger.info(`知识空间节点创建成功,node_token: ${node.node_token}, obj_token: ${node.obj_token}`); return node; } Logger.info('知识空间节点创建成功'); return response; } catch (error) { this.handleApiError(error, '创建知识空间节点失败'); } } }