mcp-medic 1.2.6 → 1.2.7

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/dist/cli.d.ts CHANGED
@@ -13,6 +13,7 @@ export interface ParsedArgs {
13
13
  updateSnapshotPath?: string;
14
14
  json: boolean;
15
15
  timeoutMs?: number;
16
+ jobs?: number;
16
17
  showFixes: boolean;
17
18
  verbose: boolean;
18
19
  failOn: 'error' | 'warning';
package/dist/cli.js CHANGED
@@ -113,6 +113,14 @@ export function parseArgs(argv) {
113
113
  }
114
114
  args.protocolVersion = val;
115
115
  }
116
+ else if (arg === '--jobs') {
117
+ const value = argv[++i];
118
+ const parsed = value ? Number(value) : NaN;
119
+ if (!Number.isSafeInteger(parsed) || parsed < 1) {
120
+ throw new Error(`--jobs requires a positive safe integer, got: ${value ?? '(none)'}`);
121
+ }
122
+ args.jobs = parsed;
123
+ }
116
124
  else {
117
125
  positional.push(arg);
118
126
  }
@@ -213,6 +221,7 @@ OPTIONS
213
221
  --timeout <ms> Per-server handshake timeout in milliseconds (default: 5000)
214
222
  --protocol-version <v> MCP protocolVersion to request: "auto" (default, latest supported)
215
223
  or an explicit version, e.g. ${SUPPORTED_PROTOCOL_VERSIONS[SUPPORTED_PROTOCOL_VERSIONS.length - 1]}
224
+ --jobs <n> Maximum config files processed at once in check-all (default: 1)
216
225
  --help, -h Show help
217
226
  --version, -V Print the installed mcp-medic version
218
227
 
@@ -568,6 +577,7 @@ export async function main(argv = process.argv.slice(2), deps = {}) {
568
577
  const fleetReport = await runFleetChecks(glob, {
569
578
  checks,
570
579
  timeoutMs: args.timeoutMs,
580
+ jobs: args.jobs,
571
581
  verbose: args.verbose,
572
582
  protocolVersion: args.protocolVersion,
573
583
  });
package/dist/fleet.d.ts CHANGED
@@ -37,6 +37,7 @@ export declare function findConfigFiles(globOrPattern: string, rootDir?: string)
37
37
  */
38
38
  export declare function runFleetChecks(globPattern: string, options?: RunOptions & {
39
39
  cwd?: string;
40
+ jobs?: number;
40
41
  }): Promise<FleetReport>;
41
42
  /**
42
43
  * Compares two MCP configurations to identify server and attribute drift.
package/dist/fleet.js CHANGED
@@ -4,6 +4,20 @@ import { loadConfig } from './config-loader.js';
4
4
  import { runChecks } from './orchestrator.js';
5
5
  import { allChecks } from './checks/index.js';
6
6
  import { redactRecord } from './redact.js';
7
+ async function mapWithConcurrency(items, concurrency, worker) {
8
+ const results = new Array(items.length);
9
+ let nextIndex = 0;
10
+ const workerCount = Math.min(concurrency, items.length);
11
+ await Promise.all(Array.from({ length: workerCount }, async () => {
12
+ while (true) {
13
+ const index = nextIndex++;
14
+ if (index >= items.length)
15
+ return;
16
+ results[index] = await worker(items[index]);
17
+ }
18
+ }));
19
+ return results;
20
+ }
7
21
  function findFilesMatching(dir, rootDir, pattern, results = []) {
8
22
  if (!existsSync(dir))
9
23
  return results;
@@ -72,38 +86,36 @@ export function findConfigFiles(globOrPattern, rootDir = process.cwd()) {
72
86
  export async function runFleetChecks(globPattern, options = {}) {
73
87
  const root = options.cwd ?? process.cwd();
74
88
  const filePaths = findConfigFiles(globPattern, root);
75
- const fileResults = [];
76
- let totalServers = 0;
77
- let totalErrors = 0;
78
- let totalWarnings = 0;
79
- for (const filePath of filePaths) {
89
+ const jobs = options.jobs ?? 1;
90
+ if (!Number.isSafeInteger(jobs) || jobs < 1) {
91
+ throw new TypeError(`jobs must be a positive safe integer, got: ${jobs}`);
92
+ }
93
+ const processed = await mapWithConcurrency(filePaths, jobs, async (filePath) => {
80
94
  try {
81
95
  const rawText = readFileSync(filePath, 'utf-8');
82
96
  const rawJson = JSON.parse(rawText);
83
97
  const { config, errors } = loadConfig(rawJson, filePath);
84
98
  if (errors.length > 0 || !config) {
85
- fileResults.push({
86
- filePath,
87
- error: `Config validation failed: ${errors.join(', ')}`,
88
- });
89
- totalErrors += errors.length;
90
- continue;
99
+ return {
100
+ fileResult: { filePath, error: `Config validation failed: ${errors.join(', ')}` },
101
+ errorCount: errors.length,
102
+ };
91
103
  }
92
104
  const checks = options.checks ?? allChecks;
93
105
  const report = await runChecks(config, { ...options, checks });
94
- fileResults.push({ filePath, report });
95
- totalServers += report.summary.servers;
96
- totalErrors += report.summary.errors;
97
- totalWarnings += report.summary.warnings;
106
+ return { fileResult: { filePath, report }, errorCount: report.summary.errors };
98
107
  }
99
108
  catch (err) {
100
- fileResults.push({
101
- filePath,
102
- error: `Could not process file: ${err instanceof Error ? err.message : String(err)}`,
103
- });
104
- totalErrors += 1;
109
+ return {
110
+ fileResult: { filePath, error: `Could not process file: ${err instanceof Error ? err.message : String(err)}` },
111
+ errorCount: 1,
112
+ };
105
113
  }
106
- }
114
+ });
115
+ const fileResults = processed.map((item) => item.fileResult);
116
+ const totalServers = fileResults.reduce((sum, result) => sum + (result.report?.summary.servers ?? 0), 0);
117
+ const totalErrors = processed.reduce((sum, item) => sum + item.errorCount, 0);
118
+ const totalWarnings = fileResults.reduce((sum, result) => sum + (result.report?.summary.warnings ?? 0), 0);
107
119
  return {
108
120
  totalFiles: filePaths.length,
109
121
  successfulFiles: fileResults.filter((f) => !f.error).length,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-medic",
3
- "version": "1.2.6",
3
+ "version": "1.2.7",
4
4
  "description": "Diagnose broken MCP (Model Context Protocol) server configs before they break your agent silently.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",