Skip to content

Commit 391b355

Browse files
authored
Merge pull request #1 from PancrePal-xiaoyibao/dev
v2.3.0-增加检索信息缓存(小树)以及OA论文全文下载和endnote格式索引生成功能
2 parents 9060401 + d259116 commit 391b355

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+9041
-65
lines changed

.cursor/rules/README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# MCP PubMed服务器 Cursor规则
2+
3+
本目录包含了为MCP PubMed服务器项目定制的Cursor规则,帮助AI更好地理解和开发这个项目。
4+
5+
## 规则文件说明
6+
7+
### 1. `project-structure.mdc` - 项目结构指导
8+
- **应用范围**: 始终应用 (`alwaysApply: true`)
9+
- **内容**: 项目架构、核心模块、开发原则
10+
- **作用**: 帮助AI理解项目的整体结构和设计理念
11+
12+
### 2. `javascript-coding.mdc` - JavaScript编码规范
13+
- **应用范围**: 所有JavaScript文件 (`globs: *.js`)
14+
- **内容**: ES6+语法、错误处理、缓存管理、API调用模式
15+
- **作用**: 确保代码风格一致性和最佳实践
16+
17+
### 3. `mcp-server-development.mdc` - MCP服务器开发规范
18+
- **应用范围**: 所有JavaScript文件 (`globs: *.js`)
19+
- **内容**: MCP服务器架构、工具定义、响应格式、性能优化
20+
- **作用**: 指导MCP服务器的开发和维护
21+
22+
### 4. `pubmed-api-integration.mdc` - PubMed API集成规范
23+
- **应用范围**: 所有JavaScript文件 (`globs: *.js`)
24+
- **内容**: API端点配置、数据获取、格式化、错误处理
25+
- **作用**: 确保PubMed API的正确集成和使用
26+
27+
### 5. `caching-management.mdc` - 缓存管理规范
28+
- **应用范围**: 所有JavaScript文件 (`globs: *.js`)
29+
- **内容**: 双层缓存架构、缓存操作、统计监控、清理策略
30+
- **作用**: 优化缓存性能和资源管理
31+
32+
### 6. `environment-config.mdc` - 环境配置和部署指导
33+
- **应用范围**: 配置文件 (`globs: *.json,*.env*,*.md`)
34+
- **内容**: 环境变量、MCP客户端配置、部署检查、故障排除
35+
- **作用**: 指导项目的配置和部署
36+
37+
## 规则特点
38+
39+
### 🎯 针对性设计
40+
- 专门为MCP PubMed服务器项目定制
41+
- 基于实际代码结构和功能特点
42+
- 覆盖从开发到部署的完整流程
43+
44+
### 🔧 实用性强
45+
- 提供具体的代码模式和最佳实践
46+
- 包含错误处理和性能优化指导
47+
- 涵盖缓存管理和API集成细节
48+
49+
### 📚 知识体系完整
50+
- 从项目结构到具体实现
51+
- 从编码规范到部署配置
52+
- 形成完整的开发知识体系
53+
54+
## 使用建议
55+
56+
1. **开发新功能时**: 参考相应的规则文件,确保符合项目规范
57+
2. **代码审查时**: 使用规则作为检查标准
58+
3. **问题排查时**: 参考环境配置和故障排除部分
59+
4. **性能优化时**: 查看缓存管理和性能监控相关规则
60+
61+
## 规则维护
62+
63+
- 当项目结构发生变化时,及时更新相关规则
64+
- 发现新的最佳实践时,补充到相应规则文件
65+
- 定期检查规则的准确性和完整性
66+
67+
---
68+
69+
*这些规则将帮助Cursor AI更好地理解您的MCP PubMed服务器项目,提供更精准的代码建议和开发支持。*
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
---
2+
globs: *.js
3+
description: 缓存管理和性能优化规范
4+
---
5+
6+
# 缓存管理规范
7+
8+
## 双层缓存架构
9+
10+
### 1. 内存缓存 (Map对象)
11+
```javascript
12+
// 内存缓存配置
13+
this.cache = new Map();
14+
this.cacheTimeout = 5 * 60 * 1000; // 5分钟过期
15+
this.maxCacheSize = 100; // 最大100个条目
16+
```
17+
18+
### 2. 文件缓存 (JSON文件)
19+
```javascript
20+
// 文件缓存配置
21+
const CACHE_DIR = path.join(process.cwd(), 'cache');
22+
const PAPER_CACHE_DIR = path.join(CACHE_DIR, 'papers');
23+
const PAPER_CACHE_EXPIRY = 30 * 24 * 60 * 60 * 1000; // 30天过期
24+
```
25+
26+
## 缓存操作模式
27+
28+
### 内存缓存操作
29+
```javascript
30+
// 获取缓存
31+
getFromCache(key) {
32+
const cached = this.cache.get(key);
33+
if (cached && Date.now() - cached.timestamp < this.cacheTimeout) {
34+
this.cacheStats.hits++;
35+
return cached.data;
36+
}
37+
this.cacheStats.misses++;
38+
return null;
39+
}
40+
41+
// 设置缓存
42+
setCache(key, data) {
43+
// LRU淘汰策略
44+
if (this.cache.size >= this.maxCacheSize) {
45+
const oldestKey = this.cache.keys().next().value;
46+
this.cache.delete(oldestKey);
47+
this.cacheStats.evictions++;
48+
}
49+
50+
this.cache.set(key, {
51+
data,
52+
timestamp: Date.now()
53+
});
54+
this.cacheStats.sets++;
55+
}
56+
```
57+
58+
### 文件缓存操作
59+
```javascript
60+
// 从文件缓存获取
61+
getPaperFromFileCache(pmid) {
62+
const cachePath = this.getPaperCachePath(pmid);
63+
if (!fs.existsSync(cachePath)) {
64+
this.cacheStats.fileMisses++;
65+
return null;
66+
}
67+
68+
const fileContent = fs.readFileSync(cachePath, 'utf8');
69+
const cachedData = JSON.parse(fileContent);
70+
71+
// 检查过期时间
72+
if (Date.now() - cachedData.timestamp > PAPER_CACHE_EXPIRY) {
73+
fs.unlinkSync(cachePath);
74+
return null;
75+
}
76+
77+
this.cacheStats.fileHits++;
78+
return cachedData.data;
79+
}
80+
81+
// 保存到文件缓存
82+
setPaperToFileCache(pmid, data) {
83+
const cachePath = this.getPaperCachePath(pmid);
84+
const cacheData = {
85+
version: CACHE_VERSION,
86+
pmid: pmid,
87+
timestamp: Date.now(),
88+
data: data
89+
};
90+
91+
fs.writeFileSync(cachePath, JSON.stringify(cacheData, null, 2));
92+
this.cacheStats.fileSets++;
93+
}
94+
```
95+
96+
## 缓存统计和监控
97+
98+
### 统计数据结构
99+
```javascript
100+
this.cacheStats = {
101+
hits: 0, // 内存缓存命中
102+
misses: 0, // 内存缓存未命中
103+
sets: 0, // 内存缓存设置
104+
evictions: 0, // 内存缓存淘汰
105+
fileHits: 0, // 文件缓存命中
106+
fileMisses: 0, // 文件缓存未命中
107+
fileSets: 0 // 文件缓存设置
108+
};
109+
```
110+
111+
### 缓存统计报告
112+
```javascript
113+
getCacheStats() {
114+
const memoryHitRate = this.cacheStats.hits / (this.cacheStats.hits + this.cacheStats.misses) * 100;
115+
const fileHitRate = this.cacheStats.fileHits / (this.cacheStats.fileHits + this.cacheStats.fileMisses) * 100;
116+
117+
return {
118+
memory: {
119+
hits: this.cacheStats.hits,
120+
misses: this.cacheStats.misses,
121+
hitRate: memoryHitRate.toFixed(2) + '%',
122+
currentSize: this.cache.size,
123+
maxSize: this.maxCacheSize
124+
},
125+
file: {
126+
hits: this.cacheStats.fileHits,
127+
misses: this.cacheStats.fileMisses,
128+
hitRate: fileHitRate.toFixed(2) + '%',
129+
totalPapers: this.getFileCacheCount()
130+
}
131+
};
132+
}
133+
```
134+
135+
## 缓存清理策略
136+
137+
### 过期缓存清理
138+
```javascript
139+
// 清理过期内存缓存
140+
cleanExpiredCache() {
141+
const now = Date.now();
142+
let cleaned = 0;
143+
for (const [key, value] of this.cache.entries()) {
144+
if (now - value.timestamp >= this.cacheTimeout) {
145+
this.cache.delete(key);
146+
cleaned++;
147+
}
148+
}
149+
return cleaned;
150+
}
151+
152+
// 清理过期文件缓存
153+
cleanExpiredPaperCache() {
154+
let cleaned = 0;
155+
for (const [pmid, info] of Object.entries(indexData.papers)) {
156+
const cachePath = this.getPaperCachePath(pmid);
157+
if (fs.existsSync(cachePath)) {
158+
const fileContent = fs.readFileSync(cachePath, 'utf8');
159+
const cachedData = JSON.parse(fileContent);
160+
161+
if (Date.now() - cachedData.timestamp > PAPER_CACHE_EXPIRY) {
162+
fs.unlinkSync(cachePath);
163+
delete indexData.papers[pmid];
164+
cleaned++;
165+
}
166+
}
167+
}
168+
return cleaned;
169+
}
170+
```
171+
172+
## 缓存键生成策略
173+
174+
### 搜索缓存键
175+
```javascript
176+
getCacheKey(query, maxResults, daysBack, sortBy) {
177+
return `${query}|${maxResults}|${daysBack}|${sortBy}`;
178+
}
179+
```
180+
181+
### 论文缓存键
182+
```javascript
183+
getPaperCachePath(pmid) {
184+
return path.join(PAPER_CACHE_DIR, `${pmid}.json`);
185+
}
186+
```
187+
188+
## 缓存性能优化
189+
190+
### 批量缓存检查
191+
```javascript
192+
// 批量检查文件缓存
193+
for (const id of ids) {
194+
const cachedArticle = this.getPaperFromFileCache(id);
195+
if (cachedArticle) {
196+
articles.push(cachedArticle);
197+
} else {
198+
uncachedIds.push(id);
199+
}
200+
}
201+
```
202+
203+
### 缓存预热
204+
```javascript
205+
// 初始化缓存目录
206+
initCacheDirectories() {
207+
if (!fs.existsSync(CACHE_DIR)) {
208+
fs.mkdirSync(CACHE_DIR, { recursive: true });
209+
}
210+
211+
if (!fs.existsSync(PAPER_CACHE_DIR)) {
212+
fs.mkdirSync(PAPER_CACHE_DIR, { recursive: true });
213+
}
214+
}
215+
```

0 commit comments

Comments
 (0)