@mrxkun/mcfast-mcp 4.0.11 → 4.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrxkun/mcfast-mcp",
3
- "version": "4.0.11",
3
+ "version": "4.0.14",
4
4
  "description": "Ultra-fast code editing with WASM acceleration, fuzzy patching, multi-layer caching, and 8 unified tools. Optimized for AI code assistants with 80-98% latency reduction. Phase 4: ML Intelligence Layer.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -54,16 +54,69 @@ const VERBOSE = process.env.MCFAST_VERBOSE !== 'false'; // Default: true
54
54
 
55
55
  // Memory Engine (initialized lazily)
56
56
  let memoryEngine = null;
57
+ let memoryEngineInitPromise = null;
58
+ let memoryEngineReady = false;
57
59
 
60
+ /**
61
+ * Start background initialization of memory engine
62
+ * Call this on server startup to pre-initialize
63
+ */
64
+ async function backgroundInitializeMemoryEngine() {
65
+ if (memoryEngineInitPromise) return memoryEngineInitPromise;
66
+
67
+ memoryEngineInitPromise = (async () => {
68
+ try {
69
+ memoryEngine = new MemoryEngine({
70
+ apiKey: TOKEN,
71
+ enableSync: true
72
+ });
73
+ // Use a shorter timeout for initialization
74
+ const initTimeout = new Promise((_, reject) => {
75
+ setTimeout(() => reject(new Error('Memory engine init timeout')), 25000);
76
+ });
77
+
78
+ await Promise.race([
79
+ memoryEngine.initialize(process.cwd()),
80
+ initTimeout
81
+ ]);
82
+
83
+ memoryEngineReady = true;
84
+ console.error(`${colors.cyan}[Memory]${colors.reset} Engine initialized successfully`);
85
+ } catch (error) {
86
+ console.error(`${colors.yellow}[Memory]${colors.reset} Engine initialization failed: ${error.message}`);
87
+ // Don't throw - allow partial initialization
88
+ memoryEngineReady = false;
89
+ }
90
+ })();
91
+
92
+ return memoryEngineInitPromise;
93
+ }
94
+
95
+ /**
96
+ * Get memory engine - waits for initialization with timeout
97
+ */
58
98
  async function getMemoryEngine() {
99
+ if (memoryEngine && memoryEngineReady) {
100
+ return memoryEngine;
101
+ }
102
+
103
+ // Wait for initialization with timeout
104
+ if (memoryEngineInitPromise) {
105
+ try {
106
+ await Promise.race([
107
+ memoryEngineInitPromise,
108
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 5000))
109
+ ]);
110
+ } catch (error) {
111
+ console.error(`${colors.yellow}[Memory]${colors.reset} Waiting for engine: ${error.message}`);
112
+ }
113
+ }
114
+
115
+ // If still not ready, try to initialize now
59
116
  if (!memoryEngine) {
60
- memoryEngine = new MemoryEngine({
61
- apiKey: TOKEN,
62
- enableSync: true
63
- });
64
- await memoryEngine.initialize(process.cwd());
65
- console.error(`${colors.cyan}[Memory]${colors.reset} Engine initialized`);
117
+ await backgroundInitializeMemoryEngine();
66
118
  }
119
+
67
120
  return memoryEngine;
68
121
  }
69
122
 
@@ -282,6 +335,28 @@ const TOOL_ALIASES = {
282
335
  'list_files_fast': 'list_files',
283
336
  'read_file': 'read',
284
337
  'goto_definition': 'search', // redirected
338
+ // VSCode MCP client adds prefixes
339
+ 'mcp--mcfast--edit': 'edit',
340
+ 'mcp--mcfast--search': 'search',
341
+ 'mcp--mcfast--read': 'read',
342
+ 'mcp--mcfast--list_files': 'list_files',
343
+ 'mcp--mcfast--reapply': 'reapply',
344
+ 'mcp--mcfast--memory_search': 'memory_search',
345
+ 'mcp--mcfast--memory_get': 'memory_get',
346
+ 'mcp--mcfast--detect_patterns': 'detect_patterns',
347
+ 'mcp--mcfast--get_suggestions': 'get_suggestions',
348
+ 'mcp--mcfast--select_strategy': 'select_strategy',
349
+ // Alternative format with double dashes
350
+ 'mcfast_edit': 'edit',
351
+ 'mcfast_search': 'search',
352
+ 'mcfast_read': 'read',
353
+ 'mcfast_list_files': 'list_files',
354
+ 'mcfast_reapply': 'reapply',
355
+ 'mcfast_memory_search': 'memory_search',
356
+ 'mcfast_memory_get': 'memory_get',
357
+ 'mcfast_detect_patterns': 'detect_patterns',
358
+ 'mcfast_get_suggestions': 'get_suggestions',
359
+ 'mcfast_select_strategy': 'select_strategy',
285
360
  };
