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.
@@ -11,14 +11,27 @@ export const ParentBlockIdSchema = z.string().describe('Parent block ID (require
11
11
  // 块ID参数定义
12
12
  export const BlockIdSchema = z.string().describe('Block ID (required). The ID of the specific block to get content from. You can obtain block IDs using the get_feishu_document_blocks tool.');
13
13
  // 插入位置索引参数定义
14
- export const IndexSchema = z.number().describe('Insertion position index (required). Specifies where the block should be inserted. Use 0 to insert at the beginning. ' +
14
+ export const IndexSchema = z.number().describe('Insertion position index (required). This index is relative to the children array of the specified parentBlockId block (not the whole document).\n' +
15
+ 'If parentBlockId is the document root (i.e., the document ID), index refers to the position among the document content blocks (excluding the title block itself).\n' +
16
+ '0 means to insert as the first content block after the title.\n' +
17
+ 'If children is empty or missing, use 0 to insert the first content block.\n' +
18
+ 'For nested blocks, index is relative to the parent block\'s children.\n' +
19
+ '**index must satisfy 0 ≤ index ≤ parentBlock.children.length, otherwise the API will return an error.**\n' +
20
+ 'Note: The title block itself is not part of the children array and cannot be operated on with index.' +
21
+ 'Specifies where the block should be inserted. Use 0 to insert at the beginning. ' +
15
22
  'Use get_feishu_document_blocks tool to understand document structure if unsure. ' +
16
23
  'For consecutive insertions, calculate next index as previous index + 1.');
17
24
  // 起始插入位置索引参数定义
18
- export const StartIndexSchema = z.number().describe('Starting insertion position index (required). Specifies where the first block should be inserted. Use 0 to insert at the beginning. ' +
25
+ export const StartIndexSchema = z.number().describe('Starting insertion position index (required). This index is relative to the children array of the specified parentBlockId block.\n' +
26
+ 'For the document root, this means the content blocks after the title. For other blocks, it means the sub-blocks under that block.\n' +
27
+ 'The index does not include the title block itself.' +
28
+ 'Specifies where the first block should be inserted or deleted. Use 0 to insert at the beginning. ' +
19
29
  'Use get_feishu_document_blocks tool to understand document structure if unsure.');
20
30
  // 结束位置索引参数定义
21
- export const EndIndexSchema = z.number().describe('Ending position index (required). Specifies the end of the range for deletion (exclusive). ' +
31
+ export const EndIndexSchema = z.number().describe('Ending position index (required). This index is relative to the children array of the specified parentBlockId block.\n' +
32
+ 'For the document root, this means the content blocks after the title. For other blocks, it means the sub-blocks under that block.\n' +
33
+ 'The index does not include the title block itself.' +
34
+ 'Specifies the end of the range for deletion (exclusive). ' +
22
35
  'For example, to delete blocks 2, 3, and 4, use startIndex=2, endIndex=5. ' +
23
36
  'To delete a single block at position 2, use startIndex=2, endIndex=3.');
24
37
  // 文本对齐方式参数定义
@@ -41,11 +54,17 @@ export const TextStylePropertiesSchema = {
41
54
  };
42
55
  // 文本样式对象定义
43
56
  export const TextStyleSchema = z.object(TextStylePropertiesSchema).optional().describe('Text style settings. Explicitly set style properties instead of relying on Markdown syntax conversion.');
44
- // 文本内容单元定义
45
- export const TextElementSchema = z.object({
46
- text: z.string().describe('Text content. Provide plain text without markdown syntax; use style object for formatting.'),
47
- style: TextStyleSchema
48
- });
57
+ // 文本内容单元定义 - 支持普通文本和公式元素
58
+ export const TextElementSchema = z.union([
59
+ z.object({
60
+ text: z.string().describe('Text content. Provide plain text without markdown syntax; use style object for formatting.'),
61
+ style: TextStyleSchema
62
+ }).describe('Regular text element with optional styling.'),
63
+ z.object({
64
+ equation: z.string().describe('Mathematical equation content. The formula or expression to display. Format: LaTeX.'),
65
+ style: TextStyleSchema
66
+ }).describe('Mathematical equation element with optional styling.')
67
+ ]);
49
68
  // 文本内容数组定义
50
69
  export const TextElementsArraySchema = z.array(TextElementSchema).describe('Array of text content objects. A block can contain multiple text segments with different styles. Example: [{text:"Hello",style:{bold:true}},{text:" World",style:{italic:true}}]');
51
70
  // 代码块语言参数定义
@@ -62,10 +81,7 @@ export const CodeLanguageSchema = z.number().optional().default(1).describe("Pro
62
81
  export const CodeWrapSchema = z.boolean().optional().default(false).describe('Whether to enable automatic line wrapping. Default is false.');
63
82
  // 文本样式段落定义 - 用于批量创建块工具
64
83
  export const TextStyleBlockSchema = z.object({
65
- textStyles: z.array(z.object({
66
- text: z.string().describe('Text segment content. The actual text to display.'),
67
- style: TextStyleSchema
68
- })).describe('Array of text content objects with styles. A block can contain multiple text segments with different styles. Example: [{text:"Hello",style:{bold:true}},{text:" World",style:{italic:true}}]'),
84
+ textStyles: z.array(TextElementSchema).describe('Array of text content objects with styles. A block can contain multiple text segments with different styles, including both regular text and equations. Example: [{text:"Hello",style:{bold:true}},{equation:"1+2=3",style:{}}]'),
69
85
  align: z.number().optional().default(1).describe('Text alignment: 1 for left (default), 2 for center, 3 for right.'),
70
86
  });
71
87
  // 代码块内容定义 - 用于批量创建块工具
@@ -87,8 +103,15 @@ export const ListBlockSchema = z.object({
87
103
  align: AlignSchemaWithValidation,
88
104
  });
89
105
  // 块类型枚举 - 用于批量创建块工具
90
- export const BlockTypeEnum = z.string().describe("Block type (required). Supports: 'text', 'code', 'heading', 'list', as well as 'heading1' through 'heading9'. " +
91
- "For headings, we recommend using 'heading' with level property, but 'heading1'-'heading9' are also supported.");
106
+ export const BlockTypeEnum = z.string().describe("Block type (required). Supports: 'text', 'code', 'heading', 'list', 'image', as well as 'heading1' through 'heading9'. " +
107
+ "For headings, we recommend using 'heading' with level property, but 'heading1'-'heading9' are also supported. " +
108
+ "For images, use 'image' to create empty image blocks that can be filled later. " +
109
+ "For text blocks, you can include both regular text and equation elements in the same block.");
110
+ // 图片块内容定义 - 用于批量创建块工具
111
+ export const ImageBlockSchema = z.object({
112
+ width: z.number().optional().describe('Image width in pixels (optional). If not provided, default width will be used.'),
113
+ height: z.number().optional().describe('Image height in pixels (optional). If not provided, default height will be used.'),
114
+ });
92
115
  // 块配置定义 - 用于批量创建块工具
93
116
  export const BlockConfigSchema = z.object({
94
117
  blockType: BlockTypeEnum,
@@ -97,6 +120,7 @@ export const BlockConfigSchema = z.object({
97
120
  z.object({ code: CodeBlockSchema }).describe("Code block options. Used when blockType is 'code'."),
98
121
  z.object({ heading: HeadingBlockSchema }).describe("Heading block options. Used with both 'heading' and 'headingN' formats."),
99
122
  z.object({ list: ListBlockSchema }).describe("List block options. Used when blockType is 'list'."),
123
+ z.object({ image: ImageBlockSchema }).describe("Image block options. Used when blockType is 'image'. Creates empty image blocks."),
100
124
  z.record(z.any()).describe("Fallback for any other block options")
101
125
  ]).describe('Options for the specific block type. Provide the corresponding options object based on blockType.'),
102
126
  });
@@ -112,11 +136,23 @@ export const FolderTokenSchema = z.string().describe('Folder token (required). T
112
136
  'Format is an alphanumeric string like "FWK2fMleClICfodlHHWc4Mygnhb".');
113
137
  // 文件夹名称参数定义
114
138
  export const FolderNameSchema = z.string().describe('Folder name (required). The name for the new folder to be created.');
115
- // 排序方式参数定义
116
- export const OrderBySchema = z.string().optional().default('EditedTime').describe('Order by field (optional). Specifies how to sort the file list. Available values: ' +
117
- '"EditedTime" (default), "CreatedTime", "Name". For user-friendly display, case insensitive.');
118
- // 排序方向参数定义
119
- export const DirectionSchema = z.string().optional().default('DESC').describe('Sort direction (optional). Specifies the sort order. Available values: ' +
120
- '"DESC" (default) for descending order, "ASC" for ascending order. Case sensitive.');
121
139
  // 搜索关键字参数定义
122
140
  export const SearchKeySchema = z.string().describe('Search keyword (required). The keyword to search for in documents.');
141
+ // 图片路径或URL参数定义
142
+ export const ImagePathOrUrlSchema = z.string().describe('Image path or URL (required). Supports the following formats:\n' +
143
+ '1. Local file absolute path: e.g., "C:\\path\\to\\image.jpg"\n' +
144
+ '2. HTTP/HTTPS URL: e.g., "https://example.com/image.png"\n' +
145
+ 'The tool will automatically detect the format and handle accordingly.');
146
+ // 图片文件名参数定义
147
+ export const ImageFileNameSchema = z.string().optional().describe('Image file name (optional). If not provided, a default name will be generated based on the source. ' +
148
+ 'Should include the file extension, e.g., "image.png" or "photo.jpg".');
149
+ // 图片宽度参数定义
150
+ export const ImageWidthSchema = z.number().optional().describe('Image width in pixels (optional). If not provided, the original image width will be used.');
151
+ // 图片高度参数定义
152
+ export const ImageHeightSchema = z.number().optional().describe('Image height in pixels (optional). If not provided, the original image height will be used.');
153
+ // 画板ID参数定义
154
+ export const WhiteboardIdSchema = z.string().describe('Whiteboard ID (required). This is the token value from the board.token field when getting document blocks.\n' +
155
+ 'When you find a block with block_type: 43, the whiteboard ID is located in board.token field.\n' +
156
+ 'Example: "EPJKwvY5ghe3pVbKj9RcT2msnBX"');
157
+ // 文档标题参数定义
158
+ export const DocumentTitleSchema = z.string().describe('Document title (required). This will be displayed in the Feishu document list and document header.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feishu-mcp",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "description": "Model Context Protocol server for Feishu integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -41,12 +41,13 @@
41
41
  "author": "cso1z",
42
42
  "license": "MIT",
43
43
  "dependencies": {
44
- "@modelcontextprotocol/sdk": "^1.6.1",
44
+ "@modelcontextprotocol/sdk": "^1.13.1",
45
45
  "@types/yargs": "^17.0.33",
46
46
  "axios": "^1.7.9",
47
47
  "cross-env": "^7.0.3",
48
48
  "dotenv": "^16.4.7",
49
49
  "express": "^4.21.2",
50
+ "form-data": "^4.0.3",
50
51
  "remeda": "^2.20.1",
51
52
  "yargs": "^17.7.2",
52
53
  "zod": "^3.24.2"
package/README.en.md DELETED
@@ -1,201 +0,0 @@
1
- # Feishu MCP Server
2
-
3
- Provides access to Feishu (Lark) documents for [Cursor](https://cursor.sh/), [Windsurf](https://codeium.com/windsurf), [Cline](https://cline.bot/), and other AI-driven coding tools, implemented based on the [Model Context Protocol](https://modelcontextprotocol.io/introduction) server.
4
-
5
- When Cursor can access Feishu document data, it can understand and process document content more accurately, making it more efficient than other methods (such as copying and pasting text).
6
-
7
- ## Core Features
8
-
9
- ### Document Management
10
- - **Create Feishu Documents**: Support for creating new Feishu documents in specified folders
11
- - **Folder Management**:
12
- - Get root folder information
13
- - View folder contents and file lists
14
- - Create new folders
15
-
16
- ### Document Content Operations
17
- - **Get Document Information**:
18
- - Get basic document information (title, version, etc.)
19
- - Get document block structure and hierarchy
20
- - Get detailed content of specific blocks
21
- - **Get Document Plain Text Content**: Support for extracting complete plain text content from documents for analysis and processing
22
- - **Edit Document Content**:
23
- - **Text Block Operations**:
24
- - Create and update text blocks with rich styles (bold, italic, underline, strikethrough, inline code)
25
- - Support for text color settings (gray, brown, orange, yellow, green, blue, purple)
26
- - Support for text alignment adjustment (left-aligned, centered, right-aligned)
27
- - **Heading Block Operations**: Create headings from level one to level nine
28
- - **Code Block Operations**:
29
- - Create code blocks for multiple programming languages
30
- - Support for code syntax highlighting
31
- - Support for automatic line wrapping settings
32
- - **List Operations**:
33
- - Create ordered lists (numbered lists)
34
- - Create unordered lists (bullet point lists)
35
- - **Block Management Operations**:
36
- - Batch content creation: Support for creating multiple different types of content blocks in a single operation
37
- - Delete document blocks: Support for deleting one or more consecutive document blocks
38
- - **Wiki Document Support**:
39
- - Convert Feishu Wiki links to compatible document IDs for use with other document operation tools
40
- - **Image Resource Processing**:
41
- - Download images from Feishu using media IDs
42
-
43
- ### Planned Features
44
- - **Advanced Content Insertion**:
45
- - Table insertion: Support for row and column structured data
46
- - Insert charts: Support for various data visualization charts
47
- - Insert flowcharts: Support for flowcharts and mind maps
48
- - Insert formulas: Support for mathematical formulas and scientific symbols
49
- - Recognition and parsing of charts and flowcharts
50
-
51
- Quick start, see the [Configuration](#configuration) section for details:
52
-
53
- ```bash
54
- npx feishu-mcp --feishu-app-id=<YOUR_FEISHU_APP_ID> --feishu-app-secret=<YOUR_FEISHU_APP_SECRET>
55
- ```
56
-
57
- ## How It Works
58
-
59
- 1. Open the editor in Cursor's Agent mode.
60
- 2. Paste a Feishu document link.
61
- 3. Ask Cursor to perform operations based on the Feishu document—for example, analyze document content or create related code.
62
- 4. Cursor will retrieve relevant metadata from Feishu and use it to assist in writing code.
63
-
64
- This MCP server is designed specifically for Cursor. Before responding with content from the [Feishu API](https://open.feishu.cn/document/home/introduction-to-lark-open-platform/overview), it simplifies and transforms the responses, ensuring that only the most relevant document information is provided to the model.
65
-
66
- ## Installation
67
-
68
- ### Quickly Run the Server Using NPM
69
-
70
- You can quickly run the server using NPM without installing or building the repository:
71
-
72
- ```bash
73
- npx feishu-mcp --feishu-app-id=<YOUR_FEISHU_APP_ID> --feishu-app-secret=<YOUR_FEISHU_APP_SECRET>
74
-
75
- # or
76
- pnpx feishu-mcp --feishu-app-id=<YOUR_FEISHU_APP_ID> --feishu-app-secret=<YOUR_FEISHU_APP_SECRET>
77
-
78
- # or
79
- yarn dlx feishu-mcp --feishu-app-id=<YOUR_FEISHU_APP_ID> --feishu-app-secret=<YOUR_FEISHU_APP_SECRET>
80
-
81
- # or
82
- bunx feishu-mcp --feishu-app-id=<YOUR_FEISHU_APP_ID> --feishu-app-secret=<YOUR_FEISHU_APP_SECRET>
83
- ```
84
-
85
- **Published to the Smithery platform, available at: https://smithery.ai/server/@cso1z/feishu-mcp**
86
-
87
- Instructions on how to create a Feishu application and obtain application credentials can be found in the [official tutorial](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app).
88
-
89
- **Detailed Feishu application configuration steps**: For detailed guidance on registering a Feishu application, configuring permissions, and adding document access permissions, please refer to [Step-by-step tutorial FEISHU_CONFIG.md](FEISHU_CONFIG.md).
90
-
91
- ### JSON Configuration for Tools Using Configuration Files
92
-
93
- Many tools such as Windsurf, Cline, and [Claude Desktop](https://claude.ai/download) use configuration files to start servers.
94
-
95
- The `feishu-mcp` server can be configured by adding the following to the configuration file:
96
-
97
- ```json
98
- {
99
- "mcpServers": {
100
- "feishu-mcp": {
101
- "command": "npx",
102
- "args": ["-y", "feishu-mcp", "--stdio"],
103
- "env": {
104
- "FEISHU_APP_ID": "<YOUR_FEISHU_APP_ID>",
105
- "FEISHU_APP_SECRET": "<YOUR_FEISHU_APP_SECRET>"
106
- }
107
- }
108
- }
109
- }
110
- ```
111
-
112
- ### Run the Server from Local Source Code
113
-
114
- 1. Clone the repository
115
- 2. Install dependencies using `pnpm install`
116
- 3. Copy `.env.example` to `.env` and fill in your [Feishu application credentials](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app).
117
- 4. Run the server using `pnpm run dev`, with any flags from the [Command Line Arguments](#command-line-arguments) section.
118
-
119
- ### Run the Server Using Docker
120
-
121
- You can use Docker to run the server, which avoids installing Node.js and other dependencies locally:
122
-
123
- 1. Build the Docker image:
124
- ```bash
125
- docker build -t feishu-mcp .
126
- ```
127
-
128
- 2. Run the Docker container:
129
- ```bash
130
- docker run -p 3333:3333 --env FEISHU_APP_ID=<YOUR_FEISHU_APP_ID> --env FEISHU_APP_SECRET=<YOUR_FEISHU_APP_SECRET> feishu-mcp
131
- ```
132
-
133
- Alternatively, you can use docker-compose:
134
-
135
- 1. Edit the `.env` file and add your Feishu application credentials:
136
- ```
137
- FEISHU_APP_ID=<YOUR_FEISHU_APP_ID>
138
- FEISHU_APP_SECRET=<YOUR_FEISHU_APP_SECRET>
139
- ```
140
-
141
- 2. Run docker-compose:
142
- ```bash
143
- docker-compose up -d
144
- ```
145
-
146
- This will start the server in the background and expose it on port 3333.
147
-
148
- ## Configuration
149
-
150
- The server can be configured using environment variables (via the `.env` file) or command line arguments. Command line arguments take precedence over environment variables.
151
-
152
- ### Environment Variables
153
-
154
- - `FEISHU_APP_ID`: Your [Feishu application ID](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app) (required)
155
- - `FEISHU_APP_SECRET`: Your [Feishu application secret](https://open.feishu.cn/document/home/develop-a-bot-in-5-minutes/create-an-app) (required)
156
- - `PORT`: The port to run the server on (default: 3333)
157
-
158
- ### Command Line Arguments
159
-
160
- - `--version`: Show version number
161
- - `--feishu-app-id`: Your Feishu application ID
162
- - `--feishu-app-secret`: Your Feishu application secret
163
- - `--port`: The port to run the server on
164
- - `--stdio`: Run the server in command mode instead of the default HTTP/SSE
165
- - `--help`: Show help menu
166
-
167
- ## Connecting to Cursor
168
-
169
- ### Configuring Cursor
170
-
171
- 1. Open Cursor settings
172
- 2. Navigate to `Settings > AI > MCP Servers`
173
- 3. Add a new server with the URL `http://localhost:3333` (or your configured port)
174
- 4. Click "Verify Connection" to ensure the connection is successful
175
-
176
- ## Usage
177
-
178
- 1. In Cursor, open the AI panel (default shortcut `Cmd+K` or `Ctrl+K`)
179
- 2. If you need to create a new Feishu document, you should explicitly specify a folderToken, which you can find by opening a Feishu document directory like: `https://vq5xxxxx7bc.feishu.cn/drive/folder/FPKvfjdxxxxx706RnOc`
180
- 3. If you need to modify Feishu document content, you should explicitly provide the Feishu document link, for example: `https://vq5ixxxx7bc.feishu.cn/docx/J6T0d6exxxxxxxDdc1zqwnph`
181
- 4. Ask questions about the document or request operations based on the document content
182
- 5. Creating and editing documents requires permissions, and you can test your account on the Feishu open platform: `https://open.feishu.cn/api-explorer/cli_a75a8ca0ac79100c?apiName=tenant_access_token_internal&from=op_doc&project=auth&resource=auth&version=v3`
183
-
184
- ## Document Permissions and Troubleshooting
185
-
186
- ### Permission Types
187
- Permissions are divided into two types: robot permissions and document access permissions.
188
-
189
- ### Permission Verification and Troubleshooting
190
- 1. Get 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)
191
- 2. Using the token obtained in step 1, verify whether you have permission to access the document: [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)
192
-
193
- ### Troubleshooting Method
194
- Test permissions normally on the Feishu development platform (when debugging on the open platform, there will be sufficient prompt information and guidance in case of failure).
195
-
196
- ### Document Authorization
197
- If you encounter permission issues, please refer to [Cloud Document FAQ](https://open.feishu.cn/document/ukTMukTMukTM/uczNzUjL3czM14yN3MTN), [Knowledge Base FAQ](https://open.feishu.cn/document/server-docs/docs/wiki-v2/wiki-qa), especially focusing on how to grant document permissions to applications or users.
198
-
199
- ## License
200
-
201
- MIT
package/dist/config.js DELETED
@@ -1,104 +0,0 @@
1
- import { config } from "dotenv";
2
- import yargs from "yargs";
3
- import { hideBin } from "yargs/helpers";
4
- // 确保在任何配置读取前加载.env文件
5
- config();
6
- function maskApiKey(key) {
7
- if (key.length <= 4)
8
- return "****";
9
- return `****${key.slice(-4)}`;
10
- }
11
- export function getServerConfig(isStdioMode) {
12
- // Parse command line arguments
13
- const argv = yargs(hideBin(process.argv))
14
- .options({
15
- port: {
16
- type: "number",
17
- description: "Port to run the server on",
18
- },
19
- "feishu-app-id": {
20
- type: "string",
21
- description: "Feishu App ID",
22
- },
23
- "feishu-app-secret": {
24
- type: "string",
25
- description: "Feishu App Secret",
26
- },
27
- })
28
- .help()
29
- .parseSync();
30
- const config = {
31
- port: 3333,
32
- configSources: {
33
- port: "default",
34
- },
35
- };
36
- // Handle PORT
37
- if (argv.port) {
38
- config.port = argv.port;
39
- config.configSources.port = "cli";
40
- }
41
- else if (process.env.PORT) {
42
- config.port = parseInt(process.env.PORT, 10);
43
- config.configSources.port = "env";
44
- }
45
- // 在加载环境变量之前添加日志
46
- console.log('开始加载环境变量配置...');
47
- console.log('当前环境变量 FEISHU_APP_ID:', process.env.FEISHU_APP_ID);
48
- console.log('当前环境变量 FEISHU_APP_SECRET:', process.env.FEISHU_APP_SECRET);
49
- // Handle Feishu configuration
50
- if (argv["feishu-app-id"]) {
51
- config.feishuAppId = argv["feishu-app-id"];
52
- config.configSources.feishuAppId = "cli";
53
- console.log(`飞书应用 ID 来自命令行参数: ${maskApiKey(config.feishuAppId)}`);
54
- }
55
- else if (process.env.FEISHU_APP_ID) {
56
- config.feishuAppId = process.env.FEISHU_APP_ID;
57
- config.configSources.feishuAppId = "env";
58
- console.log(`飞书应用 ID 来自环境变量: ${maskApiKey(config.feishuAppId)}`);
59
- }
60
- else {
61
- console.log('未提供飞书应用 ID');
62
- }
63
- if (argv["feishu-app-secret"]) {
64
- config.feishuAppSecret = argv["feishu-app-secret"];
65
- config.configSources.feishuAppSecret = "cli";
66
- console.log(`飞书应用密钥来自命令行参数: ${maskApiKey(config.feishuAppSecret)}`);
67
- }
68
- else if (process.env.FEISHU_APP_SECRET) {
69
- config.feishuAppSecret = process.env.FEISHU_APP_SECRET;
70
- config.configSources.feishuAppSecret = "env";
71
- console.log(`飞书应用密钥来自环境变量: ${maskApiKey(config.feishuAppSecret)}`);
72
- }
73
- else {
74
- console.log('未提供飞书应用密钥');
75
- }
76
- // 输出飞书配置状态总结
77
- if (config.feishuAppId && config.feishuAppSecret) {
78
- console.log('飞书配置已完整提供,服务将被初始化');
79
- }
80
- else if (config.feishuAppId || config.feishuAppSecret) {
81
- console.log('飞书配置不完整,服务将不会初始化');
82
- }
83
- else {
84
- console.log('未提供飞书配置,服务将不会初始化');
85
- }
86
- // 验证配置
87
- if (!config.feishuAppId || !config.feishuAppSecret) {
88
- console.error("FEISHU_APP_ID 和 FEISHU_APP_SECRET 是必需的(通过命令行参数 --feishu-app-id 和 --feishu-app-secret 或 .env 文件)");
89
- process.exit(1);
90
- }
91
- // Log configuration sources
92
- if (!isStdioMode) {
93
- console.log("\n配置信息:");
94
- console.log(`- PORT: ${config.port} (来源: ${config.configSources.port})`);
95
- if (config.feishuAppId) {
96
- console.log(`- FEISHU_APP_ID: ${maskApiKey(config.feishuAppId)} (来源: ${config.configSources.feishuAppId})`);
97
- }
98
- if (config.feishuAppSecret) {
99
- console.log(`- FEISHU_APP_SECRET: ${maskApiKey(config.feishuAppSecret)} (来源: ${config.configSources.feishuAppSecret})`);
100
- }
101
- console.log(); // 空行,提高可读性
102
- }
103
- return config;
104
- }