@mrxkun/mcfast-mcp 4.1.9 → 4.1.11
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 +62 -651
- package/package.json +2 -2
- package/src/index.js +223 -80
- package/src/memory/memory-engine.js +232 -13
- package/src/memory/stores/base-database.js +223 -0
- package/src/memory/utils/chunker.js +1 -0
- package/src/memory/utils/indexer.js +110 -4
- package/src/memory/utils/logger.js +162 -0
- package/src/memory/utils/vector-index.js +241 -0
- package/src/memory/watchers/file-watcher.js +255 -103
- package/src/tools/project_analyze.js +491 -0
- package/src/utils/audit-queue.js +1 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrxkun/mcfast-mcp",
|
|
3
|
-
"version": "4.1.
|
|
4
|
-
"description": "Ultra-fast code editing with WASM acceleration, fuzzy patching, multi-layer caching, and 8 unified tools. v4.1.
|
|
3
|
+
"version": "4.1.11",
|
|
4
|
+
"description": "Ultra-fast code editing with WASM acceleration, fuzzy patching, multi-layer caching, and 8 unified tools. v4.1.11: Suppress console output to prevent JSON-RPC stream corruption.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mcfast-mcp": "src/index.js"
|
package/src/index.js
CHANGED
|
@@ -8,47 +8,33 @@
|
|
|
8
8
|
// CRITICAL: Suppress ALL console output in MCP mode to prevent JSON parsing errors
|
|
9
9
|
// MCP protocol requires stdout to contain ONLY JSON-RPC messages
|
|
10
10
|
|
|
11
|
-
//
|
|
11
|
+
// ANSI Color Codes for Terminal Output (MUST be defined before any usage)
|
|
12
|
+
const colors = {
|
|
13
|
+
reset: '\x1b[0m',
|
|
14
|
+
bold: '\x1b[1m',
|
|
15
|
+
dim: '\x1b[2m',
|
|
16
|
+
cyan: '\x1b[36m',
|
|
17
|
+
green: '\x1b[32m',
|
|
18
|
+
yellow: '\x1b[33m',
|
|
19
|
+
blue: '\x1b[34m',
|
|
20
|
+
magenta: '\x1b[35m',
|
|
21
|
+
gray: '\x1b[90m',
|
|
22
|
+
white: '\x1b[37m',
|
|
23
|
+
bgBlack: '\x1b[40m',
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Override console.log - suppress in MCP mode
|
|
12
27
|
const originalConsoleLog = console.log;
|
|
13
28
|
console.log = function(...args) {
|
|
14
|
-
//
|
|
15
|
-
try {
|
|
16
|
-
const logDir = process.cwd() + '/.mcfast';
|
|
17
|
-
const logFile = logDir + '/mcp-debug.log';
|
|
18
|
-
const message = `[${new Date().toISOString()}] [LOG] ${args.join(' ')}\n`;
|
|
19
|
-
|
|
20
|
-
// Ensure directory exists
|
|
21
|
-
require('fs').mkdirSync(logDir, { recursive: true });
|
|
22
|
-
require('fs').appendFileSync(logFile, message);
|
|
23
|
-
} catch (e) {
|
|
24
|
-
// Ignore if can't write
|
|
25
|
-
}
|
|
29
|
+
// Suppressed in MCP mode
|
|
26
30
|
};
|
|
27
31
|
|
|
28
|
-
// Override console.error -
|
|
32
|
+
// Override console.error - suppress in MCP mode
|
|
29
33
|
const originalConsoleError = console.error;
|
|
30
34
|
console.error = function(...args) {
|
|
31
|
-
//
|
|
32
|
-
try {
|
|
33
|
-
const logDir = process.cwd() + '/.mcfast';
|
|
34
|
-
const logFile = logDir + '/mcp-debug.log';
|
|
35
|
-
const message = `[${new Date().toISOString()}] [ERROR] ${args.join(' ')}\n`;
|
|
36
|
-
|
|
37
|
-
// Ensure directory exists
|
|
38
|
-
require('fs').mkdirSync(logDir, { recursive: true });
|
|
39
|
-
require('fs').appendFileSync(logFile, message);
|
|
40
|
-
} catch (e) {
|
|
41
|
-
// Ignore if can't write
|
|
42
|
-
}
|
|
35
|
+
// Suppressed in MCP mode
|
|
43
36
|
};
|
|
44
37
|
|
|
45
|
-
// Write startup marker
|
|
46
|
-
try {
|
|
47
|
-
const logDir = process.cwd() + '/.mcfast';
|
|
48
|
-
require('fs').mkdirSync(logDir, { recursive: true });
|
|
49
|
-
require('fs').appendFileSync(logDir + '/mcp-debug.log', `[${new Date().toISOString()}] [START] MCP initializing...\n`);
|
|
50
|
-
} catch (e) {}
|
|
51
|
-
|
|
52
38
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
53
39
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
54
40
|
import { ListToolsRequestSchema, CallToolRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
@@ -89,9 +75,87 @@ import { getAuditQueue } from './utils/audit-queue.js';
|
|
|
89
75
|
import { getIntelligenceCache } from './utils/intelligence-cache.js';
|
|
90
76
|
import { getContextPrefetcher } from './utils/context-prefetcher.js';
|
|
91
77
|
import { parallelMemorySearch } from './utils/parallel-search.js';
|
|
78
|
+
import { execute as projectAnalyzeExecute } from './tools/project_analyze.js';
|
|
92
79
|
|
|
93
80
|
const execAsync = promisify(exec);
|
|
94
81
|
|
|
82
|
+
// ============================================================================
|
|
83
|
+
// LOCK FILE MECHANISM - Prevent multiple instances running simultaneously
|
|
84
|
+
// ============================================================================
|
|
85
|
+
const LOCK_FILE_PATH = path.join(process.cwd(), '.mcfast', '.mcp-instance.lock');
|
|
86
|
+
let lockFileHandle = null;
|
|
87
|
+
|
|
88
|
+
async function acquireLock() {
|
|
89
|
+
try {
|
|
90
|
+
const lockDir = path.dirname(LOCK_FILE_PATH);
|
|
91
|
+
await fs.mkdir(lockDir, { recursive: true });
|
|
92
|
+
|
|
93
|
+
lockFileHandle = await fs.open(LOCK_FILE_PATH, 'wx');
|
|
94
|
+
|
|
95
|
+
// Write current PID
|
|
96
|
+
await lockFileHandle.write(`${process.pid}\n${Date.now()}\n`, 0);
|
|
97
|
+
await lockFileHandle.sync();
|
|
98
|
+
|
|
99
|
+
// Cleanup on exit
|
|
100
|
+
process.on('beforeExit', releaseLock);
|
|
101
|
+
process.on('SIGINT', releaseLock);
|
|
102
|
+
process.on('SIGTERM', releaseLock);
|
|
103
|
+
process.on('uncaughtException', releaseLock);
|
|
104
|
+
|
|
105
|
+
console.error(`${colors.cyan}[Lock]${colors.reset} Acquired lock file: ${LOCK_FILE_PATH}`);
|
|
106
|
+
return true;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error.code === 'EEXIST') {
|
|
109
|
+
// Lock file exists, check if it's stale
|
|
110
|
+
try {
|
|
111
|
+
const lockContent = await fs.readFile(LOCK_FILE_PATH, 'utf-8');
|
|
112
|
+
const [pid, timestamp] = lockContent.trim().split('\n');
|
|
113
|
+
const lockAge = Date.now() - parseInt(timestamp);
|
|
114
|
+
|
|
115
|
+
// Check if process is still running (stale lock if > 5 minutes)
|
|
116
|
+
if (lockAge > 5 * 60 * 1000) {
|
|
117
|
+
console.error(`${colors.yellow}[Lock]${colors.reset} Stale lock detected (age: ${Math.round(lockAge / 1000)}s), removing...`);
|
|
118
|
+
await fs.unlink(LOCK_FILE_PATH);
|
|
119
|
+
return acquireLock(); // Retry
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.error(`${colors.red}[Lock]${colors.reset} Another instance is already running (PID: ${pid})`);
|
|
123
|
+
console.error(`${colors.yellow}[Lock]${colors.reset} To force start, delete: ${LOCK_FILE_PATH}`);
|
|
124
|
+
return false;
|
|
125
|
+
} catch (readError) {
|
|
126
|
+
console.error(`${colors.red}[Lock]${colors.reset} Failed to read lock file: ${readError.message}`);
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
console.error(`${colors.red}[Lock]${colors.reset} Failed to acquire lock: ${error.message}`);
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function releaseLock() {
|
|
136
|
+
if (lockFileHandle) {
|
|
137
|
+
try {
|
|
138
|
+
await lockFileHandle.close();
|
|
139
|
+
lockFileHandle = null;
|
|
140
|
+
} catch (e) {
|
|
141
|
+
// Ignore close errors
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
await fs.unlink(LOCK_FILE_PATH);
|
|
147
|
+
console.error(`${colors.cyan}[Lock]${colors.reset} Released lock file`);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if (error.code !== 'ENOENT') {
|
|
150
|
+
console.error(`${colors.yellow}[Lock]${colors.reset} Failed to release lock: ${error.message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ============================================================================
|
|
156
|
+
// END LOCK FILE MECHANISM
|
|
157
|
+
// ============================================================================
|
|
158
|
+
|
|
95
159
|
const API_URL = "https://mcfast.vercel.app/api/v1";
|
|
96
160
|
const TOKEN = process.env.MCFAST_TOKEN;
|
|
97
161
|
const VERBOSE = process.env.MCFAST_VERBOSE !== 'false'; // Default: true
|
|
@@ -109,28 +173,49 @@ async function backgroundInitializeMemoryEngine() {
|
|
|
109
173
|
if (memoryEngineInitPromise) return memoryEngineInitPromise;
|
|
110
174
|
|
|
111
175
|
memoryEngineInitPromise = (async () => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
176
|
+
const maxRetries = 2;
|
|
177
|
+
let lastError = null;
|
|
178
|
+
|
|
179
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
180
|
+
try {
|
|
181
|
+
memoryEngine = new MemoryEngine({
|
|
182
|
+
apiKey: TOKEN,
|
|
183
|
+
enableSync: true
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Use timeout for initialization
|
|
187
|
+
const initTimeout = new Promise((_, reject) => {
|
|
188
|
+
setTimeout(() => reject(new Error('Memory engine init timeout')), 25000);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
await Promise.race([
|
|
192
|
+
memoryEngine.initialize(process.cwd()),
|
|
193
|
+
initTimeout
|
|
194
|
+
]);
|
|
195
|
+
|
|
196
|
+
memoryEngineReady = true;
|
|
197
|
+
console.error(`${colors.cyan}[Memory]${colors.reset} Engine initialized successfully`);
|
|
198
|
+
return memoryEngine;
|
|
199
|
+
|
|
200
|
+
} catch (error) {
|
|
201
|
+
lastError = error;
|
|
202
|
+
console.error(`${colors.yellow}[Memory]${colors.reset} Initialization attempt ${attempt}/${maxRetries} failed: ${error.message}`);
|
|
203
|
+
|
|
204
|
+
if (attempt < maxRetries) {
|
|
205
|
+
// Exponential backoff before retry
|
|
206
|
+
const backoffMs = 1000 * Math.pow(2, attempt - 1);
|
|
207
|
+
console.error(`${colors.yellow}[Memory]${colors.reset} Retrying in ${backoffMs}ms...`);
|
|
208
|
+
await new Promise(resolve => setTimeout(resolve, backoffMs));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
133
211
|
}
|
|
212
|
+
|
|
213
|
+
// All retries failed - graceful degradation
|
|
214
|
+
console.error(`${colors.yellow}[Memory]${colors.reset} All initialization attempts failed. Running in degraded mode.`);
|
|
215
|
+
console.error(`${colors.yellow}[Memory]${colors.reset} Error: ${lastError?.message || 'Unknown error'}`);
|
|
216
|
+
console.error(`${colors.yellow}[Memory]${colors.reset} Tools requiring memory will be unavailable.`);
|
|
217
|
+
memoryEngineReady = false;
|
|
218
|
+
return null;
|
|
134
219
|
})();
|
|
135
220
|
|
|
136
221
|
return memoryEngineInitPromise;
|
|
@@ -331,21 +416,6 @@ async function analyzeRenameImpact(symbolName, currentFile = null) {
|
|
|
331
416
|
}
|
|
332
417
|
}
|
|
333
418
|
|
|
334
|
-
// ANSI Color Codes for Terminal Output
|
|
335
|
-
const colors = {
|
|
336
|
-
reset: '\x1b[0m',
|
|
337
|
-
bold: '\x1b[1m',
|
|
338
|
-
dim: '\x1b[2m',
|
|
339
|
-
cyan: '\x1b[36m',
|
|
340
|
-
green: '\x1b[32m',
|
|
341
|
-
yellow: '\x1b[33m',
|
|
342
|
-
blue: '\x1b[34m',
|
|
343
|
-
magenta: '\x1b[35m',
|
|
344
|
-
gray: '\x1b[90m',
|
|
345
|
-
white: '\x1b[37m',
|
|
346
|
-
bgBlack: '\x1b[40m',
|
|
347
|
-
};
|
|
348
|
-
|
|
349
419
|
// Tool icons (v2.0 - 4 core tools)
|
|
350
420
|
const toolIcons = {
|
|
351
421
|
edit: '✏️',
|
|
@@ -630,11 +700,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
630
700
|
// MEMORY TOOL 2: memory_get
|
|
631
701
|
{
|
|
632
702
|
name: "memory_get",
|
|
633
|
-
description: "📚 Get stored memories: today's log, curated memories, or
|
|
703
|
+
description: "📚 Get stored memories: today's log, curated memories, stats, or trigger re-index. Use to review recent changes or long-term knowledge.",
|
|
634
704
|
inputSchema: {
|
|
635
705
|
type: "object",
|
|
636
706
|
properties: {
|
|
637
|
-
type: { type: "string", enum: ["today_log", "curated", "stats", "intelligence"], description: "Type of memory to retrieve" }
|
|
707
|
+
type: { type: "string", enum: ["today_log", "curated", "stats", "intelligence", "reindex"], description: "Type of memory to retrieve or 'reindex' to trigger codebase re-indexing" }
|
|
638
708
|
},
|
|
639
709
|
required: ["type"]
|
|
640
710
|
}
|
|
@@ -674,6 +744,19 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
674
744
|
},
|
|
675
745
|
required: ["instruction"]
|
|
676
746
|
}
|
|
747
|
+
},
|
|
748
|
+
// PROJECT ANALYSIS TOOL
|
|
749
|
+
{
|
|
750
|
+
name: "project_analyze",
|
|
751
|
+
description: "🔍 Analyze project structure using AI (Mercury). Returns: Project Overview, Technologies, API Endpoints, Main Features. Auto-updates MEMORY.md. Requires MCFAST_TOKEN.",
|
|
752
|
+
inputSchema: {
|
|
753
|
+
type: "object",
|
|
754
|
+
properties: {
|
|
755
|
+
force: { type: "boolean", description: "Force re-analysis (ignore cache)" },
|
|
756
|
+
updateMemory: { type: "boolean", description: "Update MEMORY.md with results (default: true)" }
|
|
757
|
+
},
|
|
758
|
+
required: []
|
|
759
|
+
}
|
|
677
760
|
}
|
|
678
761
|
],
|
|
679
762
|
};
|
|
@@ -876,6 +959,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
876
959
|
result = await handleSelectStrategy(args);
|
|
877
960
|
summary = 'Strategy selected';
|
|
878
961
|
}
|
|
962
|
+
// PROJECT ANALYSIS TOOL
|
|
963
|
+
else if (name === "project_analyze") {
|
|
964
|
+
result = await projectAnalyzeExecute(args);
|
|
965
|
+
summary = 'Project analyzed';
|
|
966
|
+
}
|
|
879
967
|
else {
|
|
880
968
|
throw new Error(`Tool not found: ${name}`);
|
|
881
969
|
}
|
|
@@ -2075,10 +2163,6 @@ async function handleReadFileInternal({ path: filePath, start_line, end_line, ma
|
|
|
2075
2163
|
|
|
2076
2164
|
if (startLine < 1) startLine = 1;
|
|
2077
2165
|
if (endLine < 1 || endLine > totalLines) endLine = totalLines;
|
|
2078
|
-
if (startLine > endLine) {
|
|
2079
|
-
throw new Error(`Invalid line range: start_line (${startLine}) > end_line (${endLine})`);
|
|
2080
|
-
}
|
|
2081
|
-
|
|
2082
2166
|
if (start_line || end_line) {
|
|
2083
2167
|
outputContent = lines.slice(startLine - 1, endLine).join('\n');
|
|
2084
2168
|
} else if (max_lines && lines.length > max_lines) {
|
|
@@ -2930,7 +3014,7 @@ async function handleMemorySearch({ query, type = 'all', maxResults = 6, minScor
|
|
|
2930
3014
|
score: fact.confidence || 0.8
|
|
2931
3015
|
}));
|
|
2932
3016
|
} else if (type === 'code') {
|
|
2933
|
-
const searchResult = await engine.
|
|
3017
|
+
const searchResult = await engine.intelligentSearch(query, { limit: maxResults });
|
|
2934
3018
|
results = searchResult.results.map(result => ({
|
|
2935
3019
|
type: 'chunk',
|
|
2936
3020
|
content: result.code || result.content,
|
|
@@ -3022,10 +3106,31 @@ async function handleMemoryGet({ type }) {
|
|
|
3022
3106
|
} else if (type === 'stats') {
|
|
3023
3107
|
const stats = await engine.getStats();
|
|
3024
3108
|
output = `📊 Memory Stats\n\n`;
|
|
3025
|
-
output +=
|
|
3026
|
-
output += `
|
|
3027
|
-
output += `
|
|
3028
|
-
output += `
|
|
3109
|
+
output += `📝 Memory Index\n`;
|
|
3110
|
+
output += ` Files: ${stats.memory?.files || 0}\n`;
|
|
3111
|
+
output += ` Chunks: ${stats.memory?.chunks || 0}\n`;
|
|
3112
|
+
output += ` Embeddings: ${stats.memory?.embeddings || 0}\n\n`;
|
|
3113
|
+
output += `💻 Codebase Index\n`;
|
|
3114
|
+
output += ` Files: ${stats.codebase?.files || 0}\n`;
|
|
3115
|
+
output += ` Facts: ${stats.codebase?.facts || 0}\n`;
|
|
3116
|
+
output += ` Chunks: ${stats.codebase?.chunks || 0}\n`;
|
|
3117
|
+
output += ` Embeddings: ${stats.codebase?.embeddings || 0}\n`;
|
|
3118
|
+
output += ` Edits: ${stats.codebase?.edits || 0}\n\n`;
|
|
3119
|
+
output += `🔄 Indexing\n`;
|
|
3120
|
+
output += ` Complete: ${stats.indexing?.is_complete ? '✅' : '⏳'}\n`;
|
|
3121
|
+
output += ` Indexed: ${stats.indexing?.indexed_files || 0}/${stats.indexing?.total_files || 0}\n`;
|
|
3122
|
+
output += ` Failed: ${stats.indexing?.failed_files || 0}\n`;
|
|
3123
|
+
} else if (type === 'reindex') {
|
|
3124
|
+
output = `🔄 Re-indexing Codebase\n\n`;
|
|
3125
|
+
output += `Starting re-index in background...\n`;
|
|
3126
|
+
|
|
3127
|
+
// Trigger re-index in background
|
|
3128
|
+
engine.performInitialScan().catch(err => {
|
|
3129
|
+
console.error('[Reindex] Error:', err.message);
|
|
3130
|
+
});
|
|
3131
|
+
|
|
3132
|
+
output += `✅ Re-index started. Check stats in a few seconds.\n`;
|
|
3133
|
+
output += `Use 'memory_get stats' to check progress.`;
|
|
3029
3134
|
} else if (type === 'intelligence') {
|
|
3030
3135
|
const intelStats = engine.getIntelligenceStats();
|
|
3031
3136
|
output = `🧠 Intelligence Stats\n\n`;
|
|
@@ -3250,12 +3355,50 @@ async function handleSelectStrategy({ instruction, files = [] }) {
|
|
|
3250
3355
|
/**
|
|
3251
3356
|
* Start Server
|
|
3252
3357
|
*/
|
|
3358
|
+
|
|
3359
|
+
// Acquire lock before starting - prevents multiple instances
|
|
3360
|
+
const lockAcquired = await acquireLock();
|
|
3361
|
+
if (!lockAcquired) {
|
|
3362
|
+
console.error(`${colors.red}[ERROR]${colors.reset} Failed to acquire lock. Another mcfast-mcp instance may be running.`);
|
|
3363
|
+
console.error(`${colors.yellow}[HINT]${colors.reset} Delete ${LOCK_FILE_PATH} if you're sure no other instance is running.`);
|
|
3364
|
+
process.exit(1);
|
|
3365
|
+
}
|
|
3366
|
+
|
|
3253
3367
|
const transport = new StdioServerTransport();
|
|
3254
3368
|
|
|
3255
3369
|
// Pre-initialize memory engine in background
|
|
3256
3370
|
backgroundInitializeMemoryEngine().catch(err => {
|
|
3257
3371
|
console.error(`${colors.yellow}[Memory]${colors.reset} Background init error: ${err.message}`);
|
|
3372
|
+
// Don't exit - continue without memory
|
|
3258
3373
|
});
|
|
3259
3374
|
|
|
3375
|
+
// Graceful shutdown handler
|
|
3376
|
+
async function gracefulShutdown(signal) {
|
|
3377
|
+
console.error(`${colors.yellow}[Shutdown]${colors.reset} Received ${signal}, cleaning up...`);
|
|
3378
|
+
|
|
3379
|
+
try {
|
|
3380
|
+
// Stop memory engine
|
|
3381
|
+
if (memoryEngine && memoryEngineReady) {
|
|
3382
|
+
await memoryEngine.cleanup();
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
// Flush audit queue
|
|
3386
|
+
const auditQ = getAuditQueue();
|
|
3387
|
+
await auditQ.destroy();
|
|
3388
|
+
|
|
3389
|
+
// Release lock
|
|
3390
|
+
await releaseLock();
|
|
3391
|
+
|
|
3392
|
+
console.error(`${colors.green}[Shutdown]${colors.reset} Cleanup complete`);
|
|
3393
|
+
} catch (error) {
|
|
3394
|
+
console.error(`${colors.red}[Shutdown]${colors.reset} Error during cleanup: ${error.message}`);
|
|
3395
|
+
}
|
|
3396
|
+
|
|
3397
|
+
process.exit(0);
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
3401
|
+
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
3402
|
+
|
|
3260
3403
|
await server.connect(transport);
|
|
3261
3404
|
console.error("mcfast MCP v1.0.0 running on stdio");
|