@dasaying/feishu-doc-mcp 1.0.0 → 1.1.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.
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ import { InMemoryTaskMessageQueue, InMemoryTaskStore, isTerminal } from '@modelc
21
21
  import '@modelcontextprotocol/sdk/server/auth/errors.js';
22
22
  import { Hono } from 'hono';
23
23
  import { cors } from 'hono/cors';
24
- import * as z17 from 'zod/v4';
24
+ import * as z18 from 'zod/v4';
25
25
  import '@modelcontextprotocol/sdk/shared/auth.js';
26
26
  import 'hono/bearer-auth';
27
27
  import { ErrorCode, JSONRPCMessageSchema, isInitializeRequest, isJSONRPCRequest, DEFAULT_NEGOTIATED_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, isJSONRPCResultResponse, isJSONRPCErrorResponse } from '@modelcontextprotocol/sdk/types.js';
@@ -47,7 +47,7 @@ var __decorateParam = (index, decorator) => (target, key) => decorator(target, k
47
47
  // package.json
48
48
  var package_default = {
49
49
  name: "@dasaying/feishu-doc-mcp",
50
- version: "1.0.0",
50
+ version: "1.1.0",
51
51
  description: "\u98DE\u4E66\u4E91\u6587\u6863 MCP \u670D\u52A1\u5668 - \u652F\u6301 Markdown \u6587\u6863\u4E0A\u4F20\u3001\u8BFB\u53D6\u548C\u6279\u91CF\u64CD\u4F5C\u3002Feishu (Lark) Document MCP Server - Support Markdown upload, read and batch operations."};
52
52
  var JsonRpcErrorCode = /* @__PURE__ */ ((JsonRpcErrorCode2) => {
53
53
  JsonRpcErrorCode2[JsonRpcErrorCode2["ParseError"] = -32700] = "ParseError";
@@ -3918,6 +3918,7 @@ var FileSystemProvider = class {
3918
3918
  }
3919
3919
  getTenantPath(tenantId) {
3920
3920
  const sanitizedTenantId = sanitization.sanitizePath(tenantId, {
3921
+ rootDir: this.storagePath,
3921
3922
  toPosix: true
3922
3923
  }).sanitizedPath;
3923
3924
  if (sanitizedTenantId.includes("/") || sanitizedTenantId.includes("..")) {
@@ -6197,7 +6198,7 @@ var FEISHU_CONFIG = {
6197
6198
  TOKEN_URL: "https://open.feishu.cn/open-apis/authen/v2/oauth/token",
6198
6199
  REFRESH_TOKEN_URL: "https://open.feishu.cn/open-apis/authen/v2/oauth/token",
6199
6200
  // API 权限范围(包含 offline_access 以支持 refresh_token)
6200
- SCOPES: "contact:user.base:readonly docx:document wiki:wiki drive:drive offline_access",
6201
+ SCOPES: "contact:user.base:readonly docx:document wiki:wiki drive:drive bitable:app offline_access",
6201
6202
  // 文件上传相关(使用素材上传 API,导入后自动删除源文件)
6202
6203
  UPLOAD_URL: "https://open.feishu.cn/open-apis/drive/v1/medias/upload_all",
6203
6204
  // 文档创建相关
@@ -6311,7 +6312,7 @@ var FeishuService = class {
6311
6312
  this.storage = storage;
6312
6313
  }
6313
6314
  /** createContext method 创建请求上下文. */
6314
- createContext(operation, tenantId = "feishu-service") {
6315
+ createContext(operation, tenantId = "feishu_service") {
6315
6316
  const context = requestContextService.createRequestContext({
6316
6317
  operation,
6317
6318
  tenantId
@@ -6943,12 +6944,14 @@ var FeishuService = class {
6943
6944
  const content = await this.apiProvider.getDocumentContent(
6944
6945
  auth.accessToken,
6945
6946
  documentId,
6946
- options.documentType
6947
+ options.documentType,
6948
+ options.wikiSpaceId
6947
6949
  );
6948
6950
  const metadata = await this.apiProvider.getDocumentMetadata(
6949
6951
  auth.accessToken,
6950
6952
  documentId,
6951
- options.documentType
6953
+ options.documentType,
6954
+ options.wikiSpaceId
6952
6955
  );
6953
6956
  const conversionResult = this.convertToMarkdown(content, options);
6954
6957
  let downloadedImages = 0;
@@ -6980,7 +6983,7 @@ var FeishuService = class {
6980
6983
  downloadedImages,
6981
6984
  downloadedAttachments
6982
6985
  };
6983
- if (outputFile) result.outputFile = outputFile;
6986
+ if (outputFile !== void 0) result.outputFile = outputFile;
6984
6987
  return result;
6985
6988
  } catch (error) {
6986
6989
  logger.error(
@@ -7051,6 +7054,157 @@ var FeishuService = class {
7051
7054
  results
7052
7055
  };
7053
7056
  }
7057
+ /**
7058
+ * readBitable method 读取多维表格.
7059
+ */
7060
+ async readBitable(bitableToken, options, context) {
7061
+ logger.info("\u8BFB\u53D6\u591A\u7EF4\u8868\u683C", { ...context, bitableToken, options });
7062
+ try {
7063
+ const finalAppId = options.appId || FEISHU_CONFIG.DEFAULT_APP_ID;
7064
+ if (!finalAppId) {
7065
+ throw new McpError(-32602 /* InvalidParams */, "\u672A\u914D\u7F6E\u5E94\u7528 ID");
7066
+ }
7067
+ const auth = await this.getAuth(finalAppId, context);
7068
+ if (!auth) {
7069
+ throw new McpError(
7070
+ -32602 /* InvalidParams */,
7071
+ "\u672A\u627E\u5230\u6709\u6548\u7684\u8BA4\u8BC1\u4FE1\u606F"
7072
+ );
7073
+ }
7074
+ const validAuth = await this.ensureValidToken(auth, context);
7075
+ const metadata = await this.apiProvider.getBitableMetadata(
7076
+ validAuth.accessToken,
7077
+ bitableToken
7078
+ );
7079
+ const tables = await this.apiProvider.getBitableTables(
7080
+ validAuth.accessToken,
7081
+ bitableToken
7082
+ );
7083
+ const tableResults = [];
7084
+ for (const table of tables) {
7085
+ const fields = await this.apiProvider.getBitableFields(
7086
+ validAuth.accessToken,
7087
+ bitableToken,
7088
+ table.tableId
7089
+ );
7090
+ const allRecords = [];
7091
+ let pageToken;
7092
+ let hasMore = true;
7093
+ while (hasMore) {
7094
+ const recordsResult = await this.apiProvider.getBitableRecords(
7095
+ validAuth.accessToken,
7096
+ bitableToken,
7097
+ table.tableId,
7098
+ 100,
7099
+ pageToken
7100
+ );
7101
+ allRecords.push(...recordsResult.records);
7102
+ hasMore = recordsResult.hasMore;
7103
+ pageToken = recordsResult.pageToken;
7104
+ }
7105
+ let markdown2 = "";
7106
+ if (options.outputFormat === "markdown" || !options.outputFormat) {
7107
+ markdown2 = this.convertBitableToMarkdown(
7108
+ table.name,
7109
+ fields,
7110
+ allRecords
7111
+ );
7112
+ }
7113
+ tableResults.push({
7114
+ tableId: table.tableId,
7115
+ name: table.name,
7116
+ markdown: markdown2,
7117
+ records: allRecords
7118
+ });
7119
+ }
7120
+ let fullMarkdown = "";
7121
+ if (options.outputFormat === "markdown" || !options.outputFormat) {
7122
+ fullMarkdown = `# ${metadata.name}
7123
+
7124
+ `;
7125
+ for (const table of tableResults) {
7126
+ fullMarkdown += table.markdown + "\n\n";
7127
+ }
7128
+ }
7129
+ logger.info("\u591A\u7EF4\u8868\u683C\u8BFB\u53D6\u6210\u529F", {
7130
+ ...context,
7131
+ bitableToken,
7132
+ name: metadata.name,
7133
+ tableCount: tables.length
7134
+ });
7135
+ return {
7136
+ success: true,
7137
+ bitableToken,
7138
+ name: metadata.name,
7139
+ content: fullMarkdown,
7140
+ tables: tableResults
7141
+ };
7142
+ } catch (error) {
7143
+ logger.error(
7144
+ "\u8BFB\u53D6\u591A\u7EF4\u8868\u683C\u5931\u8D25",
7145
+ error instanceof Error ? error : new Error(String(error)),
7146
+ context
7147
+ );
7148
+ return {
7149
+ success: false,
7150
+ bitableToken,
7151
+ error: error instanceof Error ? error.message : String(error)
7152
+ };
7153
+ }
7154
+ }
7155
+ /**
7156
+ * convertBitableToMarkdown method 将多维表格转换为 Markdown.
7157
+ */
7158
+ convertBitableToMarkdown(tableName, fields, records) {
7159
+ if (records.length === 0) {
7160
+ return `## ${tableName}
7161
+
7162
+ *\uFF08\u7A7A\u8868\u683C\uFF09*
7163
+ `;
7164
+ }
7165
+ let markdown2 = `## ${tableName}
7166
+
7167
+ `;
7168
+ const headers = fields.map((f) => f.fieldName);
7169
+ markdown2 += "| " + headers.join(" | ") + " |\n";
7170
+ markdown2 += "| " + headers.map(() => "---").join(" | ") + " |\n";
7171
+ for (const record of records) {
7172
+ const row = fields.map((field) => {
7173
+ const value = record.fields[field.fieldName];
7174
+ if (value === null || value === void 0) {
7175
+ return "";
7176
+ }
7177
+ if (Array.isArray(value)) {
7178
+ return value.map((v) => this.formatCellValue(v)).join(", ");
7179
+ }
7180
+ return this.formatCellValue(value);
7181
+ });
7182
+ markdown2 += "| " + row.join(" | ") + " |\n";
7183
+ }
7184
+ return markdown2;
7185
+ }
7186
+ /**
7187
+ * formatCellValue method 格式化单元格值.
7188
+ */
7189
+ formatCellValue(value) {
7190
+ if (value === null || value === void 0) {
7191
+ return "";
7192
+ }
7193
+ if (typeof value === "object") {
7194
+ if ("text" in value && typeof value.text === "string") {
7195
+ return value.text;
7196
+ }
7197
+ if ("name" in value && typeof value.name === "string") {
7198
+ return value.name;
7199
+ }
7200
+ if ("link" in value && typeof value.link === "string") {
7201
+ return value.link;
7202
+ }
7203
+ return JSON.stringify(value);
7204
+ }
7205
+ const primitiveValue = value;
7206
+ return String(primitiveValue).replace(/\|/g, "\\|").replace(/\n/g, " ");
7207
+ }
7054
7208
  /**
7055
7209
  * readWikiRecursive method 递归读取知识库.
7056
7210
  */
@@ -7165,6 +7319,9 @@ var FeishuService = class {
7165
7319
  async downloadResources(resources, options, accessToken) {
7166
7320
  let images = 0;
7167
7321
  let attachments = 0;
7322
+ if (!options.downloadImages && !options.downloadAttachments) {
7323
+ return { images, attachments };
7324
+ }
7168
7325
  for (const resource of resources) {
7169
7326
  if (resource.type === "image" && options.downloadImages) {
7170
7327
  const savePath = `${options.assetsPath ?? "./assets"}/${resource.fileToken}`;
@@ -7917,7 +8074,7 @@ var FeishuApiProvider = class {
7917
8074
  async createDocument(accessToken, title, content, targetType, targetId, parentNodeToken) {
7918
8075
  const ctx = requestContextService.createRequestContext({
7919
8076
  operation: "feishu.createDocument",
7920
- tenantId: "feishu-service"
8077
+ tenantId: "feishu_service"
7921
8078
  });
7922
8079
  logger.info("\u5F00\u59CB\u521B\u5EFA\u98DE\u4E66\u6587\u6863", {
7923
8080
  ...ctx,
@@ -8251,6 +8408,140 @@ var FeishuApiProvider = class {
8251
8408
  return result;
8252
8409
  });
8253
8410
  }
8411
+ /**
8412
+ * getBitableMetadata method 获取多维表格元数据.
8413
+ */
8414
+ async getBitableMetadata(accessToken, bitableToken) {
8415
+ const ctx = requestContextService.createRequestContext({
8416
+ operation: "feishu.getBitableMetadata",
8417
+ tenantId: "feishu_service"
8418
+ });
8419
+ logger.info("\u83B7\u53D6\u591A\u7EF4\u8868\u683C\u5143\u6570\u636E", { ...ctx, bitableToken });
8420
+ try {
8421
+ const url2 = `${FEISHU_CONFIG.BASE_URL}/bitable/v1/apps/${bitableToken}`;
8422
+ const response = await this.requestWithAuth(url2, accessToken, { method: "GET" });
8423
+ if (response.code !== 0 || !response.data) {
8424
+ throw new McpError(
8425
+ -32603 /* InternalError */,
8426
+ response.msg ?? "\u83B7\u53D6\u591A\u7EF4\u8868\u683C\u5143\u6570\u636E\u5931\u8D25"
8427
+ );
8428
+ }
8429
+ return {
8430
+ name: response.data.app.name,
8431
+ revision: response.data.app.revision,
8432
+ isAdvanced: response.data.app.is_advanced
8433
+ };
8434
+ } catch (error) {
8435
+ logger.error("\u83B7\u53D6\u591A\u7EF4\u8868\u683C\u5143\u6570\u636E\u5931\u8D25", error instanceof Error ? error : new Error(String(error)), ctx);
8436
+ throw error instanceof McpError ? error : new McpError(
8437
+ -32603 /* InternalError */,
8438
+ `\u83B7\u53D6\u591A\u7EF4\u8868\u683C\u5143\u6570\u636E\u5931\u8D25: ${String(error)}`
8439
+ );
8440
+ }
8441
+ }
8442
+ /**
8443
+ * getBitableTables method 获取多维表格的所有数据表.
8444
+ */
8445
+ async getBitableTables(accessToken, bitableToken) {
8446
+ const ctx = requestContextService.createRequestContext({
8447
+ operation: "feishu.getBitableTables",
8448
+ tenantId: "feishu_service"
8449
+ });
8450
+ logger.info("\u83B7\u53D6\u591A\u7EF4\u8868\u683C\u6570\u636E\u8868\u5217\u8868", { ...ctx, bitableToken });
8451
+ try {
8452
+ const url2 = `${FEISHU_CONFIG.BASE_URL}/bitable/v1/apps/${bitableToken}/tables?page_size=100`;
8453
+ const response = await this.requestWithAuth(url2, accessToken, { method: "GET" });
8454
+ if (response.code !== 0 || !response.data) {
8455
+ throw new McpError(
8456
+ -32603 /* InternalError */,
8457
+ response.msg ?? "\u83B7\u53D6\u6570\u636E\u8868\u5217\u8868\u5931\u8D25"
8458
+ );
8459
+ }
8460
+ return response.data.items.map((table) => ({
8461
+ tableId: table.table_id,
8462
+ name: table.name,
8463
+ revision: table.revision
8464
+ }));
8465
+ } catch (error) {
8466
+ logger.error("\u83B7\u53D6\u6570\u636E\u8868\u5217\u8868\u5931\u8D25", error instanceof Error ? error : new Error(String(error)), ctx);
8467
+ throw error instanceof McpError ? error : new McpError(
8468
+ -32603 /* InternalError */,
8469
+ `\u83B7\u53D6\u6570\u636E\u8868\u5217\u8868\u5931\u8D25: ${String(error)}`
8470
+ );
8471
+ }
8472
+ }
8473
+ /**
8474
+ * getBitableFields method 获取数据表的字段信息.
8475
+ */
8476
+ async getBitableFields(accessToken, bitableToken, tableId) {
8477
+ const ctx = requestContextService.createRequestContext({
8478
+ operation: "feishu.getBitableFields",
8479
+ tenantId: "feishu_service"
8480
+ });
8481
+ logger.info("\u83B7\u53D6\u6570\u636E\u8868\u5B57\u6BB5", { ...ctx, bitableToken, tableId });
8482
+ try {
8483
+ const url2 = `${FEISHU_CONFIG.BASE_URL}/bitable/v1/apps/${bitableToken}/tables/${tableId}/fields?page_size=100`;
8484
+ const response = await this.requestWithAuth(url2, accessToken, { method: "GET" });
8485
+ if (response.code !== 0 || !response.data) {
8486
+ throw new McpError(
8487
+ -32603 /* InternalError */,
8488
+ response.msg ?? "\u83B7\u53D6\u5B57\u6BB5\u4FE1\u606F\u5931\u8D25"
8489
+ );
8490
+ }
8491
+ return response.data.items.map((field) => ({
8492
+ fieldId: field.field_id,
8493
+ fieldName: field.field_name,
8494
+ type: field.type,
8495
+ property: field.property
8496
+ }));
8497
+ } catch (error) {
8498
+ logger.error("\u83B7\u53D6\u5B57\u6BB5\u4FE1\u606F\u5931\u8D25", error instanceof Error ? error : new Error(String(error)), ctx);
8499
+ throw error instanceof McpError ? error : new McpError(
8500
+ -32603 /* InternalError */,
8501
+ `\u83B7\u53D6\u5B57\u6BB5\u4FE1\u606F\u5931\u8D25: ${String(error)}`
8502
+ );
8503
+ }
8504
+ }
8505
+ /**
8506
+ * getBitableRecords method 获取数据表的记录.
8507
+ */
8508
+ async getBitableRecords(accessToken, bitableToken, tableId, pageSize = 100, pageToken) {
8509
+ const ctx = requestContextService.createRequestContext({
8510
+ operation: "feishu.getBitableRecords",
8511
+ tenantId: "feishu_service"
8512
+ });
8513
+ logger.info("\u83B7\u53D6\u6570\u636E\u8868\u8BB0\u5F55", { ...ctx, bitableToken, tableId, pageSize });
8514
+ try {
8515
+ let url2 = `${FEISHU_CONFIG.BASE_URL}/bitable/v1/apps/${bitableToken}/tables/${tableId}/records?page_size=${pageSize}`;
8516
+ if (pageToken) {
8517
+ url2 += `&page_token=${pageToken}`;
8518
+ }
8519
+ const response = await this.requestWithAuth(url2, accessToken, { method: "GET" });
8520
+ if (response.code !== 0 || !response.data) {
8521
+ throw new McpError(
8522
+ -32603 /* InternalError */,
8523
+ response.msg ?? "\u83B7\u53D6\u8BB0\u5F55\u5931\u8D25"
8524
+ );
8525
+ }
8526
+ const result = {
8527
+ records: response.data.items.map((record) => ({
8528
+ recordId: record.record_id,
8529
+ fields: record.fields
8530
+ })),
8531
+ hasMore: response.data.has_more
8532
+ };
8533
+ if (response.data.page_token) {
8534
+ result.pageToken = response.data.page_token;
8535
+ }
8536
+ return result;
8537
+ } catch (error) {
8538
+ logger.error("\u83B7\u53D6\u8BB0\u5F55\u5931\u8D25", error instanceof Error ? error : new Error(String(error)), ctx);
8539
+ throw error instanceof McpError ? error : new McpError(
8540
+ -32603 /* InternalError */,
8541
+ `\u83B7\u53D6\u8BB0\u5F55\u5931\u8D25: ${String(error)}`
8542
+ );
8543
+ }
8544
+ }
8254
8545
  /**
8255
8546
  * healthCheck method 健康检查.
8256
8547
  */
@@ -8402,7 +8693,7 @@ var FeishuApiProvider = class {
8402
8693
  async uploadMarkdownFile(accessToken, fileName, content) {
8403
8694
  const ctx = requestContextService.createRequestContext({
8404
8695
  operation: "feishu.uploadMarkdownFile",
8405
- tenantId: "feishu-service"
8696
+ tenantId: "feishu_service"
8406
8697
  });
8407
8698
  try {
8408
8699
  logger.debug("\u5F00\u59CB\u4E0A\u4F20Markdown\u6587\u4EF6", {
@@ -8510,7 +8801,7 @@ var FeishuApiProvider = class {
8510
8801
  async createImportTask(accessToken, fileToken, title, targetFolderId) {
8511
8802
  const ctx = requestContextService.createRequestContext({
8512
8803
  operation: "feishu.createImportTask",
8513
- tenantId: "feishu-service"
8804
+ tenantId: "feishu_service"
8514
8805
  });
8515
8806
  try {
8516
8807
  const url2 = `${FEISHU_CONFIG.BASE_URL}/drive/v1/import_tasks`;
@@ -8590,7 +8881,7 @@ var FeishuApiProvider = class {
8590
8881
  const maxAttempts = 30;
8591
8882
  const ctx = requestContextService.createRequestContext({
8592
8883
  operation: "feishu.waitForImportCompletion",
8593
- tenantId: "feishu-service"
8884
+ tenantId: "feishu_service"
8594
8885
  });
8595
8886
  logger.info("\u5F00\u59CB\u7B49\u5F85\u5BFC\u5165\u4EFB\u52A1\u5B8C\u6210", {
8596
8887
  ...ctx,
@@ -8773,18 +9064,18 @@ var FeishuApiProvider = class {
8773
9064
  /**
8774
9065
  * getDocumentContent method 获取文档内容.
8775
9066
  */
8776
- async getDocumentContent(accessToken, documentId, documentType) {
9067
+ async getDocumentContent(accessToken, documentId, documentType, wikiSpaceId) {
8777
9068
  const ctx = requestContextService.createRequestContext({
8778
9069
  operation: "feishu.getDocumentContent",
8779
- tenantId: "feishu-service"
9070
+ tenantId: "feishu_service"
8780
9071
  });
8781
- logger.info("\u83B7\u53D6\u6587\u6863\u5185\u5BB9", { ...ctx, documentId, documentType });
9072
+ logger.info("\u83B7\u53D6\u6587\u6863\u5185\u5BB9", { ...ctx, documentId, documentType, wikiSpaceId });
8782
9073
  try {
8783
9074
  let url2;
8784
9075
  if (documentType === "drive") {
8785
9076
  url2 = `${FEISHU_CONFIG.BASE_URL}/docx/v1/documents/${documentId}/blocks`;
8786
9077
  } else {
8787
- url2 = `${FEISHU_CONFIG.BASE_URL}/wiki/v2/spaces/${documentId}/nodes`;
9078
+ url2 = `${FEISHU_CONFIG.BASE_URL}/docx/v1/documents/${documentId}/blocks`;
8788
9079
  }
8789
9080
  const response = await this.requestWithAuth(url2, accessToken, { method: "GET" });
8790
9081
  if (response.code !== 0 || !response.data) {
@@ -8794,6 +9085,16 @@ var FeishuApiProvider = class {
8794
9085
  );
8795
9086
  }
8796
9087
  const blocks = response.data.blocks ?? response.data.items ?? [];
9088
+ logger.debug("\u98DE\u4E66 API \u8FD4\u56DE\u7684 blocks \u6570\u636E", {
9089
+ ...ctx,
9090
+ blockCount: blocks.length,
9091
+ sampleBlocks: blocks.slice(0, 5).map((b) => ({
9092
+ block_id: b.block_id,
9093
+ block_type: b.block_type,
9094
+ keys: Object.keys(b),
9095
+ data: JSON.stringify(b).substring(0, 500)
9096
+ }))
9097
+ });
8797
9098
  return {
8798
9099
  documentId,
8799
9100
  title: "",
@@ -8820,19 +9121,14 @@ var FeishuApiProvider = class {
8820
9121
  /**
8821
9122
  * getDocumentMetadata method 获取文档元数据.
8822
9123
  */
8823
- async getDocumentMetadata(accessToken, documentId, documentType) {
9124
+ async getDocumentMetadata(accessToken, documentId, documentType, wikiSpaceId) {
8824
9125
  const ctx = requestContextService.createRequestContext({
8825
9126
  operation: "feishu.getDocumentMetadata",
8826
- tenantId: "feishu-service"
9127
+ tenantId: "feishu_service"
8827
9128
  });
8828
- logger.info("\u83B7\u53D6\u6587\u6863\u5143\u6570\u636E", { ...ctx, documentId, documentType });
9129
+ logger.info("\u83B7\u53D6\u6587\u6863\u5143\u6570\u636E", { ...ctx, documentId, documentType, wikiSpaceId });
8829
9130
  try {
8830
- let url2;
8831
- if (documentType === "drive") {
8832
- url2 = `${FEISHU_CONFIG.BASE_URL}/docx/v1/documents/${documentId}`;
8833
- } else {
8834
- url2 = `${FEISHU_CONFIG.BASE_URL}/wiki/v2/spaces/${documentId}`;
8835
- }
9131
+ const url2 = `${FEISHU_CONFIG.BASE_URL}/docx/v1/documents/${documentId}`;
8836
9132
  const response = await this.requestWithAuth(url2, accessToken, { method: "GET" });
8837
9133
  if (response.code !== 0 || !response.data) {
8838
9134
  throw new McpError(
@@ -8873,7 +9169,7 @@ var FeishuApiProvider = class {
8873
9169
  async downloadFile(accessToken, fileToken, savePath) {
8874
9170
  const ctx = requestContextService.createRequestContext({
8875
9171
  operation: "feishu.downloadFile",
8876
- tenantId: "feishu-service"
9172
+ tenantId: "feishu_service"
8877
9173
  });
8878
9174
  logger.info("\u4E0B\u8F7D\u6587\u4EF6", { ...ctx, fileToken, savePath });
8879
9175
  try {
@@ -9103,7 +9399,7 @@ var ContentConverterProvider = class {
9103
9399
  convert(content, _options) {
9104
9400
  const ctx = requestContextService.createRequestContext({
9105
9401
  operation: "contentConverter.convert",
9106
- tenantId: "feishu-service"
9402
+ tenantId: "feishu_service"
9107
9403
  });
9108
9404
  logger.info("\u5F00\u59CB\u8F6C\u6362\u6587\u6863\u5185\u5BB9", {
9109
9405
  ...ctx,
@@ -9188,6 +9484,13 @@ var ContentConverterProvider = class {
9188
9484
  const block = blockMap.get(blockId);
9189
9485
  if (!block) return "";
9190
9486
  const result = [];
9487
+ if (block.blockType === "table") {
9488
+ const tableMarkdown = this.convertTableWithCells(block, blockMap);
9489
+ if (tableMarkdown) {
9490
+ result.push(tableMarkdown);
9491
+ }
9492
+ return result.join("\n\n");
9493
+ }
9191
9494
  const markdown2 = this.convertBlock(block, depth);
9192
9495
  if (markdown2) {
9193
9496
  result.push(markdown2);
@@ -9247,12 +9550,14 @@ var ContentConverterProvider = class {
9247
9550
  return this.convertFileBlock(block);
9248
9551
  case "table":
9249
9552
  return this.convertTableBlock(block);
9553
+ case "table_cell":
9554
+ return this.convertTableCellBlock(block);
9250
9555
  case "page":
9251
9556
  return "";
9252
9557
  default:
9253
9558
  const ctx = requestContextService.createRequestContext({
9254
9559
  operation: "contentConverter.convertBlock",
9255
- tenantId: "feishu-service"
9560
+ tenantId: "feishu_service"
9256
9561
  });
9257
9562
  logger.warning("\u4E0D\u652F\u6301\u7684\u5757\u7C7B\u578B", {
9258
9563
  ...ctx,
@@ -9266,18 +9571,78 @@ var ContentConverterProvider = class {
9266
9571
  * extractText method 提取块中的文本内容.
9267
9572
  */
9268
9573
  extractText(block) {
9269
- if (!block.content?.text) return "";
9270
- return block.content.text.map((run2) => {
9271
- let text = run2.text;
9272
- if (run2.style) {
9273
- if (run2.style.bold) text = `**${text}**`;
9274
- if (run2.style.italic) text = `*${text}*`;
9275
- if (run2.style.strikethrough) text = `~~${text}~~`;
9276
- if (run2.style.inlineCode) text = `\`${text}\``;
9277
- if (run2.style.link) text = `[${text}](${run2.style.link.url})`;
9278
- }
9279
- return text;
9280
- }).join("");
9574
+ if (!block.content) return "";
9575
+ const blockContent = block.content;
9576
+ let elements;
9577
+ if (blockContent.page && typeof blockContent.page === "object") {
9578
+ elements = blockContent.page.elements;
9579
+ } else if (blockContent.heading1 && typeof blockContent.heading1 === "object") {
9580
+ elements = blockContent.heading1.elements;
9581
+ } else if (blockContent.heading2 && typeof blockContent.heading2 === "object") {
9582
+ elements = blockContent.heading2.elements;
9583
+ } else if (blockContent.heading3 && typeof blockContent.heading3 === "object") {
9584
+ elements = blockContent.heading3.elements;
9585
+ } else if (blockContent.heading4 && typeof blockContent.heading4 === "object") {
9586
+ elements = blockContent.heading4.elements;
9587
+ } else if (blockContent.heading5 && typeof blockContent.heading5 === "object") {
9588
+ elements = blockContent.heading5.elements;
9589
+ } else if (blockContent.heading6 && typeof blockContent.heading6 === "object") {
9590
+ elements = blockContent.heading6.elements;
9591
+ } else if (blockContent.heading7 && typeof blockContent.heading7 === "object") {
9592
+ elements = blockContent.heading7.elements;
9593
+ } else if (blockContent.heading8 && typeof blockContent.heading8 === "object") {
9594
+ elements = blockContent.heading8.elements;
9595
+ } else if (blockContent.heading9 && typeof blockContent.heading9 === "object") {
9596
+ elements = blockContent.heading9.elements;
9597
+ } else if (blockContent.text && typeof blockContent.text === "object") {
9598
+ elements = blockContent.text.elements;
9599
+ } else if (blockContent.bullet && typeof blockContent.bullet === "object") {
9600
+ elements = blockContent.bullet.elements;
9601
+ } else if (blockContent.ordered && typeof blockContent.ordered === "object") {
9602
+ elements = blockContent.ordered.elements;
9603
+ } else if (blockContent.code && typeof blockContent.code === "object") {
9604
+ elements = blockContent.code.elements;
9605
+ } else if (blockContent.quote && typeof blockContent.quote === "object") {
9606
+ elements = blockContent.quote.elements;
9607
+ } else if (blockContent.todo && typeof blockContent.todo === "object") {
9608
+ elements = blockContent.todo.elements;
9609
+ } else if (blockContent.callout && typeof blockContent.callout === "object") {
9610
+ elements = blockContent.callout.elements;
9611
+ } else if (blockContent.elements && Array.isArray(blockContent.elements)) {
9612
+ elements = blockContent.elements;
9613
+ }
9614
+ if (elements && Array.isArray(elements)) {
9615
+ return elements.map((element) => {
9616
+ if (!element.text_run?.content) return "";
9617
+ let text = element.text_run.content;
9618
+ const style = element.text_run.text_element_style;
9619
+ if (style) {
9620
+ if (style.bold) text = `**${text}**`;
9621
+ if (style.italic) text = `*${text}*`;
9622
+ if (style.strikethrough) text = `~~${text}~~`;
9623
+ if (style.inline_code) text = `\`${text}\``;
9624
+ if (style.link?.url) text = `[${text}](${style.link.url})`;
9625
+ }
9626
+ return text;
9627
+ }).join("");
9628
+ }
9629
+ if (blockContent.text && Array.isArray(blockContent.text)) {
9630
+ return blockContent.text.map((run2) => {
9631
+ let text = run2.text;
9632
+ if (run2.style) {
9633
+ if (run2.style.bold) text = `**${text}**`;
9634
+ if (run2.style.italic) text = `*${text}*`;
9635
+ if (run2.style.strikethrough) text = `~~${text}~~`;
9636
+ if (run2.style.inlineCode) text = `\`${text}\``;
9637
+ if (run2.style.link) text = `[${text}](${run2.style.link.url})`;
9638
+ }
9639
+ return text;
9640
+ }).join("");
9641
+ }
9642
+ if (typeof blockContent.text === "string") {
9643
+ return blockContent.text;
9644
+ }
9645
+ return "";
9281
9646
  }
9282
9647
  /**
9283
9648
  * convertCodeBlock method 转换代码块.
@@ -9328,13 +9693,74 @@ ${text}
9328
9693
  /**
9329
9694
  * convertTableBlock method 转换表格块.
9330
9695
  */
9331
- convertTableBlock(block) {
9332
- const ctx = requestContextService.createRequestContext({
9333
- operation: "contentConverter.convertTableBlock",
9334
- tenantId: "feishu-service"
9335
- });
9336
- logger.warning("\u8868\u683C\u8F6C\u6362\u6682\u672A\u5B8C\u5168\u5B9E\u73B0", { ...ctx, blockId: block.blockId });
9337
- return "<!-- Table content -->";
9696
+ convertTableBlock(_block) {
9697
+ return "";
9698
+ }
9699
+ /**
9700
+ * convertTableCellBlock method 转换表格单元格块.
9701
+ */
9702
+ convertTableCellBlock(block) {
9703
+ return this.extractText(block);
9704
+ }
9705
+ /**
9706
+ * convertTableWithCells method 转换表格及其所有单元格.
9707
+ */
9708
+ convertTableWithCells(tableBlock, blockMap) {
9709
+ if (!tableBlock.children || tableBlock.children.length === 0) {
9710
+ return "<!-- Empty table -->";
9711
+ }
9712
+ const tableContent = tableBlock.content;
9713
+ const rowSize = tableContent?.table?.property?.row_size ?? 0;
9714
+ const columnSize = tableContent?.table?.property?.column_size ?? 0;
9715
+ if (rowSize === 0 || columnSize === 0) {
9716
+ return "<!-- Invalid table -->";
9717
+ }
9718
+ const rows = [];
9719
+ for (let i = 0; i < rowSize; i++) {
9720
+ rows.push(new Array(columnSize).fill(""));
9721
+ }
9722
+ let cellIndex = 0;
9723
+ for (const cellId of tableBlock.children) {
9724
+ const cell = blockMap.get(cellId);
9725
+ if (!cell || cell.blockType !== "table_cell") continue;
9726
+ const rowIndex = Math.floor(cellIndex / columnSize);
9727
+ const columnIndex = cellIndex % columnSize;
9728
+ cellIndex++;
9729
+ if (rowIndex < rowSize && columnIndex < columnSize) {
9730
+ let cellText = "";
9731
+ if (cell.children && cell.children.length > 0) {
9732
+ const childTexts = [];
9733
+ for (const childId of cell.children) {
9734
+ const childBlock = blockMap.get(childId);
9735
+ if (childBlock) {
9736
+ const text = this.extractText(childBlock);
9737
+ if (text) {
9738
+ childTexts.push(text);
9739
+ }
9740
+ }
9741
+ }
9742
+ cellText = childTexts.join(" ");
9743
+ } else {
9744
+ cellText = this.extractText(cell);
9745
+ }
9746
+ if (rows[rowIndex] && columnIndex < columnSize) {
9747
+ rows[rowIndex][columnIndex] = cellText;
9748
+ }
9749
+ }
9750
+ }
9751
+ const lines = [];
9752
+ if (rows.length === 0 || !rows[0]) {
9753
+ return "<!-- Empty table -->";
9754
+ }
9755
+ lines.push("| " + rows[0].join(" | ") + " |");
9756
+ lines.push("| " + rows[0].map(() => "---").join(" | ") + " |");
9757
+ for (let i = 1; i < rows.length; i++) {
9758
+ const row = rows[i];
9759
+ if (row) {
9760
+ lines.push("| " + row.join(" | ") + " |");
9761
+ }
9762
+ }
9763
+ return lines.join("\n");
9338
9764
  }
9339
9765
  };
9340
9766
  ContentConverterProvider = __decorateClass([
@@ -9522,9 +9948,9 @@ ResourceRegistry = __decorateClass([
9522
9948
  injectable(),
9523
9949
  __decorateParam(0, injectAll(ResourceDefinitions, { isOptional: true }))
9524
9950
  ], ResourceRegistry);
9525
- var registerResources = (container25) => {
9951
+ var registerResources = (container26) => {
9526
9952
  for (const resource of allResourceDefinitions) {
9527
- container25.register(ResourceDefinitions, { useValue: resource });
9953
+ container26.register(ResourceDefinitions, { useValue: resource });
9528
9954
  }
9529
9955
  };
9530
9956
 
@@ -9759,7 +10185,7 @@ async function authCallbackLogic(input, appContext, _sdkContext) {
9759
10185
  try {
9760
10186
  const context = requestContextService.createRequestContext({
9761
10187
  operation: "feishu.handleAuthCallback",
9762
- tenantId: "feishu-service"
10188
+ tenantId: "feishu_service"
9763
10189
  });
9764
10190
  const result = await feishuService.handleAuthCallback(
9765
10191
  input.code,
@@ -9907,7 +10333,7 @@ async function uploadLogic(input, appContext, _sdkContext) {
9907
10333
  });
9908
10334
  const context = requestContextService.createRequestContext({
9909
10335
  operation: "feishu.uploadMarkdown",
9910
- tenantId: "feishu-service"
10336
+ tenantId: "feishu_service"
9911
10337
  });
9912
10338
  let content;
9913
10339
  let documentTitle = input.title;
@@ -10073,7 +10499,7 @@ async function updateLogic(input, appContext, _sdkContext) {
10073
10499
  });
10074
10500
  const context = requestContextService.createRequestContext({
10075
10501
  operation: "feishu.updateDocument",
10076
- tenantId: "feishu-service"
10502
+ tenantId: "feishu_service"
10077
10503
  });
10078
10504
  let content;
10079
10505
  let workingDirectory = input.workingDirectory;
@@ -10215,7 +10641,7 @@ async function listFoldersLogic(input, appContext, _sdkContext) {
10215
10641
  );
10216
10642
  const ctx = requestContextService.createRequestContext({
10217
10643
  operation: "feishu.listFolders",
10218
- tenantId: "feishu-service"
10644
+ tenantId: "feishu_service"
10219
10645
  });
10220
10646
  try {
10221
10647
  const folders = await feishuService.listFolders(
@@ -10311,7 +10737,7 @@ async function listWikisLogic(input, appContext, _sdkContext) {
10311
10737
  );
10312
10738
  const ctx = requestContextService.createRequestContext({
10313
10739
  operation: "feishu.listWikis",
10314
- tenantId: "feishu-service"
10740
+ tenantId: "feishu_service"
10315
10741
  });
10316
10742
  try {
10317
10743
  const wikis = await feishuService.listWikis(ctx, input.appId);
@@ -10430,7 +10856,7 @@ async function listWikiNodesLogic(input, appContext, _sdkContext) {
10430
10856
  );
10431
10857
  const ctx = requestContextService.createRequestContext({
10432
10858
  operation: "feishu.listWikiNodes",
10433
- tenantId: "feishu-service"
10859
+ tenantId: "feishu_service"
10434
10860
  });
10435
10861
  const nodes = await feishuService.getWikiNodes(
10436
10862
  ctx,
@@ -10518,7 +10944,7 @@ async function getUserInfoLogic(input, appContext, _sdkContext) {
10518
10944
  const storage = container.resolve(StorageService);
10519
10945
  const ctx = requestContextService.createRequestContext({
10520
10946
  operation: "feishu.getUserInfo",
10521
- tenantId: "feishu-service"
10947
+ tenantId: "feishu_service"
10522
10948
  });
10523
10949
  const appId = input.appId || "cli_a9e211f948381bdf";
10524
10950
  const auth = await storage.get(`feishu/auth/${appId}`, ctx);
@@ -10592,7 +11018,7 @@ async function setDefaultAppLogic(input, appContext, _sdkContext) {
10592
11018
  const storage = container.resolve(StorageService);
10593
11019
  const ctx = requestContextService.createRequestContext({
10594
11020
  operation: "feishu.setDefaultApp",
10595
- tenantId: "feishu-service"
11021
+ tenantId: "feishu_service"
10596
11022
  });
10597
11023
  const auth = await storage.get(
10598
11024
  `feishu/auth/${input.appId}`,
@@ -10676,7 +11102,7 @@ async function listAppsLogic(_input, appContext, _sdkContext) {
10676
11102
  const storage = container.resolve(StorageService);
10677
11103
  const ctx = requestContextService.createRequestContext({
10678
11104
  operation: "feishu.listApps",
10679
- tenantId: "feishu-service"
11105
+ tenantId: "feishu_service"
10680
11106
  });
10681
11107
  const defaultAppId = await storage.get(
10682
11108
  "feishu/config/default_app",
@@ -10871,7 +11297,7 @@ async function batchUploadLogic(input, appContext, _sdkContext) {
10871
11297
  );
10872
11298
  const context = requestContextService.createRequestContext({
10873
11299
  operation: "feishu.batchUploadMarkdown",
10874
- tenantId: "feishu-service"
11300
+ tenantId: "feishu_service"
10875
11301
  });
10876
11302
  const baseWorkingDirectory = input.workingDirectory || process.cwd();
10877
11303
  const uploadDocument = async (doc, index) => {
@@ -11090,7 +11516,7 @@ async function readLogic(input, appContext, _sdkContext) {
11090
11516
  });
11091
11517
  const context = requestContextService.createRequestContext({
11092
11518
  operation: "feishu.readDocument",
11093
- tenantId: "feishu-service"
11519
+ tenantId: "feishu_service"
11094
11520
  });
11095
11521
  if (input.documentType === "wiki" && !input.wikiSpaceId) {
11096
11522
  throw new McpError(
@@ -11270,7 +11696,7 @@ async function batchReadLogic(input, appContext, _sdkContext) {
11270
11696
  });
11271
11697
  const context = requestContextService.createRequestContext({
11272
11698
  operation: "feishu.batchReadDocuments",
11273
- tenantId: "feishu-service"
11699
+ tenantId: "feishu_service"
11274
11700
  });
11275
11701
  const feishuService = container.resolve(
11276
11702
  FeishuServiceToken
@@ -11413,7 +11839,7 @@ async function recursiveReadLogic(input, appContext, _sdkContext) {
11413
11839
  });
11414
11840
  const context = requestContextService.createRequestContext({
11415
11841
  operation: "feishu.readWikiRecursive",
11416
- tenantId: "feishu-service"
11842
+ tenantId: "feishu_service"
11417
11843
  });
11418
11844
  const feishuService = container.resolve(
11419
11845
  FeishuServiceToken
@@ -11502,6 +11928,136 @@ var feishuReadWikiRecursiveTool = {
11502
11928
  logic: withToolAuth(["tool:feishu:read"], recursiveReadLogic),
11503
11929
  responseFormatter: responseFormatter14
11504
11930
  };
11931
+ var TOOL_NAME15 = "feishu_read_bitable";
11932
+ var TOOL_TITLE15 = "\u8BFB\u53D6\u98DE\u4E66\u591A\u7EF4\u8868\u683C";
11933
+ var TOOL_DESCRIPTION15 = `\u8BFB\u53D6\u98DE\u4E66\u591A\u7EF4\u8868\u683C\uFF08Bitable\uFF09\uFF0C\u5E76\u8F6C\u6362\u4E3A Markdown \u683C\u5F0F\u3002
11934
+
11935
+ \u591A\u7EF4\u8868\u683C\u662F\u98DE\u4E66\u7684\u4E00\u79CD\u6570\u636E\u7BA1\u7406\u5DE5\u5177\uFF0C\u7C7B\u4F3C\u4E8E\u7535\u5B50\u8868\u683C\uFF0C\u4F46\u529F\u80FD\u66F4\u5F3A\u5927\u3002
11936
+
11937
+ \u529F\u80FD\u7279\u6027\uFF1A
11938
+ - \u8BFB\u53D6\u591A\u7EF4\u8868\u683C\u7684\u6240\u6709\u6570\u636E\u8868\uFF08Sheet\uFF09
11939
+ - \u81EA\u52A8\u8F6C\u6362\u4E3A Markdown \u8868\u683C\u683C\u5F0F
11940
+ - \u652F\u6301\u5206\u9875\u8BFB\u53D6\u5927\u91CF\u6570\u636E
11941
+ - \u5904\u7406\u591A\u79CD\u5B57\u6BB5\u7C7B\u578B\uFF08\u6587\u672C\u3001\u6570\u5B57\u3001\u65E5\u671F\u3001\u94FE\u63A5\u7B49\uFF09
11942
+
11943
+ **\u6CE8\u610F\u4E8B\u9879\uFF1A**
11944
+ - \u9700\u8981\u5148\u5B8C\u6210\u98DE\u4E66 OAuth \u6388\u6743
11945
+ - \u9700\u8981\u5E94\u7528\u5177\u6709 bitable:bitable \u6743\u9650
11946
+ - \u591A\u7EF4\u8868\u683C token \u53EF\u4EE5\u4ECE\u6587\u6863 URL \u4E2D\u83B7\u53D6
11947
+ `.trim();
11948
+ var TOOL_ANNOTATIONS15 = {
11949
+ readOnlyHint: true,
11950
+ destructiveHint: false,
11951
+ idempotentHint: true,
11952
+ openWorldHint: true
11953
+ };
11954
+ var InputSchema15 = z.object({
11955
+ bitableToken: z.string().min(1).describe("\u591A\u7EF4\u8868\u683C token\u3002\u53EF\u4EE5\u4ECE\u591A\u7EF4\u8868\u683C URL \u4E2D\u83B7\u53D6\u3002"),
11956
+ outputFormat: z.enum(["markdown", "json"]).default("markdown").describe("\u8F93\u51FA\u683C\u5F0F\uFF1Amarkdown\uFF08Markdown \u8868\u683C\uFF09\u6216 json\uFF08JSON \u6570\u636E\uFF09\u3002"),
11957
+ appId: z.string().optional().describe("\u98DE\u4E66\u5E94\u7528 ID\u3002\u5982\u679C\u4E0D\u63D0\u4F9B\uFF0C\u5C06\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E\u7684\u5E94\u7528\u3002")
11958
+ }).describe("\u8BFB\u53D6\u98DE\u4E66\u591A\u7EF4\u8868\u683C\u7684\u53C2\u6570\u3002");
11959
+ var OutputSchema15 = z.object({
11960
+ success: z.boolean().describe("\u8BFB\u53D6\u662F\u5426\u6210\u529F\u3002"),
11961
+ bitableToken: z.string().describe("\u591A\u7EF4\u8868\u683C token\u3002"),
11962
+ name: z.string().optional().describe("\u591A\u7EF4\u8868\u683C\u540D\u79F0\u3002"),
11963
+ content: z.string().optional().describe("Markdown \u5185\u5BB9\uFF08\u6240\u6709\u8868\u683C\uFF09\u3002"),
11964
+ tables: z.array(
11965
+ z.object({
11966
+ tableId: z.string().describe("\u6570\u636E\u8868 ID\u3002"),
11967
+ name: z.string().describe("\u6570\u636E\u8868\u540D\u79F0\u3002"),
11968
+ markdown: z.string().optional().describe("Markdown \u8868\u683C\u5185\u5BB9\u3002"),
11969
+ records: z.array(
11970
+ z.object({
11971
+ recordId: z.string().describe("\u8BB0\u5F55 ID\u3002"),
11972
+ fields: z.record(z.string(), z.unknown()).describe("\u5B57\u6BB5\u6570\u636E\u3002")
11973
+ })
11974
+ ).optional().describe("\u8BB0\u5F55\u5217\u8868\u3002")
11975
+ })
11976
+ ).optional().describe("\u6570\u636E\u8868\u5217\u8868\u3002"),
11977
+ error: z.string().optional().describe("\u9519\u8BEF\u4FE1\u606F\u3002")
11978
+ }).describe("\u591A\u7EF4\u8868\u683C\u8BFB\u53D6\u7ED3\u679C\u3002");
11979
+ async function readBitableLogic(input, appContext, _sdkContext) {
11980
+ logger.debug("\u5F00\u59CB\u8BFB\u53D6\u98DE\u4E66\u591A\u7EF4\u8868\u683C", {
11981
+ ...appContext,
11982
+ bitableToken: input.bitableToken,
11983
+ outputFormat: input.outputFormat
11984
+ });
11985
+ const context = requestContextService.createRequestContext({
11986
+ operation: "feishu.readBitable",
11987
+ tenantId: "feishu_service"
11988
+ });
11989
+ const feishuService = container.resolve(
11990
+ FeishuServiceToken
11991
+ );
11992
+ const options = {
11993
+ outputFormat: input.outputFormat
11994
+ };
11995
+ if (input.appId) options.appId = input.appId;
11996
+ const result = await feishuService.readBitable(
11997
+ input.bitableToken,
11998
+ options,
11999
+ context
12000
+ );
12001
+ if (result.success) {
12002
+ logger.info("\u98DE\u4E66\u591A\u7EF4\u8868\u683C\u8BFB\u53D6\u6210\u529F", {
12003
+ ...context,
12004
+ bitableToken: result.bitableToken,
12005
+ name: result.name,
12006
+ tableCount: result.tables?.length
12007
+ });
12008
+ } else {
12009
+ logger.warning("\u98DE\u4E66\u591A\u7EF4\u8868\u683C\u8BFB\u53D6\u5931\u8D25", {
12010
+ ...context,
12011
+ error: result.error
12012
+ });
12013
+ }
12014
+ return {
12015
+ success: result.success,
12016
+ bitableToken: result.bitableToken,
12017
+ name: result.name,
12018
+ content: result.content,
12019
+ tables: result.tables,
12020
+ error: result.error
12021
+ };
12022
+ }
12023
+ function responseFormatter15(result) {
12024
+ const md = markdown();
12025
+ if (result.success) {
12026
+ md.h2("\u2705 \u591A\u7EF4\u8868\u683C\u8BFB\u53D6\u6210\u529F").keyValue("\u8868\u683C\u540D\u79F0", result.name ?? "\u672A\u77E5").keyValue("\u591A\u7EF4\u8868\u683C Token", result.bitableToken).keyValue("\u6570\u636E\u8868\u6570\u91CF", String(result.tables?.length ?? 0));
12027
+ if (result.tables && result.tables.length > 0) {
12028
+ md.blankLine().h3("\u{1F4CA} \u6570\u636E\u8868\u5217\u8868");
12029
+ for (const table of result.tables) {
12030
+ md.text(`- **${table.name}** (${table.records?.length ?? 0} \u6761\u8BB0\u5F55)`);
12031
+ }
12032
+ }
12033
+ if (result.content) {
12034
+ md.blankLine().h3("\u{1F4DD} \u8868\u683C\u5185\u5BB9").blankLine().text(
12035
+ result.content.length > 2e3 ? result.content.substring(0, 2e3) + "\n\n... (\u5185\u5BB9\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD)" : result.content
12036
+ );
12037
+ }
12038
+ } else {
12039
+ md.h2("\u274C \u591A\u7EF4\u8868\u683C\u8BFB\u53D6\u5931\u8D25").paragraph(result.error ?? "\u672A\u77E5\u9519\u8BEF");
12040
+ md.blankLine().blockquote(
12041
+ "\u8BF7\u68C0\u67E5\u9519\u8BEF\u4FE1\u606F\uFF0C\u786E\u4FDD\u5DF2\u5B8C\u6210 OAuth \u8BA4\u8BC1\u4E14\u6709\u6743\u9650\u8BBF\u95EE\u8BE5\u591A\u7EF4\u8868\u683C\u3002"
12042
+ );
12043
+ }
12044
+ return [
12045
+ {
12046
+ type: "text",
12047
+ text: md.build()
12048
+ }
12049
+ ];
12050
+ }
12051
+ var feishuReadBitableTool = {
12052
+ name: TOOL_NAME15,
12053
+ title: TOOL_TITLE15,
12054
+ description: TOOL_DESCRIPTION15,
12055
+ inputSchema: InputSchema15,
12056
+ outputSchema: OutputSchema15,
12057
+ annotations: TOOL_ANNOTATIONS15,
12058
+ logic: withToolAuth(["tool:feishu:read"], readBitableLogic),
12059
+ responseFormatter: responseFormatter15
12060
+ };
11505
12061
 
11506
12062
  // src/mcp-server/tools/definitions/index.ts
11507
12063
  var allToolDefinitions = [
@@ -11523,6 +12079,8 @@ var allToolDefinitions = [
11523
12079
  // 飞书文档:批量读取
11524
12080
  feishuReadWikiRecursiveTool,
11525
12081
  // 飞书文档:递归读取知识库
12082
+ feishuReadBitableTool,
12083
+ // 飞书文档:读取多维表格
11526
12084
  // 飞书管理工具
11527
12085
  feishuListFoldersTool,
11528
12086
  // 飞书管理:列出文件夹
@@ -11547,7 +12105,7 @@ function createMcpToolHandler({
11547
12105
  inputSchema: _inputSchema,
11548
12106
  // Captured for type inference, not used at runtime
11549
12107
  logic,
11550
- responseFormatter: responseFormatter15 = defaultResponseFormatter2
12108
+ responseFormatter: responseFormatter16 = defaultResponseFormatter2
11551
12109
  }) {
11552
12110
  return async (input, callContext) => {
11553
12111
  const sdkContext = callContext;
@@ -11569,7 +12127,7 @@ function createMcpToolHandler({
11569
12127
  );
11570
12128
  return {
11571
12129
  structuredContent: result,
11572
- content: responseFormatter15(result)
12130
+ content: responseFormatter16(result)
11573
12131
  };
11574
12132
  } catch (error) {
11575
12133
  const mcpError = ErrorHandler.handleError(error, {
@@ -12021,9 +12579,9 @@ ToolRegistry = __decorateClass([
12021
12579
  injectable(),
12022
12580
  __decorateParam(0, injectAll(ToolDefinitions, { isOptional: true }))
12023
12581
  ], ToolRegistry);
12024
- var registerTools = (container25) => {
12582
+ var registerTools = (container26) => {
12025
12583
  for (const tool of allToolDefinitions) {
12026
- container25.register(ToolDefinitions, { useValue: tool });
12584
+ container26.register(ToolDefinitions, { useValue: tool });
12027
12585
  }
12028
12586
  };
12029
12587
 
@@ -12084,33 +12642,33 @@ async function createMcpServerInstance() {
12084
12642
  globalThis.crypto?.webcrypto ?? // Node.js [18-16] REPL
12085
12643
  globalThis.crypto ?? // Node.js >18
12086
12644
  import('crypto').then((m) => m.webcrypto);
12087
- z17.object({
12088
- client_id: z17.string(),
12089
- redirect_uri: z17.string().optional().refine((value) => value === void 0 || URL.canParse(value), { message: "redirect_uri must be a valid URL" })
12645
+ z18.object({
12646
+ client_id: z18.string(),
12647
+ redirect_uri: z18.string().optional().refine((value) => value === void 0 || URL.canParse(value), { message: "redirect_uri must be a valid URL" })
12090
12648
  });
12091
- z17.object({
12092
- response_type: z17.literal("code"),
12093
- code_challenge: z17.string(),
12094
- code_challenge_method: z17.literal("S256"),
12095
- scope: z17.string().optional(),
12096
- state: z17.string().optional(),
12097
- resource: z17.url().optional()
12649
+ z18.object({
12650
+ response_type: z18.literal("code"),
12651
+ code_challenge: z18.string(),
12652
+ code_challenge_method: z18.literal("S256"),
12653
+ scope: z18.string().optional(),
12654
+ state: z18.string().optional(),
12655
+ resource: z18.url().optional()
12098
12656
  });
12099
- z17.object({ grant_type: z17.string() });
12100
- z17.object({
12101
- code: z17.string(),
12102
- code_verifier: z17.string(),
12103
- redirect_uri: z17.string().optional(),
12104
- resource: z17.url().optional()
12657
+ z18.object({ grant_type: z18.string() });
12658
+ z18.object({
12659
+ code: z18.string(),
12660
+ code_verifier: z18.string(),
12661
+ redirect_uri: z18.string().optional(),
12662
+ resource: z18.url().optional()
12105
12663
  });
12106
- z17.object({
12107
- refresh_token: z17.string(),
12108
- scope: z17.string().optional(),
12109
- resource: z17.url().optional()
12664
+ z18.object({
12665
+ refresh_token: z18.string(),
12666
+ scope: z18.string().optional(),
12667
+ resource: z18.url().optional()
12110
12668
  });
12111
- z17.object({
12112
- client_id: z17.string(),
12113
- client_secret: z17.string().optional()
12669
+ z18.object({
12670
+ client_id: z18.string(),
12671
+ client_secret: z18.string().optional()
12114
12672
  });
12115
12673
  var isOldBunVersion = () => {
12116
12674
  const version = typeof Bun !== "undefined" ? Bun.version : void 0;