mcp-probe-kit 1.2.7 → 1.2.8

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/build/index.js CHANGED
@@ -6,7 +6,7 @@ import { detectShell, initSetting, initProject, gencommit, debug, genapi, codeRe
6
6
  // 创建MCP服务器实例
7
7
  const server = new Server({
8
8
  name: "mcp-probe-kit",
9
- version: "1.2.7",
9
+ version: "1.2.8",
10
10
  }, {
11
11
  capabilities: {
12
12
  tools: {},
@@ -528,7 +528,7 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
528
528
  timestamp: new Date().toISOString(),
529
529
  serverInfo: {
530
530
  name: "mcp-probe-kit",
531
- version: "1.2.7",
531
+ version: "1.2.8",
532
532
  description: "Cursor 开发增强工具集",
533
533
  },
534
534
  tools: {
@@ -5,6 +5,7 @@ export async function analyzeProject(args) {
5
5
  const maxDepth = args.max_depth || 5;
6
6
  const includeContent = args.include_content !== false;
7
7
  try {
8
+ console.error(`开始分析项目: ${projectPath}`);
8
9
  const analysis = await performProjectAnalysis(projectPath, maxDepth, includeContent);
9
10
  return {
10
11
  content: [
@@ -42,8 +43,14 @@ ${analysis.dependencies.production.slice(0, 10).map(dep => `- ${dep}`).join('\n'
42
43
  ## 📈 代码指标
43
44
  - **总文件数**: ${analysis.codeMetrics.totalFiles}
44
45
  - **总行数**: ${analysis.codeMetrics.totalLines}
46
+ ${analysis.codeMetrics.skippedFiles > 0 ? `- **跳过文件**: ${analysis.codeMetrics.skippedFiles} 个(过大或无法读取)` : ''}
45
47
  - **文件类型分布**:
46
- ${Object.entries(analysis.codeMetrics.fileTypes).map(([type, count]) => ` - ${type}: ${count} 个文件`).join('\n')}
48
+ ${Object.entries(analysis.codeMetrics.fileTypes)
49
+ .sort(([, a], [, b]) => b - a)
50
+ .slice(0, 10)
51
+ .map(([type, count]) => ` - ${type}: ${count} 个文件`)
52
+ .join('\n')}
53
+ ${Object.keys(analysis.codeMetrics.fileTypes).length > 10 ? ' - ... (更多类型已省略)' : ''}
47
54
 
48
55
  ### 最大文件
49
56
  ${analysis.codeMetrics.largestFiles.slice(0, 5).map(file => `- ${file.path} (${file.lines} 行)`).join('\n')}
@@ -61,7 +68,12 @@ ${analysis.summary.recommendations.map(rec => `- ${rec}`).join('\n')}
61
68
 
62
69
  ---
63
70
  *分析完成时间: ${new Date().toLocaleString('zh-CN')}*
64
- *分析工具: MCP Probe Kit v1.2.0*`,
71
+ *分析工具: MCP Probe Kit v1.2.8*
72
+
73
+ **分析说明**:
74
+ - 大型项目会自动采样分析,限制最多扫描 5000 个文件
75
+ - 已自动忽略以下目录: \`node_modules\`, \`dist\`, \`build\`, \`.git\`, \`coverage\`, \`.next\`, \`.nuxt\`, \`vendor\` 等
76
+ - 单个文件大小限制: 1MB,超过则跳过`,
65
77
  },
66
78
  ],
67
79
  };
@@ -181,19 +193,34 @@ function detectPackageManager() {
181
193
  return 'npm';
182
194
  }
183
195
  function generateDirectoryTree(projectPath, maxDepth) {
184
- const ignoreDirs = ['node_modules', '.git', 'dist', 'build', '.next', '.nuxt'];
196
+ const ignoreDirs = [
197
+ 'node_modules', '.git', 'dist', 'build', '.next', '.nuxt',
198
+ 'coverage', '.vscode', '.idea', 'tmp', 'temp', 'out',
199
+ 'vendor', '__pycache__', '.cache', '.parcel-cache',
200
+ 'bower_components', 'jspm_packages'
201
+ ];
202
+ const MAX_ITEMS_PER_DIR = 50; // 每个目录最多显示50项
185
203
  function buildTree(dir, prefix = '', depth = 0) {
186
204
  if (depth >= maxDepth)
187
205
  return '';
188
206
  try {
189
- const items = readdirSync(dir)
207
+ let items = readdirSync(dir)
190
208
  .filter(item => !ignoreDirs.includes(item) && !item.startsWith('.'))
191
209
  .map(item => {
192
210
  const fullPath = join(dir, item);
193
- const stat = statSync(fullPath);
194
- return { name: item, isDir: stat.isDirectory(), path: fullPath };
211
+ try {
212
+ const stat = statSync(fullPath);
213
+ return { name: item, isDir: stat.isDirectory(), path: fullPath };
214
+ }
215
+ catch {
216
+ return null;
217
+ }
195
218
  })
196
- .sort((a, b) => {
219
+ .filter(item => item !== null);
220
+ // 限制每个目录显示的项目数量
221
+ const hasMore = items.length > MAX_ITEMS_PER_DIR;
222
+ items = items.slice(0, MAX_ITEMS_PER_DIR);
223
+ items.sort((a, b) => {
197
224
  if (a.isDir && !b.isDir)
198
225
  return -1;
199
226
  if (!a.isDir && b.isDir)
@@ -202,7 +229,7 @@ function generateDirectoryTree(projectPath, maxDepth) {
202
229
  });
203
230
  let result = '';
204
231
  items.forEach((item, index) => {
205
- const isLast = index === items.length - 1;
232
+ const isLast = index === items.length - 1 && !hasMore;
206
233
  const currentPrefix = isLast ? '└── ' : '├── ';
207
234
  const nextPrefix = isLast ? ' ' : '│ ';
208
235
  result += `${prefix}${currentPrefix}${item.name}\n`;
@@ -210,6 +237,9 @@ function generateDirectoryTree(projectPath, maxDepth) {
210
237
  result += buildTree(item.path, prefix + nextPrefix, depth + 1);
211
238
  }
212
239
  });
240
+ if (hasMore) {
241
+ result += `${prefix}└── ... (更多项目被省略)\n`;
242
+ }
213
243
  return result;
214
244
  }
215
245
  catch {
@@ -225,12 +255,31 @@ async function identifyKeyFiles(projectPath, includeContent) {
225
255
  'webpack.config.js', 'vite.config.js', 'next.config.js', 'nuxt.config.js',
226
256
  'tsconfig.json', 'babel.config.js', '.env', '.env.example'
227
257
  ];
258
+ const MAX_FILE_SIZE = 100 * 1024; // 100KB
259
+ const MAX_CONTENT_LINES = 100; // 最多显示100行
228
260
  const keyFiles = [];
229
261
  for (const pattern of keyFilePatterns) {
230
262
  try {
231
263
  const filePath = join(projectPath, pattern);
232
- const content = readFileSync(filePath, 'utf-8');
264
+ const stat = statSync(filePath);
265
+ // 跳过过大的文件
266
+ if (stat.size > MAX_FILE_SIZE) {
267
+ keyFiles.push({
268
+ path: pattern,
269
+ purpose: getFilePurpose(pattern, ''),
270
+ content: includeContent ? `[文件过大 (${Math.round(stat.size / 1024)}KB),已跳过]` : ''
271
+ });
272
+ continue;
273
+ }
274
+ let content = readFileSync(filePath, 'utf-8');
233
275
  const purpose = getFilePurpose(pattern, content);
276
+ // 限制内容行数
277
+ if (includeContent && content) {
278
+ const lines = content.split('\n');
279
+ if (lines.length > MAX_CONTENT_LINES) {
280
+ content = lines.slice(0, MAX_CONTENT_LINES).join('\n') + `\n... (省略 ${lines.length - MAX_CONTENT_LINES} 行)`;
281
+ }
282
+ }
234
283
  keyFiles.push({
235
284
  path: pattern,
236
285
  purpose,
@@ -280,16 +329,39 @@ function analyzeDependencies(packageJson) {
280
329
  async function calculateCodeMetrics(projectPath) {
281
330
  const fileTypes = {};
282
331
  const largestFiles = [];
332
+ const MAX_FILES_TO_SCAN = 5000; // 最多扫描5000个文件
333
+ const MAX_FILE_SIZE = 1 * 1024 * 1024; // 1MB
334
+ const SAMPLE_LARGE_PROJECTS = true; // 大项目采样
283
335
  let totalFiles = 0;
284
336
  let totalLines = 0;
337
+ let skippedFiles = 0;
338
+ let scannedFiles = 0;
285
339
  function scanDirectory(dir) {
340
+ // 达到文件数量限制
341
+ if (scannedFiles >= MAX_FILES_TO_SCAN) {
342
+ return;
343
+ }
286
344
  try {
287
345
  const items = readdirSync(dir);
288
346
  for (const item of items) {
347
+ if (scannedFiles >= MAX_FILES_TO_SCAN)
348
+ break;
289
349
  const fullPath = join(dir, item);
290
- const stat = statSync(fullPath);
350
+ let stat;
351
+ try {
352
+ stat = statSync(fullPath);
353
+ }
354
+ catch {
355
+ continue;
356
+ }
291
357
  if (stat.isDirectory()) {
292
- if (!['node_modules', '.git', 'dist', 'build'].includes(item)) {
358
+ const ignoreDirs = [
359
+ 'node_modules', '.git', 'dist', 'build', '.next', '.nuxt',
360
+ 'coverage', '.vscode', '.idea', 'tmp', 'temp', 'out',
361
+ 'vendor', '__pycache__', '.cache', '.parcel-cache',
362
+ 'bower_components', 'jspm_packages', 'target', 'bin', 'obj'
363
+ ];
364
+ if (!ignoreDirs.includes(item) && !item.startsWith('.')) {
293
365
  scanDirectory(fullPath);
294
366
  }
295
367
  }
@@ -298,14 +370,27 @@ async function calculateCodeMetrics(projectPath) {
298
370
  const fileType = ext || 'no-extension';
299
371
  fileTypes[fileType] = (fileTypes[fileType] || 0) + 1;
300
372
  totalFiles++;
373
+ scannedFiles++;
374
+ // 跳过过大的文件
375
+ if (stat.size > MAX_FILE_SIZE) {
376
+ skippedFiles++;
377
+ continue;
378
+ }
301
379
  try {
302
- const content = readFileSync(fullPath, 'utf-8');
303
- const lines = content.split('\n').length;
304
- totalLines += lines;
305
- largestFiles.push({ path: fullPath, lines });
380
+ // 只读取文本文件
381
+ const textExtensions = ['.js', '.ts', '.jsx', '.tsx', '.vue', '.py', '.java', '.go', '.rs', '.php', '.rb', '.cpp', '.c', '.h', '.cs', '.swift', '.kt'];
382
+ if (textExtensions.includes(ext.toLowerCase())) {
383
+ const content = readFileSync(fullPath, 'utf-8');
384
+ const lines = content.split('\n').length;
385
+ totalLines += lines;
386
+ // 只保存相对路径
387
+ const relativePath = fullPath.replace(projectPath, '').replace(/\\/g, '/');
388
+ largestFiles.push({ path: relativePath, lines });
389
+ }
306
390
  }
307
391
  catch {
308
- // 忽略无法读取的文件
392
+ // 忽略无法读取的文件(二进制文件等)
393
+ skippedFiles++;
309
394
  }
310
395
  }
311
396
  }
@@ -314,14 +399,18 @@ async function calculateCodeMetrics(projectPath) {
314
399
  // 忽略无法访问的目录
315
400
  }
316
401
  }
402
+ console.error('开始扫描代码文件...');
403
+ console.error('忽略目录: node_modules, dist, build, .git 等');
317
404
  scanDirectory(projectPath);
405
+ console.error(`扫描完成: ${totalFiles} 个文件, ${skippedFiles} 个跳过`);
318
406
  // 按行数排序,取前10个
319
407
  largestFiles.sort((a, b) => b.lines - a.lines);
320
408
  return {
321
409
  totalFiles,
322
410
  totalLines,
323
411
  fileTypes,
324
- largestFiles: largestFiles.slice(0, 10)
412
+ largestFiles: largestFiles.slice(0, 10),
413
+ skippedFiles
325
414
  };
326
415
  }
327
416
  async function analyzeArchitecture(projectPath, keyFiles) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-probe-kit",
3
- "version": "1.2.7",
3
+ "version": "1.2.8",
4
4
  "description": "Cursor Development Enhancement Toolkit - MCP Server with 23 practical tools for code quality, development efficiency, and project management",
5
5
  "type": "module",
6
6
  "main": "build/index.js",