286
361
 
287
362
  /**
@@ -1107,7 +1182,8 @@ async function handleSearchFilesystem({ query, path: searchPath, isRegex = false
1107
1182
  lines.forEach((line, idx) => {
1108
1183
  if (line.includes(query)) {
1109
1184
  matches.push({
1110
- line: idx + 1,
1185
+ file,
1186
+ lineNumber: idx + 1,
1111
1187
  content: line.trim()
1112
1188
  });
1113
1189
  }
@@ -1152,7 +1228,7 @@ async function handleSearchFilesystem({ query, path: searchPath, isRegex = false
1152
1228
  contentMatches.slice(0, 10).forEach(({ file, matches }) => {
1153
1229
  output += `\n${colors.yellow}${file}${colors.reset}\n`;
1154
1230
  matches.forEach(match => {
1155
- output += ` ${colors.dim}${match.line}:${colors.reset} ${match.content}\n`;
1231
+ output += ` ${colors.dim}${match.lineNumber}:${colors.reset} ${match.content}\n`;
1156
1232
  });
1157
1233
  });
1158
1234
  }
@@ -1233,6 +1309,22 @@ async function handleReapply({ instruction, files, errorContext = "", attempt =
1233
1309
  */
1234
1310
  async function handleEdit({ instruction, files, code_edit, dryRun = false }) {
1235
1311
  const editStartTime = Date.now();
1312
+
1313
+ // Validate required parameters
1314
+ if (!instruction) {
1315
+ return {
1316
+ content: [{ type: "text", text: "❌ Error: 'instruction' parameter is required" }],
1317
+ isError: true
1318
+ };
1319
+ }
1320
+
1321
+ if (!files || Object.keys(files).length === 0) {
1322
+ return {
1323
+ content: [{ type: "text", text: "❌ Error: 'files' parameter is required and must contain at least one file" }],
1324
+ isError: true
1325
+ };
1326
+ }
1327
+
1236
1328
  const firstFile = Object.keys(files)[0];
1237
1329
 
1238
1330
  // 1. Retrieve memory context for enhanced understanding
@@ -1243,7 +1335,7 @@ async function handleEdit({ instruction, files, code_edit, dryRun = false }) {
1243
1335
  console.error(`${colors.cyan}[MEMORY]${colors.reset} Retrieved context for edit`);
1244
1336
  }
1245
1337
  } catch (error) {
1246
- console.error(`${colors.yellow}[MEMORY]${colors.reset} Context retrieval failed: ${error.message}`);
1338
+ console.error(`${colors.yellow}[Memory]${colors.reset} Context retrieval failed: ${error.message}`);
1247
1339
  }
1248
1340
 
1249
1341
  // 2. Analyze impact for rename operations
