get_notebook_mcp_server 1.0.3 → 1.1.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/README.md CHANGED
@@ -1,15 +1,21 @@
1
- # Get Notes MCP Server
1
+ # Get Notes MCP Server / Get 笔记 MCP 服务器
2
+
3
+ [English](#english) | [中文](#chinese)
4
+
5
+ <a name="english"></a>
6
+
7
+ ## 🇬🇧 English
2
8
 
3
9
  A Model Context Protocol (MCP) server for integrating with Get Notes API. This server provides tools to search and recall knowledge from your Get Notes knowledge base.
4
10
 
5
- ## Features
11
+ ### Features
6
12
 
7
13
  - **Knowledge Search**: AI-processed search that returns synthesized answers and references.
8
14
  - **Knowledge Recall**: Raw recall of relevant notes and files.
9
15
  - **Rate Limiting**: Built-in protection with QPS < 2 and Total Requests < 5000 limits.
10
16
  - **Retry Mechanism**: Automatic retries for transient network errors (5xx).
11
17
 
12
- ## Installation
18
+ ### Installation
13
19
 
14
20
  1. Clone the repository
15
21
  2. Install dependencies:
@@ -22,90 +28,448 @@ A Model Context Protocol (MCP) server for integrating with Get Notes API. This s
22
28
  ```
23
29
  4. Configure your API key in `.env`:
24
30
  ```
25
- GET_API_KEY=your_api_key_here
31
+ GET_API_KEY=T0TR1HWqw+tL00gVc5PPoXDnGIUIuPw7QCBeb1dMC6afCojR9WpHyuZicEFJjkMg3oZYS0HB/S3vqOj7+0e5FGoVtYuv938zkR8=
32
+ GET_NOTE_TOPIC_ID=RYk1kmRJ
26
33
  ```
27
34
 
28
- ## Usage
35
+ ### Usage
29
36
 
30
- ### Running the Server
37
+ #### Running with npx
38
+
39
+ You can run the server directly without installing it using `npx`:
31
40
 
32
41
  ```bash
33
- node index.js
42
+ npx get_notebook_mcp_server
34
43
  ```
35
44
 
36
- ### Testing with MCP Inspector
45
+ #### MCP Configuration (Claude Desktop)
37
46
 
38
- You can test the MCP server interactively using the MCP Inspector:
47
+ **Option 1: Single Knowledge Base (Simple Setup)**
39
48
 
40
- ```bash
41
- npx @modelcontextprotocol/inspector node index.js
49
+ For a single knowledge base, add this to your `claude_desktop_config.json`:
50
+
51
+ ```json
52
+ {
53
+ "mcpServers": {
54
+ "get-notes": {
55
+ "command": "npx",
56
+ "args": ["-y", "get_notebook_mcp_server"],
57
+ "env": {
58
+ "GET_API_KEY": "T0TR1HWqw+tL00gVc5PPoXDnGIUIuPw7QCBeb1dMC6afCojR9WpHyuZicEFJjkMg3oZYS0HB/S3vqOj7+0e5FGoVtYuv938zkR8=",
59
+ "GET_NOTE_TOPIC_ID": "RYk1kmRJ"
60
+ }
61
+ }
62
+ }
63
+ }
42
64
  ```
43
65
 
44
- ### Running with npx
66
+ **Option 2: Multiple Knowledge Bases (Grouped Configuration - Recommended)**
45
67
 
46
- You can run the server directly without installing it using `npx`:
68
+ For multiple knowledge bases sharing the same API key, use grouped configuration. The system will automatically expand them into individual knowledge bases:
47
69
 
48
- ```bash
49
- npx get_notebook_mcp_server
70
+ ```json
71
+ {
72
+ "mcpServers": {
73
+ "get-notes": {
74
+ "command": "npx",
75
+ "args": ["-y", "get_notebook_mcp_server"],
76
+ "env": {
77
+ "GET_KNOWLEDGE_BASES": "[{\"id\":\"medical_group\",\"name\":\"Medical Knowledge Bases\",\"config\":{\"api_key\":\"T0TR1HWqw+tL00gVc5PPoXDnGIUIuPw7QCBeb1dMC6afCojR9WpHyuZicEFJjkMg3oZYS0HB/S3vqOj7+0e5FGoVtYuv938zkR8=\",\"topics\":[{\"id\":\"kb_pancreatic_trials\",\"name\":\"Tumor Clinical Trials KB\",\"topic_id\":\"RYk1kmRJ\"},{\"id\":\"kb_patient_experience\",\"name\":\"Patient Experience KB\",\"topic_id\":\"mnyV9OjY\"}]}}]"
78
+ }
79
+ }
80
+ }
81
+ }
50
82
  ```
51
83
 
52
- ### MCP Configuration (Claude Desktop)
84
+ This configuration will be automatically expanded into two independent knowledge bases: `kb_pancreatic_trials` and `kb_patient_experience`.
85
+
86
+ **Option 3: Using Local Configuration File (Recommended for Development)**
87
+
88
+ Create a `knowledge_bases.json` file in your project root:
89
+
90
+ ```json
91
+ [
92
+ {
93
+ "id": "demo_group",
94
+ "name": "Sam's Knowledge Bases",
95
+ "description": "Knowledge bases sharing the same API Key",
96
+ "config": {
97
+ "api_key": "T0TR1HWqw+tL00gVc5PPoXDnGIUIuPw7QCBeb1dMC6afCojR9WpHyuZicEFJjkMg3oZYS0HB/S3vqOj7+0e5FGoVtYuv938zkR8=",
98
+ "api_endpoint": "https://open-api.biji.com/getnote/openapi",
99
+ "topics": [
100
+ {
101
+ "id": "kb_pancreatic_trials",
102
+ "name": "Tumor Clinical Trials Knowledge Base",
103
+ "description": "Knowledge base about tumor clinical trials",
104
+ "topic_id": "RYk1kmRJ"
105
+ },
106
+ {
107
+ "id": "kb_patient_experience",
108
+ "name": "Patient Experience Information",
109
+ "description": "Patient experience info including guidelines and treatment experiences",
110
+ "topic_id": "mnyV9OjY"
111
+ }
112
+ ]
113
+ }
114
+ }
115
+ ]
116
+ ```
53
117
 
54
- Add the following configuration to your `claude_desktop_config.json`:
118
+ Then configure Claude Desktop to use the local file:
55
119
 
56
120
  ```json
57
121
  {
58
122
  "mcpServers": {
59
123
  "get-notes": {
60
124
  "command": "npx",
61
- "args": [
62
- "-y",
63
- "get_notebook_mcp_server"
64
- ],
65
- "env": {
66
- "GET_API_KEY": "your_api_key_here",
67
- "GET_NOTE_TOPIC_ID": "your_topic_id_here"
68
- }
125
+ "args": ["-y", "get_notebook_mcp_server"]
69
126
  }
70
127
  }
71
128
  }
72
129
  ```
73
130
 
131
+ #### How Claude Uses Multiple Knowledge Bases
132
+
133
+ **Claude automatically selects the appropriate knowledge base - no manual selection needed!**
134
+
135
+ **Workflow:**
136
+ 1. **User asks a question**: "How long after pancreatic cancer surgery should chemotherapy start?"
137
+ 2. **Claude automatically calls `list_knowledge_bases`**: Views all available knowledge bases
138
+ 3. **Claude intelligently selects**: Based on the question content, automatically chooses the most relevant KB (e.g., `kb_pancreatic_trials`)
139
+ 4. **Claude calls `search_knowledge`**: Passes the selected `kb_id` and the question
140
+ 5. **Returns results**: Claude synthesizes the search results into an answer
141
+
142
+ **Users can also specify explicitly:**
143
+ - "Search in the Tumor Clinical Trials KB: pancreatic cancer chemotherapy timing"
144
+ - "Find in Patient Experience: chemotherapy side effect management"
145
+
146
+ This way Claude knows exactly which knowledge base to use.
147
+
148
+ #### Running Locally
149
+
150
+ ```bash
151
+ node index.js
152
+ ```
153
+
154
+ #### Testing with MCP Inspector
155
+
156
+ You can test the MCP server interactively using the MCP Inspector:
157
+
158
+ ```bash
159
+ npx @modelcontextprotocol/inspector node index.js
160
+ ```
161
+
74
162
  ### Tools
75
163
 
164
+ #### `list_knowledge_bases`
165
+ List all available knowledge bases with their IDs, names, and descriptions.
166
+
167
+ **Parameters:** None
168
+
169
+ **Returns:** Array of knowledge base information (without sensitive API keys)
170
+
76
171
  #### `search_knowledge`
77
172
  Search the knowledge base with AI processing.
78
173
 
79
174
  **Parameters:**
175
+ - `kb_id` (string, optional): Knowledge base ID. If not provided, uses the first configured KB.
80
176
  - `question` (string, required): The question to ask.
81
- - `topic_ids` (array<string>, optional): List of knowledge base IDs. If not provided, uses `GET_NOTE_TOPIC_ID` from environment.
82
- - `deep_seek` (boolean): Enable deep thinking mode (default: true).
177
+ - `deep_seek` (boolean): Enable deep thinking mode (default: false).
83
178
  - `history` (array): Chat history for context.
84
179
 
85
180
  #### `recall_knowledge`
86
181
  Raw recall from knowledge base without AI synthesis.
87
182
 
88
183
  **Parameters:**
184
+ - `kb_id` (string, optional): Knowledge base ID. If not provided, uses the first configured KB.
89
185
  - `question` (string, required): The question or query.
90
- - `topic_id` (string, optional): Knowledge base ID. If not provided, uses `GET_NOTE_TOPIC_ID` from environment.
91
186
  - `top_k` (number): Number of results to return (default: 10).
92
187
  - `intent_rewrite` (boolean): Enable intent rewrite (default: false).
93
188
 
94
- ## Development
189
+ ### Development
95
190
 
96
- ### Running Tests
191
+ #### Running Tests
97
192
 
98
193
  ```bash
99
194
  npm test
100
195
  ```
101
196
 
102
- ### Project Structure
197
+ #### Project Structure
103
198
 
104
199
  - `src/api`: API client implementation
105
200
  - `src/utils`: Utility classes (RateLimiter, etc.)
106
201
  - `tests`: Unit and integration tests
107
202
  - `index.js`: Main MCP server entry point
108
203
 
109
- ## License
204
+ ### License
205
+
206
+ ISC
207
+
208
+ ### ❤️ Acknowledgments
209
+
210
+ This project is contributed by the **Xiao-X-Bao Community** - an AI open-source public welfare community focused on improving medical information access for cancer/rare disease patients and their families throughout their life cycle.
211
+
212
+ #### About Xiao-X-Bao Community
213
+
214
+ We are an AI open-source public welfare community dedicated to using AI technology to build a high-quality, high-density patient knowledge ecosystem to improve medical information barriers. Our community brings together a diverse group of open-source contributors, AI technology experts, cancer patients, family members, medical professionals, and public welfare volunteers, working together to improve the information access challenges faced by patients.
215
+
216
+ **Community Website**: https://info.xiao-x-bao.com.cn
217
+
218
+ **Our Mission**: To use AI technology to break down medical information barriers and build a comprehensive knowledge ecosystem for patients.
219
+
220
+ **Origin of Community Name**: All our AI assistants are named "Xiao-X-Bao" (Little X Treasure), such as "Xiao Yi Bao" (Little Pancreas Treasure), "Xiao Fen Bao" (Little Pink Treasure), etc., hence our community is named "Xiao-X-Bao Community".
221
+
222
+ **Community Development**: In 2024, the project was donated to the "Tiangong Kaiwu Foundation", which provides funding and guidance to promote public welfare initiatives.
223
+
224
+ **Progress Updates**: Published via the WeChat Official Account "Xiao Yi Bao Assistant".
225
+
226
+ #### Community Contact
227
+
228
+ **Detailed Community Introduction**: [View Introduction](https://uei55ql5ok.feishu.cn/wiki/ULuKwHuv1iEM8gkrFTecP8DqnSd)
229
+
230
+ **Contact Us**:
231
+ - WeChat: qinxiaoqiang2002
232
+ - WeChat: hhxdeweixinxin
233
+ - WeChat: zhuangbiaowei
234
+
235
+ We welcome all contributors, developers, medical professionals, and volunteers to join our community and use technology to improve medical information accessibility! 🌟
236
+
237
+ ---
238
+
239
+ <a name="chinese"></a>
240
+
241
+ ## 🇨🇳 中文
242
+
243
+ 这是一个用于集成 Get 笔记 API 的 Model Context Protocol (MCP) 服务器。该服务器提供了从您的 Get 笔记知识库中搜索和召回知识的工具。
244
+
245
+ ### 功能特性
246
+
247
+ - **知识库搜索 (Knowledge Search)**:经过 AI 处理的搜索,返回综合的答案和引用。
248
+ - **知识库召回 (Knowledge Recall)**:相关笔记和文件的原始召回。
249
+ - **速率限制 (Rate Limiting)**:内置保护,限制 QPS < 2 和总请求数 < 5000。
250
+ - **重试机制 (Retry Mechanism)**:针对瞬时网络错误 (5xx) 的自动重试。
251
+
252
+ ### 安装
253
+
254
+ 1. 克隆仓库
255
+ 2. 安装依赖:
256
+ ```bash
257
+ npm install
258
+ ```
259
+ 3. 从示例创建 `.env` 文件:
260
+ ```bash
261
+ cp .env.example .env
262
+ ```
263
+ 4. 在 `.env` 中配置您的 API 密钥:
264
+ ```
265
+ GET_API_KEY=T0TR1HWqw+tL00gVc5PPoXDnGIUIuPw7QCBeb1dMC6afCojR9WpHyuZicEFJjkMg3oZYS0HB/S3vqOj7+0e5FGoVtYuv938zkR8=
266
+ GET_NOTE_TOPIC_ID=RYk1kmRJ
267
+ ```
268
+
269
+ ### 使用方法
270
+
271
+ #### 使用 npx 运行
272
+
273
+ 您可以直接使用 `npx` 运行服务器,无需安装:
274
+
275
+ ```bash
276
+ npx get_notebook_mcp_server
277
+ ```
278
+
279
+ #### MCP 配置 (Claude Desktop)
280
+
281
+ 将以下配置添加到您的 `claude_desktop_config.json`:
282
+
283
+ **方式1:单个知识库(简单配置)**
284
+
285
+ ```json
286
+ {
287
+ "mcpServers": {
288
+ "get-notes": {
289
+ "command": "npx",
290
+ "args": [
291
+ "-y",
292
+ "get_notebook_mcp_server"
293
+ ],
294
+ "env": {
295
+ "GET_API_KEY": "T0TR1HWqw+tL00gVc5PPoXDnGIUIuPw7QCBeb1dMC6afCojR9WpHyuZicEFJjkMg3oZYS0HB/S3vqOj7+0e5FGoVtYuv938zkR8=",
296
+ "GET_NOTE_TOPIC_ID": "RYk1kmRJ"
297
+ }
298
+ }
299
+ }
300
+ }
301
+ ```
302
+
303
+ **方式2:多知识库(分组配置,推荐)**
304
+
305
+ 如果多个知识库共享同一个 API Key,可以使用分组配置。系统会自动将其展开为独立的知识库:
306
+
307
+ ```json
308
+ {
309
+ "mcpServers": {
310
+ "get-notes-multi": {
311
+ "command": "npx",
312
+ "args": [
313
+ "-y",
314
+ "get_notebook_mcp_server"
315
+ ],
316
+ "env": {
317
+ "GET_KNOWLEDGE_BASES": "[{\"id\":\"medical_group\",\"name\":\"医学知识库组\",\"config\":{\"api_key\":\"T0TR1HWqw+tL00gVc5PPoXDnGIUIuPw7QCBeb1dMC6afCojR9WpHyuZicEFJjkMg3oZYS0HB/S3vqOj7+0e5FGoVtYuv938zkR8=\",\"topics\":[{\"id\":\"kb_pancreatic_trials\",\"name\":\"肿瘤临床试验知识库\",\"topic_id\":\"RYk1kmRJ\"},{\"id\":\"kb_patient_experience\",\"name\":\"小胰宝病友经验信息\",\"topic_id\":\"mnyV9OjY\"}]}}]"
318
+ }
319
+ }
320
+ }
321
+ }
322
+ ```
323
+
324
+ 上述配置会自动展开为两个独立的知识库:`kb_pancreatic_trials` 和 `kb_patient_experience`。
325
+
326
+ **方式3:使用本地配置文件(推荐用于开发)**
327
+
328
+ 在项目根目录创建 `knowledge_bases.json` 文件:
329
+
330
+ ```json
331
+ [
332
+ {
333
+ "id": "demo_group",
334
+ "name": "sam的知识库",
335
+ "description": "使用同一个 API Key 的知识库",
336
+ "config": {
337
+ "api_key": "T0TR1HWqw+tL00gVc5PPoXDnGIUIuPw7QCBeb1dMC6afCojR9WpHyuZicEFJjkMg3oZYS0HB/S3vqOj7+0e5FGoVtYuv938zkR8=",
338
+ "api_endpoint": "https://open-api.biji.com/getnote/openapi",
339
+ "topics": [
340
+ {
341
+ "id": "kb_pancreatic_trials",
342
+ "name": "肿瘤临床试验知识库",
343
+ "description": "有关肿瘤临床试验的知识库",
344
+ "topic_id": "RYk1kmRJ"
345
+ },
346
+ {
347
+ "id": "kb_patient_experience",
348
+ "name": "小胰宝病友经验信息",
349
+ "description": "小胰宝病友经验信息,包括各种指南和治疗经验",
350
+ "topic_id": "mnyV9OjY"
351
+ }
352
+ ]
353
+ }
354
+ }
355
+ ]
356
+ ```
357
+
358
+ 然后在 Claude Desktop 配置中使用本地文件:
359
+
360
+ ```json
361
+ {
362
+ "mcpServers": {
363
+ "get-notes": {
364
+ "command": "npx",
365
+ "args": ["-y", "get_notebook_mcp_server"]
366
+ }
367
+ }
368
+ }
369
+ ```
370
+
371
+ #### Claude 如何使用多知识库
372
+
373
+ **Claude 会自动选择合适的知识库,无需手动选择!**
374
+
375
+ **工作流程:**
376
+ 1. **用户提问**:"胰腺癌术后多久开始化疗?"
377
+ 2. **Claude 自动调用 `list_knowledge_bases`**:查看所有可用的知识库
378
+ 3. **Claude 智能选择**:根据问题内容,自动选择最相关的知识库(如 `kb_pancreatic_trials`)
379
+ 4. **Claude 调用 `search_knowledge`**:传入选定的 `kb_id` 和问题
380
+ 5. **返回结果**:Claude 综合搜索结果给出答案
381
+
382
+ **用户也可以明确指定:**
383
+ - "在肿瘤临床试验知识库中搜索:胰腺癌化疗方案"
384
+ - "在小胰宝病友经验中查找:化疗副作用处理方法"
385
+
386
+ 这样 Claude 就会明确使用指定的知识库。
387
+
388
+ #### 本地运行
389
+
390
+ ```bash
391
+ node index.js
392
+ ```
393
+
394
+ #### 使用 MCP Inspector 测试
395
+
396
+ 您可以使用 MCP Inspector 交互式测试 MCP 服务器:
397
+
398
+ ```bash
399
+ npx @modelcontextprotocol/inspector node index.js
400
+ ```
401
+
402
+ ### 工具说明
403
+
404
+ #### `list_knowledge_bases`
405
+ 列出所有可用的知识库及其 ID、名称和描述。
406
+
407
+ **参数:** 无
408
+
409
+ **返回:** 知识库信息数组(不包含敏感的 API 密钥)
410
+
411
+ #### `search_knowledge`
412
+ 使用 AI 处理搜索知识库。
413
+
414
+ **参数:**
415
+ - `kb_id` (string, 可选): 知识库 ID。如果未提供,使用第一个配置的知识库。
416
+ - `question` (string, 必需): 要提问的问题。
417
+ - `deep_seek` (boolean): 启用深度思考模式(默认值:false)。
418
+ - `history` (array): 用于上下文的聊天历史。
419
+
420
+ #### `recall_knowledge`
421
+ 从知识库原始召回,不进行 AI 综合。
422
+
423
+ **参数:**
424
+ - `kb_id` (string, 可选): 知识库 ID。如果未提供,使用第一个配置的知识库。
425
+ - `question` (string, 必需): 问题或查询。
426
+ - `top_k` (number): 返回结果数量(默认值:10)。
427
+ - `intent_rewrite` (boolean): 启用意图重写(默认值:false)。
428
+
429
+ ### 开发
430
+
431
+ #### 运行测试
432
+
433
+ ```bash
434
+ npm test
435
+ ```
436
+
437
+ #### 项目结构
438
+
439
+ - `src/api`:API 客户端实现
440
+ - `src/utils`:工具类(速率限制器等)
441
+ - `tests`:单元和集成测试
442
+ - `index.js`:MCP 服务器主入口点
443
+
444
+ ### 许可证
110
445
 
111
446
  ISC
447
+
448
+ ### ❤️ 致谢
449
+
450
+ 本项目由**小x宝社区**贡献 - 一个专注于改善癌症/罕见病患者及其家庭整个生命周期医疗信息获取的AI开源公益社区。
451
+
452
+ #### 关于小x宝社区
453
+
454
+ 我们是一个AI开源公益社区,致力于使用AI技术构建高质量、高密度的患者知识生态系统,以改善医疗信息壁垒。我们的社区汇聚了开源贡献者、AI技术专家、癌症患者、家庭成员、医疗专业人员和公益志愿者等多元化群体,共同努力改善患者面临的信息获取挑战。
455
+
456
+ **社区网站**:https://info.xiao-x-bao.com.cn
457
+
458
+ **我们的使命**:使用AI技术打破医疗信息壁垒,为患者构建全面的知识生态系统。
459
+
460
+ **社区名称由来**:我们所有的AI助手都以"小x宝"命名,如"小胰宝"、"小粉宝"等,因此我们的社区命名为"小x宝社区"。
461
+
462
+ **社区发展**:2024年,项目捐赠给"天工开物基金会",该基金会提供资金和指导以促进公益倡议。
463
+
464
+ **进展更新**:通过微信公众号"小胰宝助手"发布。
465
+
466
+ #### 社区联系方式
467
+
468
+ **详细社区介绍**: [查看介绍](https://uei55ql5ok.feishu.cn/wiki/ULuKwHuv1iEM8gkrFTecP8DqnSd)
469
+
470
+ **社区联系方式**:
471
+ - 微信号: qinxiaoqiang2002
472
+ - 微信号: hhxdeweixinxin
473
+ - 微信号: zhuangbiaowei
474
+
475
+ 我们欢迎所有贡献者、开发人员、医疗专业人员和志愿者加入我们的社区,使用技术改善医疗信息可及性!🌟
package/index.js CHANGED
@@ -9,19 +9,10 @@ import { z } from 'zod';
9
9
  import dotenv from 'dotenv';
10
10
  import { ApiClient } from './src/api/client.js';
11
11
  import logger from './src/logger.js';
12
+ import { loadKnowledgeBases, getKnowledgeBases, getKnowledgeBaseById } from './src/config/knowledgeBases.js';
12
13
 
13
14
  dotenv.config();
14
15
 
15
- const API_KEY = process.env.GET_API_KEY;
16
- const DEFAULT_TOPIC_ID = process.env.GET_NOTE_TOPIC_ID;
17
-
18
- if (!API_KEY) {
19
- logger.error('GET_API_KEY environment variable is required');
20
- process.exit(1);
21
- }
22
-
23
- const apiClient = new ApiClient({ apiKey: API_KEY });
24
-
25
16
  const server = new Server(
26
17
  {
27
18
  name: 'get-notes-mcp',
@@ -37,25 +28,33 @@ const server = new Server(
37
28
  /**
38
29
  * Tool Definitions
39
30
  */
31
+ const LIST_KNOWLEDGE_BASES_TOOL = {
32
+ name: 'list_knowledge_bases',
33
+ description: 'List available knowledge bases with their IDs and descriptions. You MUST use this tool first to find the correct kb_id for search_knowledge or recall_knowledge.',
34
+ inputSchema: {
35
+ type: 'object',
36
+ properties: {},
37
+ }
38
+ };
39
+
40
40
  const SEARCH_KNOWLEDGE_TOOL = {
41
41
  name: 'search_knowledge',
42
42
  description: 'Search knowledge base with AI processing. Returns synthesized answers and references.',
43
43
  inputSchema: {
44
44
  type: 'object',
45
45
  properties: {
46
+ kb_id: {
47
+ type: 'string',
48
+ description: 'The ID of the knowledge base to search. Optional if only one KB is configured or to use the default.'
49
+ },
46
50
  question: {
47
51
  type: 'string',
48
52
  description: 'The question to ask'
49
53
  },
50
- topic_ids: {
51
- type: 'array',
52
- items: { type: 'string' },
53
- description: 'List of knowledge base IDs. If not provided, uses the default configured topic ID.'
54
- },
55
54
  deep_seek: {
56
55
  type: 'boolean',
57
56
  description: 'Enable deep thinking mode',
58
- default: true
57
+ default: false
59
58
  },
60
59
  history: {
61
60
  type: 'array',
@@ -79,13 +78,13 @@ const RECALL_KNOWLEDGE_TOOL = {
79
78
  inputSchema: {
80
79
  type: 'object',
81
80
  properties: {
82
- question: {
81
+ kb_id: {
83
82
  type: 'string',
84
- description: 'The question or query'
83
+ description: 'The ID of the knowledge base to search. Optional if only one KB is configured or to use the default.'
85
84
  },
86
- topic_id: {
85
+ question: {
87
86
  type: 'string',
88
- description: 'Knowledge base ID. If not provided, uses the default configured topic ID.'
87
+ description: 'The question or query'
89
88
  },
90
89
  top_k: {
91
90
  type: 'number',
@@ -104,7 +103,7 @@ const RECALL_KNOWLEDGE_TOOL = {
104
103
 
105
104
  server.setRequestHandler(ListToolsRequestSchema, async () => {
106
105
  return {
107
- tools: [SEARCH_KNOWLEDGE_TOOL, RECALL_KNOWLEDGE_TOOL],
106
+ tools: [LIST_KNOWLEDGE_BASES_TOOL, SEARCH_KNOWLEDGE_TOOL, RECALL_KNOWLEDGE_TOOL],
108
107
  };
109
108
  });
110
109
 
@@ -113,24 +112,55 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
113
112
  const { name, arguments: args } = request.params;
114
113
 
115
114
  switch (name) {
115
+ case 'list_knowledge_bases': {
116
+ const kbs = getKnowledgeBases();
117
+ // Return simplified list (hide sensitive config)
118
+ const publicKbs = kbs.map(kb => ({
119
+ id: kb.id,
120
+ name: kb.name,
121
+ description: kb.description
122
+ }));
123
+
124
+ return {
125
+ content: [
126
+ {
127
+ type: 'text',
128
+ text: JSON.stringify(publicKbs, null, 2),
129
+ },
130
+ ],
131
+ };
132
+ }
133
+
116
134
  case 'search_knowledge': {
117
- const params = { ...args };
118
-
119
- // Handle default topic_ids
120
- if (!params.topic_ids || params.topic_ids.length === 0) {
121
- if (DEFAULT_TOPIC_ID) {
122
- params.topic_ids = [DEFAULT_TOPIC_ID];
123
- } else {
124
- throw new Error('topic_ids is required (no default configured)');
135
+ const { kb_id, ...params } = args;
136
+ let kb;
137
+
138
+ if (kb_id) {
139
+ kb = getKnowledgeBaseById(kb_id);
140
+ if (!kb) {
141
+ throw new Error(`Knowledge base not found: ${kb_id}`);
142
+ }
143
+ } else {
144
+ // Default to the first one
145
+ const kbs = getKnowledgeBases();
146
+ if (kbs.length === 0) {
147
+ throw new Error('No knowledge bases configured');
125
148
  }
149
+ kb = kbs[0];
126
150
  }
127
151
 
128
- // Ensure topic_ids is array
129
- if (!Array.isArray(params.topic_ids)) {
130
- throw new Error('topic_ids must be an array');
152
+ // Initialize client for this specific KB
153
+ const client = new ApiClient({
154
+ apiKey: kb.config.api_key,
155
+ baseUrl: kb.config.api_endpoint
156
+ });
157
+
158
+ // Inject topic_id from config (API requires array format but only supports 1)
159
+ if (kb.config.topic_id) {
160
+ params.topic_ids = [kb.config.topic_id];
131
161
  }
132
162
 
133
- const response = await apiClient.searchKnowledge(params);
163
+ const response = await client.searchKnowledge(params);
134
164
 
135
165
  return {
136
166
  content: [
@@ -143,18 +173,34 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
143
173
  }
144
174
 
145
175
  case 'recall_knowledge': {
146
- const params = { ...args };
147
-
148
- // Handle default topic_id
149
- if (!params.topic_id) {
150
- if (DEFAULT_TOPIC_ID) {
151
- params.topic_id = DEFAULT_TOPIC_ID;
152
- } else {
153
- throw new Error('topic_id is required (no default configured)');
176
+ const { kb_id, ...params } = args;
177
+ let kb;
178
+
179
+ if (kb_id) {
180
+ kb = getKnowledgeBaseById(kb_id);
181
+ if (!kb) {
182
+ throw new Error(`Knowledge base not found: ${kb_id}`);
154
183
  }
184
+ } else {
185
+ // Default to the first one
186
+ const kbs = getKnowledgeBases();
187
+ if (kbs.length === 0) {
188
+ throw new Error('No knowledge bases configured');
189
+ }
190
+ kb = kbs[0];
191
+ }
192
+
193
+ const client = new ApiClient({
194
+ apiKey: kb.config.api_key,
195
+ baseUrl: kb.config.api_endpoint
196
+ });
197
+
198
+ // Inject topic_id from config
199
+ if (kb.config.topic_id) {
200
+ params.topic_id = kb.config.topic_id;
155
201
  }
156
202
 
157
- const response = await apiClient.recallKnowledge(params);
203
+ const response = await client.recallKnowledge(params);
158
204
  return {
159
205
  content: [
160
206
  {
@@ -183,6 +229,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
183
229
  });
184
230
 
185
231
  async function runServer() {
232
+ await loadKnowledgeBases();
186
233
  const transport = new StdioServerTransport();
187
234
  await server.connect(transport);
188
235
  logger.info('Get Notes MCP Server running on stdio');
@@ -0,0 +1,25 @@
1
+ [
2
+ {
3
+ "id": "demo_group",
4
+ "name": "sam的知识库",
5
+ "description": "使用同一个 API Key 的示例知识库(方案3:分组配置)",
6
+ "config": {
7
+ "api_key": "T0TR1HWqw+tL00gVc5PPoXDnGIUIuPw7QCBeb1dMC6afCojR9WpHyuZicEFJjkMg3oZYS0HB/S3vqOj7+0e5FGoVtYuv938zkR8=",
8
+ "api_endpoint": "https://open-api.biji.com/getnote/openapi",
9
+ "topics": [
10
+ {
11
+ "id": "kb_pancreatic_trials",
12
+ "name": "肿瘤临床试验知识库",
13
+ "description": "有关肿瘤临床试验的知识库",
14
+ "topic_id": "RYk1kmRJ"
15
+ },
16
+ {
17
+ "id": "kb_patient_experience",
18
+ "name": "小胰宝病友经验信息",
19
+ "description": "小胰宝病友经验信息,包括各种指南和治疗经验",
20
+ "topic_id": "mnyV9OjY"
21
+ }
22
+ ]
23
+ }
24
+ }
25
+ ]
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "get_notebook_mcp_server",
3
- "version": "1.0.3",
4
- "description": "MCP server for Get Notes API integration",
3
+ "version": "1.1.0",
4
+ "description": "MCP server for Get Notes API integration with multi-knowledge base support",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "bin": {
@@ -9,7 +9,8 @@
9
9
  },
10
10
  "files": [
11
11
  "index.js",
12
- "src"
12
+ "src",
13
+ "knowledge_bases.json"
13
14
  ],
14
15
  "scripts": {
15
16
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
@@ -0,0 +1,130 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import dotenv from 'dotenv';
5
+
6
+ dotenv.config();
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const CONFIG_PATH = path.resolve(__dirname, '../../knowledge_bases.json');
10
+
11
+ let knowledgeBases = [];
12
+
13
+ export async function loadKnowledgeBases() {
14
+ try {
15
+ const data = await fs.readFile(CONFIG_PATH, 'utf-8');
16
+ knowledgeBases = JSON.parse(data);
17
+ } catch (error) {
18
+ console.warn('Warning: Could not load knowledge_bases.json, using empty list or environment variables.', error.message);
19
+ knowledgeBases = [];
20
+ }
21
+
22
+ // Backward compatibility: Inject KB from environment variables if they exist
23
+ const envApiKey = process.env.GET_API_KEY;
24
+ const envTopicId = process.env.GET_NOTE_TOPIC_ID;
25
+
26
+ if (envApiKey) {
27
+ // Check if already exists to avoid duplicates
28
+ const defaultId = 'default_env_kb';
29
+ const exists = knowledgeBases.find(kb => kb.id === defaultId);
30
+
31
+ if (!exists) {
32
+ knowledgeBases.unshift({
33
+ id: defaultId,
34
+ name: "Default Knowledge Base (Env)",
35
+ description: "Configured via environment variables",
36
+ config: {
37
+ api_endpoint: process.env.GET_API_ENDPOINT || 'https://open-api.biji.com/getnote/openapi',
38
+ api_key: envApiKey,
39
+ topic_id: envTopicId || ''
40
+ }
41
+ });
42
+ }
43
+ }
44
+
45
+ // Support for multiple KBs via environment variable (JSON string)
46
+ const envKbsJson = process.env.GET_KNOWLEDGE_BASES;
47
+ if (envKbsJson) {
48
+ try {
49
+ const envKbs = JSON.parse(envKbsJson);
50
+ if (Array.isArray(envKbs)) {
51
+ const DEFAULT_ENDPOINT = 'https://open-api.biji.com/getnote/openapi';
52
+ // Merge strategies: Append? Prepend? Overwrite?
53
+ // Let's append, but filter out duplicates by ID
54
+ for (const kb of envKbs) {
55
+ if (!knowledgeBases.find(existing => existing.id === kb.id)) {
56
+ // Apply defaults
57
+ if (kb.config && !kb.config.api_endpoint) {
58
+ kb.config.api_endpoint = DEFAULT_ENDPOINT;
59
+ }
60
+ knowledgeBases.push(kb);
61
+ }
62
+ }
63
+ }
64
+ } catch (e) {
65
+ console.warn('Failed to parse GET_KNOWLEDGE_BASES environment variable:', e.message);
66
+ }
67
+ }
68
+
69
+ // Expand grouped configurations
70
+ knowledgeBases = expandKnowledgeBases(knowledgeBases);
71
+
72
+ // Normalize configs: ensure api_endpoint and topic_id are set
73
+ const DEFAULT_ENDPOINT = 'https://open-api.biji.com/getnote/openapi';
74
+ knowledgeBases.forEach(kb => {
75
+ if (kb.config) {
76
+ if (!kb.config.api_endpoint) {
77
+ kb.config.api_endpoint = DEFAULT_ENDPOINT;
78
+ }
79
+ // Ensure topic_id is set (no longer support topic_ids array)
80
+ if (!kb.config.topic_id) {
81
+ kb.config.topic_id = '';
82
+ }
83
+ }
84
+ });
85
+
86
+ return knowledgeBases;
87
+ }
88
+
89
+ /**
90
+ * Expand grouped knowledge base configurations into individual entries.
91
+ * A grouped config has a 'topics' array in its config, where each topic
92
+ * becomes an independent knowledge base entry.
93
+ *
94
+ * @param {Array} rawConfig - Raw configuration array
95
+ * @returns {Array} Expanded configuration array
96
+ */
97
+ function expandKnowledgeBases(rawConfig) {
98
+ const expanded = [];
99
+
100
+ for (const group of rawConfig) {
101
+ if (group.config && group.config.topics && Array.isArray(group.config.topics)) {
102
+ // Grouped configuration: expand into multiple independent KBs
103
+ for (const topic of group.config.topics) {
104
+ expanded.push({
105
+ id: topic.id,
106
+ name: topic.name,
107
+ description: topic.description || '',
108
+ config: {
109
+ api_key: group.config.api_key,
110
+ api_endpoint: group.config.api_endpoint || 'https://open-api.biji.com/getnote/openapi',
111
+ topic_id: topic.topic_id
112
+ }
113
+ });
114
+ }
115
+ } else {
116
+ // Regular configuration: keep as-is
117
+ expanded.push(group);
118
+ }
119
+ }
120
+
121
+ return expanded;
122
+ }
123
+
124
+ export function getKnowledgeBases() {
125
+ return knowledgeBases;
126
+ }
127
+
128
+ export function getKnowledgeBaseById(id) {
129
+ return knowledgeBases.find(kb => kb.id === id);
130
+ }