-
Notifications
You must be signed in to change notification settings - Fork 625
feat: add npm registry caching and optimization system #697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -117,15 +117,13 @@ export class McpPresenter implements IMCPPresenter { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.configPresenter.getMcpDefaultServers() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 先测试npm registry速度 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('[MCP] Testing npm registry speed...') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 初始化npm registry(优先使用缓存) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('[MCP] Initializing npm registry...') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.serverManager.testNpmRegistrySpeed() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| `[MCP] npm registry speed test completed, selected best registry: ${this.serverManager.getNpmRegistry()}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.serverManager.testNpmRegistrySpeed(true) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`[MCP] npm registry initialized: ${this.serverManager.getNpmRegistry()}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('[MCP] npm registry speed test failed:', error) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('[MCP] npm registry initialization failed:', error) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 检查并启动 deepchat-inmemory/custom-prompts-server | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -173,6 +171,8 @@ export class McpPresenter implements IMCPPresenter { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 检查并管理自定义提示词服务器 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.checkAndManageCustomPromptsServer() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.scheduleBackgroundRegistryUpdate() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('[MCP] Initialization failed:', error) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 即使初始化失败也标记为已完成,避免系统卡在未初始化状态 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -181,6 +181,16 @@ export class McpPresenter implements IMCPPresenter { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private scheduleBackgroundRegistryUpdate(): void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setTimeout(async () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await this.serverManager.updateNpmRegistryInBackground() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error('[MCP] Background registry update failed:', error) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, 5000) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 添加获取初始化状态的方法 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isReady(): boolean { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return this.isInitialized | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1127,4 +1137,58 @@ export class McpPresenter implements IMCPPresenter { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async getNpmRegistryStatus(): Promise<{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentRegistry: string | null | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isFromCache: boolean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lastChecked?: number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| autoDetectEnabled: boolean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| customRegistry?: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const cache = this.configPresenter.getNpmRegistryCache?.() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const autoDetectEnabled = this.configPresenter.getAutoDetectNpmRegistry?.() ?? true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const customRegistry = this.configPresenter.getCustomNpmRegistry?.() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentRegistry = this.serverManager.getNpmRegistry() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let isFromCache = false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (customRegistry && currentRegistry === customRegistry) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isFromCache = false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else if (cache && this.configPresenter.isNpmRegistryCacheValid?.()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isFromCache = currentRegistry === cache.registry | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentRegistry, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isFromCache, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lastChecked: cache?.lastChecked, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| autoDetectEnabled, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| customRegistry | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async refreshNpmRegistry(): Promise<string> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await this.serverManager.refreshNpmRegistry() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async setCustomNpmRegistry(registry: string | undefined): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.configPresenter.setCustomNpmRegistry?.(registry) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (registry) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log(`[MCP] Setting custom NPM registry: ${registry}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('[MCP] Clearing custom NPM registry') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.serverManager.loadRegistryFromCache() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1173
to
+1181
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add input validation and error handling. The implementation is good but could benefit from validation and error handling. async setCustomNpmRegistry(registry: string | undefined): Promise<void> {
+ try {
+ // Validate registry URL format if provided
+ if (registry && registry.trim()) {
+ const trimmed = registry.trim()
+ if (!trimmed.startsWith('http://') && !trimmed.startsWith('https://')) {
+ throw new Error('Registry URL must start with http:// or https://')
+ }
+ registry = trimmed
+ }
+
this.configPresenter.setCustomNpmRegistry?.(registry)
if (registry) {
console.log(`[MCP] Setting custom NPM registry: ${registry}`)
} else {
console.log('[MCP] Clearing custom NPM registry')
}
this.serverManager.loadRegistryFromCache()
+ } catch (error) {
+ console.error('[MCP] Failed to set custom NPM registry:', error)
+ throw error
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async setAutoDetectNpmRegistry(enabled: boolean): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.configPresenter.setAutoDetectNpmRegistry?.(enabled) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (enabled) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.serverManager.loadRegistryFromCache() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1183
to
+1188
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for consistency. The logic is sound but should include error handling consistent with other methods. async setAutoDetectNpmRegistry(enabled: boolean): Promise<void> {
+ try {
this.configPresenter.setAutoDetectNpmRegistry?.(enabled)
if (enabled) {
this.serverManager.loadRegistryFromCache()
}
+ } catch (error) {
+ console.error('[MCP] Failed to set auto-detect NPM registry:', error)
+ throw error
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async clearNpmRegistryCache(): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.configPresenter.clearNpmRegistryCache?.() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| console.log('[MCP] NPM Registry cache cleared') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1190
to
+1193
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add error handling for robustness. Simple implementation but should include error handling. async clearNpmRegistryCache(): Promise<void> {
+ try {
this.configPresenter.clearNpmRegistryCache?.()
console.log('[MCP] NPM Registry cache cleared')
+ } catch (error) {
+ console.error('[MCP] Failed to clear NPM registry cache:', error)
+ throw error
+ }
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add URL validation in normalization method.
The URL normalization should validate that the input is a valid HTTP/HTTPS URL before normalizing.
private normalizeNpmRegistryUrl(registry: string): string { let normalized = registry.trim() + // Validate URL format + if (!normalized.startsWith('http://') && !normalized.startsWith('https://')) { + throw new Error('Registry URL must start with http:// or https://') + } + try { + new URL(normalized) // Validate URL structure + } catch { + throw new Error('Invalid registry URL format') + } if (!normalized.endsWith('/')) { normalized += '/' } return normalized }📝 Committable suggestion
🤖 Prompt for AI Agents