@@ -2489,7 +2581,7 @@ async function handleApplyFast({ instruction, files, dryRun, toolName }) {
2489
2581
  if (!TOKEN) {
2490
2582
  return {
2491
2583
  content: [{ type: "text", text: "❌ Error: MCFAST_TOKEN is missing. Please set it in your MCP config." }],
2492
- isError: true
2584
+ isError: true,
2493
2585
  };
2494
2586
  }
2495
2587
  try {
@@ -2858,6 +2950,18 @@ async function handleMemorySearch({ query, type = 'all', maxResults = 6, minScor
2858
2950
  */
2859
2951
  async function handleMemoryGet({ type }) {
2860
2952
  const start = Date.now();
2953
+
2954
+ // Early return if memory engine not ready
2955
+ if (!memoryEngineReady) {
2956
+ return {
2957
+ content: [{
2958
+ type: "text",
2959
+ text: `⏳ Memory engine is still initializing. Please try again in a few seconds.`
2960
+ }],
2961
+ isError: true
2962
+ };
2963
+ }
2964
+
2861
2965
  try {
2862
2966
  const engine = await getMemoryEngine();
2863
2967
  let output = '';
@@ -2923,6 +3027,18 @@ async function handleMemoryGet({ type }) {
2923
3027
  */
2924
3028
  async function handleDetectPatterns() {
2925
3029
  const start = Date.now();
3030
+
3031
+ // Early return if memory engine not ready
3032
+ if (!memoryEngineReady) {
3033
+ return {
3034
+ content: [{
3035
+ type: "text",
3036
+ text: `⏳ Memory engine is still initializing. Please try again in a few seconds.`
3037
+ }],
3038
+ isError: true
3039
+ };
3040
+ }
3041
+
2926
3042
  try {
2927
3043
  const engine = await getMemoryEngine();
2928
3044
  const patterns = await engine.detectPatterns();
@@ -2970,6 +3086,18 @@ async function handleDetectPatterns() {
2970
3086
  */
2971
3087
  async function handleGetSuggestions({ currentFile, currentLine }) {
2972
3088
  const start = Date.now();
3089
+
3090
+ // Early return if memory engine not ready
3091
+ if (!memoryEngineReady) {
3092
+ return {
3093
+ content: [{
3094
+ type: "text",
3095
+ text: `⏳ Memory engine is still initializing. Please try again in a few seconds.`
3096
+ }],
3097
+ isError: true
3098
+ };
3099
+ }
3100
+
2973
3101
  try {
2974
3102
  const engine = await getMemoryEngine();
2975
3103
  const suggestions = await engine.getSuggestions({
@@ -3023,6 +3151,18 @@ async function handleGetSuggestions({ currentFile, currentLine }) {
3023
3151
  */
3024
3152
  async function handleSelectStrategy({ instruction, files = [] }) {
3025
3153
  const start = Date.now();
3154
+
3155
+ // Early return if memory engine not ready
3156
+ if (!memoryEngineReady) {
3157
+ return {
3158
+ content: [{
3159
+ type: "text",
3160
+ text: `⏳ Memory engine is still initializing. Please try again in a few seconds.`
3161
+ }],
3162
+ isError: true
3163
+ };
3164
+ }
3165
+
3026
3166
  try {
3027
3167
  const engine = await getMemoryEngine();
3028
3168
  const result = await engine.selectStrategy(instruction, { files });
@@ -3067,5 +3207,11 @@ async function handleSelectStrategy({ instruction, files = [] }) {
3067
3207
  * Start Server
3068
3208
  */
3069
3209
  const transport = new StdioServerTransport();
3210
+
3211
+ // Pre-initialize memory engine in background
3212
+ backgroundInitializeMemoryEngine().catch(err => {
3213
+ console.error(`${colors.yellow}[Memory]${colors.reset} Background init error: ${err.message}`);
3214
+ });
3215
+
3070
3216
  await server.connect(transport);
3071
3217
  console.error("mcfast MCP v1.0.0 running on stdio");
@@ -104,12 +104,47 @@ export class MemoryEngine {
104
104
  console.log(`[MemoryEngine] Smart Routing: ${this.smartRoutingEnabled ? 'ENABLED' : 'DISABLED'}`);
105
105
  console.log(`[MemoryEngine] Intelligence Layer: ${this.intelligenceEnabled ? 'ENABLED' : 'DISABLED'}`);
106
106
 
107
- // Load intelligence models
107
+ // Initialize intelligence engines if enabled
108
108
  if (this.intelligenceEnabled) {
109
- await this.patternDetector.loadModel?.();
110
- await this.suggestionEngine.loadModel?.();
111
- await this.strategySelector.loadModel?.();
112
- console.log('[MemoryEngine] Intelligence models loaded');
109
+ try {
110
+ const { PatternDetector, SuggestionEngine, StrategySelector } = await import('../intelligence/index.js');
111
+ this.patternDetector = new PatternDetector({ memoryEngine: this });
112
+ this.suggestionEngine = new SuggestionEngine({ memoryEngine: this });
113
+ this.strategySelector = new StrategySelector({ memoryEngine: this });
114
+ console.log('[MemoryEngine] Intelligence engines initialized');
115
+ } catch (error) {
116
+ console.warn('[MemoryEngine] Failed to initialize intelligence engines:', error.message);
117
+ this.intelligenceEnabled = false;
118
+ }
119
+ }
120
+
121
+ // Load intelligence models - run in background to not block initialization
122
+ if (this.intelligenceEnabled) {
123
+ // Start model loading in background without awaiting
124
+ (async () => {
125
+ try {
126
+ const loadPromises = [
127
+ this.patternDetector.loadModel?.(),
128
+ this.suggestionEngine.loadModel?.(),
129
+ this.strategySelector.loadModel?.()
130
+ ].filter(Boolean);
131
+
132
+ // Add timeout to prevent hanging
133
+ const timeoutPromise = new Promise((_, reject) =>
134
+ setTimeout(() => reject(new Error('Model loading timeout')), 5000)
135
+ );
136
+
137
+ await Promise.race([
138
+ Promise.all(loadPromises),
139
+ timeoutPromise
140
+ ]);
141
+
142
+ console.log('[MemoryEngine] ✅ Intelligence models loaded');
143
+ } catch (error) {
144
+ console.warn('[MemoryEngine] Model loading failed or timed out:', error.message);
145
+ // Don't disable intelligence - models are optional
146
+ }
147
+ })();
113
148
  }
114
149
  }
115
150
 
@@ -98,7 +98,7 @@ export class ParallelSearch {
98
98
  );
99
99
 
100
100
  results = [...results, ...slowResults];
101
- return this.mergeResults(results, maxResults);
101
+ return this.mergeResults(results, limit);
102
102
  }
103
103
 
104
104
  return merged;