feishu-doc-mcp 1.0.0
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/LICENSE +21 -0
- package/README.md +124 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +291 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ztxtxwd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Feishu Doc MCP
|
|
2
|
+
|
|
3
|
+
A Model Context Protocol (MCP) server for accessing Feishu (Lark) Open Platform documentation. This server enables AI assistants like Claude to search and read Feishu API documentation directly.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Search Feishu API documentation by category
|
|
8
|
+
- Read detailed documentation content
|
|
9
|
+
- Support for multiple API categories including:
|
|
10
|
+
- Server API (Messaging, Calendar, Contacts, etc.)
|
|
11
|
+
- Client API (Web apps, Mini programs, etc.)
|
|
12
|
+
- Development Guides (Bots, Web apps, etc.)
|
|
13
|
+
- And many more...
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
### Using npx (Recommended)
|
|
18
|
+
|
|
19
|
+
You can run this MCP server directly using npx without installation:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx feishu-doc-mcp
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Global Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g feishu-doc-mcp
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Then run:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
feishu-doc-mcp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Usage with Claude Desktop
|
|
38
|
+
|
|
39
|
+
Add this to your Claude Desktop configuration file:
|
|
40
|
+
|
|
41
|
+
**MacOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
42
|
+
|
|
43
|
+
**Windows**: `%APPDATA%/Claude/claude_desktop_config.json`
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"mcpServers": {
|
|
48
|
+
"feishu-doc": {
|
|
49
|
+
"command": "npx",
|
|
50
|
+
"args": ["feishu-doc-mcp"]
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or if installed globally:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"feishu-doc": {
|
|
62
|
+
"command": "feishu-doc-mcp"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Available Tools
|
|
69
|
+
|
|
70
|
+
### search_feishu_doc
|
|
71
|
+
|
|
72
|
+
Search Feishu API documentation by category. Returns a list of documents under the specified category.
|
|
73
|
+
|
|
74
|
+
**Parameters:**
|
|
75
|
+
- `category`: Document category in format "Level1_Level2" (e.g., "服务端API_即时通讯", "开发指南_开发机器人")
|
|
76
|
+
|
|
77
|
+
### read_feishu_doc
|
|
78
|
+
|
|
79
|
+
Read detailed content of a Feishu API document. The content is saved to a temporary file for easy access.
|
|
80
|
+
|
|
81
|
+
**Parameters:**
|
|
82
|
+
- `path`: Document path (obtained from search_feishu_doc results)
|
|
83
|
+
|
|
84
|
+
## Development
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Install dependencies
|
|
88
|
+
npm install
|
|
89
|
+
|
|
90
|
+
# Build
|
|
91
|
+
npm run build
|
|
92
|
+
|
|
93
|
+
# Run in development mode
|
|
94
|
+
npm run dev
|
|
95
|
+
|
|
96
|
+
# Start the server
|
|
97
|
+
npm start
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Publishing
|
|
101
|
+
|
|
102
|
+
This project uses GitHub Actions for automatic publishing to npm. To publish a new version:
|
|
103
|
+
|
|
104
|
+
1. Update the version in `package.json`
|
|
105
|
+
2. Commit your changes
|
|
106
|
+
3. Create and push a tag:
|
|
107
|
+
```bash
|
|
108
|
+
git tag v1.0.1
|
|
109
|
+
git push origin v1.0.1
|
|
110
|
+
```
|
|
111
|
+
4. GitHub Actions will automatically build and publish to npm
|
|
112
|
+
|
|
113
|
+
## Requirements
|
|
114
|
+
|
|
115
|
+
- Node.js >= 18
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT
|
|
120
|
+
|
|
121
|
+
## Author
|
|
122
|
+
|
|
123
|
+
ztxtxwd
|
|
124
|
+
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import axios from "axios";
|
|
5
|
+
import TurndownService from "turndown";
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as os from "os";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import * as crypto from "crypto";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
// 初始化 Turndown 用于将 HTML 转为 Markdown
|
|
12
|
+
const turndownService = new TurndownService({
|
|
13
|
+
headingStyle: "atx",
|
|
14
|
+
codeBlockStyle: "fenced",
|
|
15
|
+
});
|
|
16
|
+
// API 端点
|
|
17
|
+
const DIRECTORY_LIST_URL = "https://open.feishu.cn/api/tools/docment/directory_list";
|
|
18
|
+
const URI_MAPPING_URL = "https://open.feishu.cn/document_portal/v1/document_portal/v1/document/uri/mapping";
|
|
19
|
+
const DOC_DETAIL_URL = "https://open.feishu.cn/document_portal/v1/document/get_detail";
|
|
20
|
+
// 临时目录路径
|
|
21
|
+
const TEMP_DOC_DIR = path.join(os.tmpdir(), "feishu-doc-mcp");
|
|
22
|
+
class FeishuDocServer {
|
|
23
|
+
server;
|
|
24
|
+
docTree = [];
|
|
25
|
+
uriMap = {};
|
|
26
|
+
categoryMappings = [];
|
|
27
|
+
categoryEnumValues = [];
|
|
28
|
+
initialized = false;
|
|
29
|
+
constructor() {
|
|
30
|
+
this.server = new McpServer({
|
|
31
|
+
name: "feishu-doc-mcp",
|
|
32
|
+
version: "1.0.0",
|
|
33
|
+
});
|
|
34
|
+
this.setupErrorHandling();
|
|
35
|
+
}
|
|
36
|
+
setupErrorHandling() {
|
|
37
|
+
process.on("SIGINT", async () => {
|
|
38
|
+
await this.server.close();
|
|
39
|
+
process.exit(0);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// 初始化并注册工具
|
|
43
|
+
async initializeAndRegisterTools() {
|
|
44
|
+
await this.initialize();
|
|
45
|
+
this.registerTools();
|
|
46
|
+
}
|
|
47
|
+
// 初始化:获取文档树和 URI 映射
|
|
48
|
+
async initialize() {
|
|
49
|
+
if (this.initialized)
|
|
50
|
+
return;
|
|
51
|
+
console.error("[Init] Fetching document tree and URI mapping...");
|
|
52
|
+
try {
|
|
53
|
+
// 并行获取文档树和 URI 映射
|
|
54
|
+
const [treeResponse, mappingResponse] = await Promise.all([
|
|
55
|
+
axios.get(DIRECTORY_LIST_URL, { timeout: 30000 }),
|
|
56
|
+
axios.get(URI_MAPPING_URL, { timeout: 30000 }),
|
|
57
|
+
]);
|
|
58
|
+
if (treeResponse.data.code === 0) {
|
|
59
|
+
this.docTree = treeResponse.data.data.items;
|
|
60
|
+
console.error(`[Init] Loaded ${this.countNodes(this.docTree)} document nodes`);
|
|
61
|
+
}
|
|
62
|
+
if (mappingResponse.data.code === 0) {
|
|
63
|
+
this.uriMap = mappingResponse.data.data.uriMap;
|
|
64
|
+
console.error(`[Init] Loaded ${Object.keys(this.uriMap).length} URI mappings`);
|
|
65
|
+
}
|
|
66
|
+
// 构建目录分类映射
|
|
67
|
+
this.buildCategoryMappings();
|
|
68
|
+
console.error(`[Init] Built ${this.categoryMappings.length} category mappings`);
|
|
69
|
+
this.initialized = true;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error("[Init] Failed to initialize:", error);
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// 计算节点总数
|
|
77
|
+
countNodes(nodes) {
|
|
78
|
+
let count = nodes.length;
|
|
79
|
+
for (const node of nodes) {
|
|
80
|
+
if (node.items?.length) {
|
|
81
|
+
count += this.countNodes(node.items);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return count;
|
|
85
|
+
}
|
|
86
|
+
// 构建目录分类映射(一级目录_二级目录)
|
|
87
|
+
buildCategoryMappings() {
|
|
88
|
+
this.categoryMappings = [];
|
|
89
|
+
this.categoryEnumValues = [];
|
|
90
|
+
for (const level1Node of this.docTree) {
|
|
91
|
+
// 跳过非目录类型
|
|
92
|
+
if (level1Node.type !== "DirectoryType")
|
|
93
|
+
continue;
|
|
94
|
+
const level1Name = level1Node.name;
|
|
95
|
+
// 遍历二级目录
|
|
96
|
+
if (level1Node.items?.length) {
|
|
97
|
+
for (const level2Node of level1Node.items) {
|
|
98
|
+
// 只处理目录类型的二级节点
|
|
99
|
+
if (level2Node.type !== "DirectoryType")
|
|
100
|
+
continue;
|
|
101
|
+
const level2Name = level2Node.name;
|
|
102
|
+
const enumValue = `${level1Name}_${level2Name}`;
|
|
103
|
+
this.categoryMappings.push({
|
|
104
|
+
enumValue,
|
|
105
|
+
level1Name,
|
|
106
|
+
level2Name,
|
|
107
|
+
node: level2Node,
|
|
108
|
+
});
|
|
109
|
+
this.categoryEnumValues.push(enumValue);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// 排序枚举值
|
|
114
|
+
this.categoryEnumValues.sort();
|
|
115
|
+
}
|
|
116
|
+
registerTools() {
|
|
117
|
+
// 注册 search_feishu_doc 工具(使用动态枚举)
|
|
118
|
+
this.server.registerTool("search_feishu_doc", {
|
|
119
|
+
description: "搜索飞书开放平台 API 文档。根据分类浏览文档列表,返回该分类下所有文档的标题和路径。适用于查找特定 API 接口、了解某个功能模块有哪些接口等场景。",
|
|
120
|
+
inputSchema: {
|
|
121
|
+
category: z.enum(this.categoryEnumValues).describe("文档分类,格式为「一级目录_二级目录」,例如「服务端 API_即时通讯」「开发指南_开发机器人」"),
|
|
122
|
+
},
|
|
123
|
+
}, async (args) => {
|
|
124
|
+
const category = args.category;
|
|
125
|
+
return await this.handleSearchDoc(category);
|
|
126
|
+
});
|
|
127
|
+
// 注册 read_feishu_doc 工具
|
|
128
|
+
this.server.registerTool("read_feishu_doc", {
|
|
129
|
+
description: "读取飞书开放平台文档的详细内容。根据文档路径获取完整的 API 说明,并保存到本地临时文件。返回文件路径和文件大小,如果文件较大会包含警告提示。使用 Read 工具读取文件内容,对于大文件建议使用 offset/limit 参数分段读取或使用 Grep 搜索特定内容。",
|
|
130
|
+
inputSchema: {
|
|
131
|
+
path: z.string().describe("文档路径,从 search_feishu_doc 结果中获取"),
|
|
132
|
+
},
|
|
133
|
+
}, async (args) => {
|
|
134
|
+
const docPath = args.path;
|
|
135
|
+
return await this.handleReadDoc(docPath);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// 递归收集目录下所有文档
|
|
139
|
+
collectDocuments(node) {
|
|
140
|
+
const results = [];
|
|
141
|
+
if (node.type === "DocumentType") {
|
|
142
|
+
// 是文档,添加到结果(不再显示位置)
|
|
143
|
+
const pathInfo = this.uriMap[node.fullPath] || node.fullPath;
|
|
144
|
+
results.push(`📄 **${node.name}**\n 路径: \`${pathInfo}\``);
|
|
145
|
+
}
|
|
146
|
+
// 递归处理子节点
|
|
147
|
+
if (node.items?.length) {
|
|
148
|
+
for (const child of node.items) {
|
|
149
|
+
results.push(...this.collectDocuments(child));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return results;
|
|
153
|
+
}
|
|
154
|
+
// 搜索文档
|
|
155
|
+
async handleSearchDoc(category) {
|
|
156
|
+
// 查找对应的分类(调用者已验证 category 有效)
|
|
157
|
+
const mapping = this.categoryMappings.find((m) => m.enumValue === category);
|
|
158
|
+
// 收集该分类下的所有文档
|
|
159
|
+
const documents = this.collectDocuments(mapping.node);
|
|
160
|
+
if (documents.length === 0) {
|
|
161
|
+
return {
|
|
162
|
+
content: [
|
|
163
|
+
{
|
|
164
|
+
type: "text",
|
|
165
|
+
text: `分类 "${category}" 下没有文档。`,
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const output = documents.join("\n\n");
|
|
171
|
+
return {
|
|
172
|
+
content: [
|
|
173
|
+
{
|
|
174
|
+
type: "text",
|
|
175
|
+
text: `📁 **${mapping.level1Name} > ${mapping.level2Name}** 下共有 ${documents.length} 个文档:\n\n${output}\n\n使用 \`read_feishu_doc\` 并传入路径可获取文档详细内容。`,
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
// 生成文档的临时文件路径
|
|
181
|
+
getTempFilePath(docPath) {
|
|
182
|
+
// 使用路径的 hash 作为文件名,避免特殊字符问题
|
|
183
|
+
const hash = crypto.createHash("md5").update(docPath).digest("hex").substring(0, 12);
|
|
184
|
+
// 从路径中提取有意义的名称部分
|
|
185
|
+
const pathParts = docPath.split("/").filter(Boolean);
|
|
186
|
+
const namePart = pathParts.slice(-2).join("_").replace(/[^a-zA-Z0-9_\u4e00-\u9fa5-]/g, "_");
|
|
187
|
+
return path.join(TEMP_DOC_DIR, `${namePart}_${hash}.md`);
|
|
188
|
+
}
|
|
189
|
+
// 确保临时目录存在
|
|
190
|
+
ensureTempDir() {
|
|
191
|
+
if (!fs.existsSync(TEMP_DOC_DIR)) {
|
|
192
|
+
fs.mkdirSync(TEMP_DOC_DIR, { recursive: true });
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// 读取文档内容
|
|
196
|
+
async handleReadDoc(docPath) {
|
|
197
|
+
try {
|
|
198
|
+
// 确定要请求的路径
|
|
199
|
+
let requestPath = docPath;
|
|
200
|
+
// 如果传入的是 fullPath,尝试转换为 mappedPath
|
|
201
|
+
if (this.uriMap[docPath]) {
|
|
202
|
+
requestPath = this.uriMap[docPath];
|
|
203
|
+
}
|
|
204
|
+
// 请求文档内容
|
|
205
|
+
const response = await axios.get(DOC_DETAIL_URL, {
|
|
206
|
+
params: { fullPath: requestPath },
|
|
207
|
+
timeout: 30000,
|
|
208
|
+
});
|
|
209
|
+
if (response.data.code !== 0) {
|
|
210
|
+
throw new Error(`API error: ${response.data.msg || "Unknown error"}`);
|
|
211
|
+
}
|
|
212
|
+
const detail = response.data.data;
|
|
213
|
+
// 提取文档内容
|
|
214
|
+
let content = "";
|
|
215
|
+
// 文档标题
|
|
216
|
+
if (detail.title) {
|
|
217
|
+
content += `# ${detail.title}\n\n`;
|
|
218
|
+
}
|
|
219
|
+
// 文档描述
|
|
220
|
+
if (detail.description) {
|
|
221
|
+
content += `${detail.description}\n\n`;
|
|
222
|
+
}
|
|
223
|
+
// 主要内容 - 通常在 content 或 body 字段
|
|
224
|
+
if (detail.content) {
|
|
225
|
+
// 如果是 HTML,转换为 Markdown
|
|
226
|
+
if (typeof detail.content === "string" && detail.content.includes("<")) {
|
|
227
|
+
content += turndownService.turndown(detail.content);
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
content += detail.content;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else if (detail.body) {
|
|
234
|
+
if (typeof detail.body === "string" && detail.body.includes("<")) {
|
|
235
|
+
content += turndownService.turndown(detail.body);
|
|
236
|
+
}
|
|
237
|
+
else {
|
|
238
|
+
content += JSON.stringify(detail.body, null, 2);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
// 返回原始数据结构供分析
|
|
243
|
+
content += "```json\n" + JSON.stringify(detail, null, 2) + "\n```";
|
|
244
|
+
}
|
|
245
|
+
// 如果存在 schema 字段,追加到内容中
|
|
246
|
+
if (detail.schema) {
|
|
247
|
+
content += "\n\n---\n\n## Schema\n\n";
|
|
248
|
+
content += "```json\n" + JSON.stringify(detail.schema, null, 2) + "\n```";
|
|
249
|
+
}
|
|
250
|
+
const finalContent = content || "文档内容为空";
|
|
251
|
+
// 保存到临时文件
|
|
252
|
+
this.ensureTempDir();
|
|
253
|
+
const tempFilePath = this.getTempFilePath(docPath);
|
|
254
|
+
fs.writeFileSync(tempFilePath, finalContent, "utf-8");
|
|
255
|
+
// 获取文件大小
|
|
256
|
+
const stats = fs.statSync(tempFilePath);
|
|
257
|
+
const fileSizeBytes = stats.size;
|
|
258
|
+
const fileSizeKB = (fileSizeBytes / 1024).toFixed(2);
|
|
259
|
+
// 大文件阈值:50KB(约 50000 字符,可能占用大量 context window)
|
|
260
|
+
const LARGE_FILE_THRESHOLD = 50 * 1024;
|
|
261
|
+
const isLargeFile = fileSizeBytes > LARGE_FILE_THRESHOLD;
|
|
262
|
+
let message = `文档已保存到: ${tempFilePath}\n文件大小: ${fileSizeKB} KB (${fileSizeBytes} bytes)`;
|
|
263
|
+
if (isLargeFile) {
|
|
264
|
+
message += `\n\n⚠️ 警告: 该文档较大,直接读取可能占用大量 context window。建议使用 Read 工具的 offset 和 limit 参数分段读取,或使用 Grep 工具搜索特定内容。`;
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
content: [
|
|
268
|
+
{
|
|
269
|
+
type: "text",
|
|
270
|
+
text: message,
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
if (axios.isAxiosError(error)) {
|
|
277
|
+
throw new Error(`Failed to fetch document: ${error.message}`);
|
|
278
|
+
}
|
|
279
|
+
throw error;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
async run() {
|
|
283
|
+
// 先初始化并注册工具
|
|
284
|
+
await this.initializeAndRegisterTools();
|
|
285
|
+
const transport = new StdioServerTransport();
|
|
286
|
+
await this.server.connect(transport);
|
|
287
|
+
console.error("Feishu Doc MCP Server running on stdio");
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
const server = new FeishuDocServer();
|
|
291
|
+
server.run();
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "feishu-doc-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for Feishu Open Platform Documentation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "build/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"feishu-doc-mcp": "./build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"build",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc && chmod +x build/index.js",
|
|
17
|
+
"dev": "tsc --watch",
|
|
18
|
+
"start": "node build/index.js",
|
|
19
|
+
"prepare": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/ztxtxwd/feishu-doc-mcp.git"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"mcp",
|
|
27
|
+
"model-context-protocol",
|
|
28
|
+
"feishu",
|
|
29
|
+
"lark",
|
|
30
|
+
"documentation",
|
|
31
|
+
"api",
|
|
32
|
+
"claude",
|
|
33
|
+
"ai"
|
|
34
|
+
],
|
|
35
|
+
"author": "ztxtxwd",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/ztxtxwd/feishu-doc-mcp/issues"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/ztxtxwd/feishu-doc-mcp#readme",
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
43
|
+
"axios": "^1.6.0",
|
|
44
|
+
"turndown": "^7.1.0",
|
|
45
|
+
"zod": "^4.2.1",
|
|
46
|
+
"zod-to-json-schema": "^3.25.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^20.0.0",
|
|
50
|
+
"@types/turndown": "^5.0.0",
|
|
51
|
+
"typescript": "^5.0.0"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=18"
|
|
55
|
+
}
|
|
56
|
+
}
|