imcp 0.0.1 → 0.0.2

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.
Files changed (38) hide show
  1. package/dist/cli/commands/install.js +8 -8
  2. package/dist/cli/index.js +3 -2
  3. package/dist/core/ConfigurationProvider.d.ts +2 -0
  4. package/dist/core/ConfigurationProvider.js +49 -3
  5. package/dist/core/InstallationService.d.ts +8 -0
  6. package/dist/core/InstallationService.js +117 -0
  7. package/dist/core/MCPManager.d.ts +1 -0
  8. package/dist/core/MCPManager.js +42 -0
  9. package/dist/core/RequirementService.d.ts +7 -0
  10. package/dist/core/RequirementService.js +17 -0
  11. package/dist/core/constants.d.ts +5 -0
  12. package/dist/core/constants.js +9 -4
  13. package/dist/core/installers/BaseInstaller.js +26 -9
  14. package/dist/core/installers/GeneralInstaller.js +0 -5
  15. package/dist/core/installers/NpmInstaller.js +2 -1
  16. package/dist/core/types.d.ts +7 -6
  17. package/dist/services/ServerService.js +16 -0
  18. package/dist/utils/versionUtils.d.ts +12 -0
  19. package/dist/utils/versionUtils.js +26 -0
  20. package/dist/web/public/js/modal.js +231 -46
  21. package/dist/web/server.d.ts +6 -0
  22. package/dist/web/server.js +6 -1
  23. package/package.json +1 -1
  24. package/src/cli/commands/install.ts +11 -14
  25. package/src/cli/index.ts +4 -2
  26. package/src/core/ConfigurationProvider.ts +51 -3
  27. package/src/core/InstallationService.ts +131 -0
  28. package/src/core/MCPManager.ts +60 -1
  29. package/src/core/RequirementService.ts +21 -1
  30. package/src/core/constants.ts +11 -5
  31. package/src/core/installers/BaseInstaller.ts +33 -17
  32. package/src/core/installers/GeneralInstaller.ts +0 -5
  33. package/src/core/installers/NpmInstaller.ts +2 -1
  34. package/src/core/types.ts +8 -6
  35. package/src/services/ServerService.ts +22 -0
  36. package/src/utils/versionUtils.ts +29 -0
  37. package/src/web/public/js/modal.js +231 -46
  38. package/src/web/server.ts +16 -2
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Utility functions for version comparison and management
3
+ */
4
+ /**
5
+ * Compare two semantic version strings
6
+ * @param v1 First version
7
+ * @param v2 Second version
8
+ * @returns -1 if v1 < v2, 0 if v1 = v2, 1 if v1 > v2
9
+ * (or more specifically, a negative number if v1 < v2,
10
+ * a positive number if v1 > v2, 0 if equal)
11
+ */
12
+ export function compareVersions(v1, v2) {
13
+ const v1Parts = v1.split('.').map(Number);
14
+ const v2Parts = v2.split('.').map(Number);
15
+ for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
16
+ const v1Part = i < v1Parts.length ? v1Parts[i] : 0;
17
+ const v2Part = i < v2Parts.length ? v2Parts[i] : 0;
18
+ if (v1Part !== v2Part) {
19
+ // This returns the actual difference, which is:
20
+ // negative if v1Part < v2Part, positive if v1Part > v2Part
21
+ return v1Part - v2Part;
22
+ }
23
+ }
24
+ return 0;
25
+ }
26
+ //# sourceMappingURL=versionUtils.js.map
@@ -4,6 +4,27 @@ import { showToast, showConfirm } from './notifications.js';
4
4
  document.addEventListener('DOMContentLoaded', () => {
5
5
  setupModalOutsideClick();
6
6
  });
7
+ /**
8
+ * Simple version comparison function
9
+ * @param {string} v1 First version
10
+ * @param {string} v2 Second version
11
+ * @returns {number} 1 if v1 > v2, -1 if v1 < v2, 0 if equal
12
+ */
13
+ function compareVersions(v1, v2) {
14
+ const v1Parts = v1.split('.').map(Number);
15
+ const v2Parts = v2.split('.').map(Number);
16
+
17
+ for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
18
+ const v1Part = v1Parts[i] || 0;
19
+ const v2Part = v2Parts[i] || 0;
20
+
21
+ if (v1Part > v2Part) return 1;
22
+ if (v1Part < v2Part) return -1;
23
+ }
24
+
25
+ return 0;
26
+ }
27
+
7
28
  /** Delayed message queue for loading modal */
8
29
  let messageQueue = [];
9
30
  let isAppending = false;
@@ -147,8 +168,8 @@ async function showInstallModal(categoryName, serverName, callback) {
147
168
  const operationStatus = serverStatus.installedStatus[target] || { status: 'not-installed', type: 'check', target: 'server' };
148
169
 
149
170
  // Determine client status
150
- let statusText = 'Not Installed';
151
- let statusClass = 'not-installed';
171
+ let statusText = '';
172
+ let statusClass = '';
152
173
 
153
174
  if (operationStatus.status === 'completed' && operationStatus.type === 'install') {
154
175
  statusText = 'Installed';
@@ -163,6 +184,7 @@ async function showInstallModal(categoryName, serverName, callback) {
163
184
  statusText = 'Failed';
164
185
  statusClass = 'not-installed';
165
186
  }
187
+ // Do not show not-installed status for targets that aren't installed
166
188
 
167
189
  const isConfigured = operationStatus.status === 'completed' && operationStatus.type === 'install';
168
190
 
@@ -222,14 +244,16 @@ async function showInstallModal(categoryName, serverName, callback) {
222
244
  // Add elements to client info
223
245
  clientInfo.appendChild(clientName);
224
246
 
225
- // Status badge
226
- const statusBadge = document.createElement('span');
227
- statusBadge.className = `status-badge ${statusClass}`;
228
- statusBadge.textContent = statusText;
229
-
230
- // Add components to client item
247
+ // Add client info (name) to the item first
231
248
  clientItem.appendChild(clientInfo);
232
- clientItem.appendChild(statusBadge);
249
+
250
+ // Status badge - only show if we have status text
251
+ if (statusText) {
252
+ const statusBadge = document.createElement('span');
253
+ statusBadge.className = `status-badge ${statusClass}`;
254
+ statusBadge.textContent = statusText;
255
+ clientItem.appendChild(statusBadge);
256
+ }
233
257
 
234
258
  // Add client item to target div
235
259
  targetDiv.appendChild(clientItem);
@@ -260,6 +284,9 @@ async function showInstallModal(categoryName, serverName, callback) {
260
284
  noEnvMessage.textContent = 'No environment variables required for this MCP server.';
261
285
  envInputsDiv.appendChild(noEnvMessage);
262
286
  } else {
287
+ // Get clientMcpSettings from the targets endpoint
288
+ let clientSettings = targetData.clientMcpSettings;
289
+
263
290
  // Create inputs for each environment variable
264
291
  Object.keys(envRequirements).forEach(key => {
265
292
  const req = envRequirements[key];
@@ -277,7 +304,21 @@ async function showInstallModal(categoryName, serverName, callback) {
277
304
  input.id = inputId;
278
305
  input.name = key;
279
306
  input.placeholder = req.Description || key;
280
- input.value = req.Default || '';
307
+
308
+ // For default value, first check MSRooCode for the target server, then use the provided default
309
+ let defaultValue = req.Default || '';
310
+
311
+ // Check if we have settings from MSRooCode
312
+ if (clientSettings && clientSettings.MSRooCode &&
313
+ clientSettings.MSRooCode.mcpServers &&
314
+ clientSettings.MSRooCode.mcpServers[serverName] &&
315
+ clientSettings.MSRooCode.mcpServers[serverName].env &&
316
+ clientSettings.MSRooCode.mcpServers[serverName].env[key]) {
317
+ defaultValue = clientSettings.MSRooCode.mcpServers[serverName].env[key];
318
+ console.log(`Using MSRooCode value for ${key}: ${defaultValue}`);
319
+ }
320
+
321
+ input.value = defaultValue;
281
322
  input.required = req.Required;
282
323
  input.className = 'input-field';
283
324
 
@@ -302,10 +343,36 @@ async function showInstallModal(categoryName, serverName, callback) {
302
343
  if (serverRequirements.length > 0) {
303
344
  const reqHtml = serverRequirements.map(req => {
304
345
  const status = requirements[req.name] || {};
305
- const statusClass = status.installed
346
+ let statusClass = status.installed
306
347
  ? 'text-green-600 bg-green-50'
307
348
  : 'text-yellow-600 bg-yellow-50';
308
- const statusText = status.installed ? 'Installed' : 'Required';
349
+ let statusText = status.installed ? 'Installed' : 'Required';
350
+ let versionDisplay = status.version ? ` • <span class="font-medium">${status.version}</span>` : '';
351
+ let updateToggle = '';
352
+
353
+ // Check if there's an available update
354
+ if (status.installed && status.availableUpdate && status.availableUpdate.version) {
355
+ if (status.version && compareVersions(status.availableUpdate.version, status.version) > 0) {
356
+ // Show version update information with yellow color and icon
357
+ statusClass = 'text-yellow-600 bg-yellow-50';
358
+ statusText = `<span style="color: #f59e0b; font-weight: bold; margin-right: 5px;">↑</span>${status.availableUpdate.version}`;
359
+
360
+ // Create a toggle switch for update
361
+ updateToggle = `
362
+ <label class="inline-flex items-center cursor-pointer ml-2">
363
+ <input type="checkbox" class="toggle-update sr-only"
364
+ data-name="${req.name}"
365
+ data-version="${status.availableUpdate.version}"
366
+ data-category="${categoryName}"
367
+ data-server="${serverName}">
368
+ <div class="relative w-10 h-5 bg-gray-200 rounded-full toggle-bg">
369
+ <div class="absolute inset-y-0 left-0 w-5 h-5 bg-white rounded-full transition-transform duration-300 transform"></div>
370
+ </div>
371
+ <span class="ml-2 text-sm text-gray-700">Update</span>
372
+ </label>
373
+ `;
374
+ }
375
+ }
309
376
 
310
377
  return `
311
378
  <div class="border border-gray-200 p-3 rounded-lg mb-2 hover:bg-gray-50">
@@ -313,12 +380,15 @@ async function showInstallModal(categoryName, serverName, callback) {
313
380
  <div>
314
381
  <div class="font-semibold text-gray-800">${req.name}</div>
315
382
  <div class="text-sm text-gray-600 shadow-sm p-1 rounded bg-gray-50">
316
- <span class="font-medium">${status.type || 'package'}</span>${status.version ? ` • <span class="font-medium">${status.version}</span>` : ''}
383
+ <span class="font-medium">${status.type || 'package'}</span>${versionDisplay}
317
384
  </div>
318
385
  </div>
319
- <span class="${statusClass} inline-flex items-center px-3 py-1 rounded-full text-sm">
320
- ${statusText}
321
- </span>
386
+ <div class="flex items-center">
387
+ <span class="${statusClass} inline-flex items-center px-3 py-1 rounded-full text-sm">
388
+ ${statusText}
389
+ </span>
390
+ ${updateToggle}
391
+ </div>
322
392
  </div>
323
393
  </div>
324
394
  `;
@@ -333,6 +403,24 @@ async function showInstallModal(categoryName, serverName, callback) {
333
403
  modalRequirements.innerHTML = '<p class="text-gray-600">No additional dependencies required.</p>';
334
404
  }
335
405
 
406
+ // Add event listeners for update toggles
407
+ setTimeout(() => {
408
+ const updateToggles = modalRequirements.querySelectorAll('.toggle-update');
409
+ updateToggles.forEach(toggle => {
410
+ toggle.addEventListener('change', function () {
411
+ // When toggled, update the visual appearance
412
+ const toggleBg = this.parentElement.querySelector('.toggle-bg');
413
+ if (this.checked) {
414
+ toggleBg.classList.add('bg-blue-500');
415
+ toggleBg.querySelector('div').classList.add('translate-x-5');
416
+ } else {
417
+ toggleBg.classList.remove('bg-blue-500');
418
+ toggleBg.querySelector('div').classList.remove('translate-x-5');
419
+ }
420
+ });
421
+ });
422
+ }, 100);
423
+
336
424
  // Set up the install form submit handler
337
425
  const installForm = document.getElementById('installForm');
338
426
  installForm.onsubmit = (e) => {
@@ -347,13 +435,27 @@ async function showInstallModal(categoryName, serverName, callback) {
347
435
  }
348
436
  });
349
437
 
438
+ // Check for enabled update toggles and collect requirements to update
439
+ const requirementsToUpdate = [];
440
+ const updateToggles = modalRequirements.querySelectorAll('.toggle-update:checked');
441
+ updateToggles.forEach(toggle => {
442
+ requirementsToUpdate.push({
443
+ name: toggle.dataset.name,
444
+ version: toggle.dataset.version
445
+ });
446
+ });
447
+
350
448
  // Get selected clients
351
449
  const selectedTargets = window.selectedClients.length > 0 ?
352
450
  window.selectedClients :
353
451
  Array.from(document.querySelectorAll('.client-item.selected'))
354
452
  .map(item => item.dataset.target);
355
453
 
356
- if (selectedTargets.length === 0) {
454
+ // Check if we have any requirements selected for update
455
+ const hasRequirementsToUpdate = requirementsToUpdate.length > 0;
456
+
457
+ // Only require client selection if we don't have any requirements to update
458
+ if (selectedTargets.length === 0 && !hasRequirementsToUpdate) {
357
459
  showToast('Please select at least one client to configure.', 'error');
358
460
  return;
359
461
  }
@@ -367,7 +469,19 @@ async function showInstallModal(categoryName, serverName, callback) {
367
469
  const msg = serverStatus.installedStatus?.[target]?.message;
368
470
  if (msg) installingMessage = msg;
369
471
  }
370
- handleBulkClientInstall(categoryName, serverName, selectedTargets, envVars, installingMessage, serverData);
472
+
473
+ // Add requirements to update to serverInstallOptions if any
474
+ const serverInstallOptions = {
475
+ targetClients: selectedTargets,
476
+ env: envVars
477
+ };
478
+
479
+ // Only add requirements if we have any to update
480
+ if (requirementsToUpdate.length > 0) {
481
+ serverInstallOptions.requirements = requirementsToUpdate;
482
+ }
483
+
484
+ handleBulkClientInstall(categoryName, serverName, selectedTargets, envVars, installingMessage, serverData, serverInstallOptions);
371
485
  };
372
486
 
373
487
  } catch (error) {
@@ -379,8 +493,8 @@ async function showInstallModal(categoryName, serverName, callback) {
379
493
  }
380
494
 
381
495
  // Function to handle bulk client installations
382
- async function handleBulkClientInstall(categoryName, serverName, targets, envVars = {}, installingMessage = "Starting installation...", serverData = null) {
383
- console.log('[LoadingModal] handleBulkClientInstall called', { categoryName, serverName, targets, envVars });
496
+ async function handleBulkClientInstall(categoryName, serverName, targets, envVars = {}, installingMessage = "Starting installation...", serverData = null, serverInstallOptions = null) {
497
+ console.log('[LoadingModal] handleBulkClientInstall called', { categoryName, serverName, targets, envVars, serverInstallOptions });
384
498
  // Hide install modal, show loading modal
385
499
  const installModal = document.getElementById('installModal');
386
500
  console.log('[LoadingModal] installModal:', installModal);
@@ -401,26 +515,29 @@ async function handleBulkClientInstall(categoryName, serverName, targets, envVar
401
515
  }
402
516
  }
403
517
 
404
- showInstallLoadingModal(installingMessage);
405
-
518
+ showInstallLoadingModal();
406
519
  delayedAppendInstallLoadingMessage(installingMessage);
407
520
 
408
521
  try {
409
522
  delayedAppendInstallLoadingMessage("Installing, please wait...");
523
+
524
+ // Use serverInstallOptions if provided, otherwise build the traditional options
525
+ const requestBody = {
526
+ serverList: {
527
+ [serverName]: serverInstallOptions || {
528
+ targetClients: targets,
529
+ env: envVars
530
+ }
531
+ }
532
+ };
533
+
410
534
  const response = await fetch(`/api/categories/${categoryName}/install`, {
411
535
  method: 'POST',
412
536
  headers: {
413
537
  'Content-Type': 'application/json',
414
538
  'Accept': 'application/json'
415
539
  },
416
- body: JSON.stringify({
417
- serverList: {
418
- [serverName]: {
419
- targetClients: targets,
420
- env: envVars
421
- }
422
- }
423
- })
540
+ body: JSON.stringify(requestBody)
424
541
  });
425
542
 
426
543
  console.log('[LoadingModal] fetch install response:', response);
@@ -441,8 +558,9 @@ async function handleBulkClientInstall(categoryName, serverName, targets, envVar
441
558
  }
442
559
 
443
560
  // Optionally, you can refresh modal data here or trigger a callback
444
- // Start polling for install status
445
- pollInstallStatus(categoryName, serverName, targets);
561
+ // Start polling for install status, pass requirements if available
562
+ const requirements = serverInstallOptions?.requirements || [];
563
+ pollInstallStatus(categoryName, serverName, targets, 2000, 60, requirements);
446
564
  } catch (error) {
447
565
  console.error('[LoadingModal] Error applying configuration:', error);
448
566
  delayedAppendInstallLoadingMessage(`<span style="color:red;">Error: ${error.message}</span>`);
@@ -455,33 +573,86 @@ async function handleBulkClientInstall(categoryName, serverName, targets, envVar
455
573
  }
456
574
  }
457
575
 
458
- // Poll install status for the given server/targets
459
- async function pollInstallStatus(categoryName, serverName, targets, interval = 2000, maxTries = 60) {
576
+ // Poll install status for the given server/targets and optional requirements
577
+ async function pollInstallStatus(categoryName, serverName, targets, interval = 2000, maxTries = 60, requirements = []) {
460
578
  let tries = 0;
461
579
  let lastMessages = {};
580
+ let lastRequirementMessages = {};
462
581
  // Use global delayedAppendInstallLoadingMessage and queue logic
463
582
  while (tries < maxTries) {
464
583
  try {
465
584
  const resp = await fetch(`/api/categories/${categoryName}`);
466
585
  if (resp.ok) {
467
586
  const data = await resp.json();
468
- const serverStatuses = data?.data?.installationStatus?.serversStatus || {};
587
+ const installationStatus = data?.data?.installationStatus || {};
588
+ const serverStatuses = installationStatus.serversStatus || {};
589
+ const requirementsStatus = installationStatus.requirementsStatus || {};
469
590
  const serverStatus = serverStatuses[serverName] || { installedStatus: {} };
470
- let allCompleted = true;
471
- for (const target of targets) {
472
- const status = serverStatus.installedStatus?.[target]?.status;
473
- const msg = serverStatus.installedStatus?.[target]?.message;
474
- // Only append new messages
475
- if (msg && lastMessages[target] !== msg) {
476
- delayedAppendInstallLoadingMessage(`[${target}] ${msg}`);
477
- lastMessages[target] = msg;
591
+
592
+ // First check requirements status if we have any
593
+ let allRequirementsCompleted = true;
594
+ let hasRequirements = requirements.length > 0;
595
+
596
+ for (const req of requirements) {
597
+ const reqStatus = requirementsStatus[req.name] || {};
598
+ const opStatus = reqStatus.operationStatus || {};
599
+ const msg = opStatus.message;
600
+ const status = opStatus.status;
601
+
602
+ // Only append new messages for requirements
603
+ if (msg && lastRequirementMessages[req.name] !== msg) {
604
+ delayedAppendInstallLoadingMessage(`[Requirement: ${req.name}] ${msg}`);
605
+ lastRequirementMessages[req.name] = msg;
478
606
  }
479
- if (status !== "completed") {
480
- allCompleted = false;
607
+
608
+ if (status !== "completed" && status !== "failed") {
609
+ allRequirementsCompleted = false;
610
+ }
611
+
612
+ // If a requirement failed, show an error
613
+ if (status === "failed") {
614
+ delayedAppendInstallLoadingMessage(`<span style="color:red;">Requirement update failed: ${req.name} - ${msg || 'Unknown error'}</span>`);
615
+ }
616
+ }
617
+
618
+ // Now check target statuses
619
+ let allTargetsCompleted = true;
620
+ let hasTargets = targets && targets.length > 0;
621
+
622
+ if (hasTargets) {
623
+ for (const target of targets) {
624
+ const status = serverStatus.installedStatus?.[target]?.status;
625
+ const msg = serverStatus.installedStatus?.[target]?.message;
626
+ // Only append new messages for targets
627
+ if (msg && lastMessages[target] !== msg) {
628
+ delayedAppendInstallLoadingMessage(`[Target: ${target}] ${msg}`);
629
+ lastMessages[target] = msg;
630
+ }
631
+ if (status !== "completed") {
632
+ allTargetsCompleted = false;
633
+ }
481
634
  }
482
635
  }
636
+
637
+ // Complete if all operations are done
638
+ const allCompleted = (!hasRequirements || allRequirementsCompleted) &&
639
+ (!hasTargets || allTargetsCompleted);
640
+
483
641
  if (allCompleted) {
484
- delayedAppendInstallLoadingMessage(`<span style="color:green;">Configuration applied successfully for ${targets.length} client(s).</span>`);
642
+ // Compose completion message based on what was processed
643
+ let completionMessage = '';
644
+
645
+ if (hasRequirements && hasTargets) {
646
+ completionMessage = `Requirements updated and configuration applied successfully for ${targets.length} client(s).`;
647
+ } else if (hasRequirements) {
648
+ completionMessage = `Requirements updated successfully.`;
649
+ } else if (hasTargets) {
650
+ completionMessage = `Configuration applied successfully for ${targets.length} client(s).`;
651
+ } else {
652
+ completionMessage = `Operation completed successfully.`;
653
+ }
654
+
655
+ delayedAppendInstallLoadingMessage(`<span style="color:green;">${completionMessage}</span>`);
485
656
  setTimeout(() => {
486
657
  hideInstallLoadingModal();
487
658
  setTimeout(() => {
@@ -568,5 +739,19 @@ window.showInstallLoadingModal = showInstallLoadingModal;
568
739
  window.appendInstallLoadingMessage = appendInstallLoadingMessage;
569
740
  window.hideInstallLoadingModal = hideInstallLoadingModal;
570
741
 
742
+ // CSS styles for the toggle switch
743
+ const styleElement = document.createElement('style');
744
+ styleElement.textContent = `
745
+ .toggle-bg.bg-blue-500 {
746
+ background-color: #3b82f6;
747
+ }
748
+ .toggle-bg {
749
+ transition: background-color 0.3s;
750
+ }
751
+ .toggle-bg div {
752
+ transition: transform 0.3s;
753
+ }
754
+ `;
755
+ document.head.appendChild(styleElement);
571
756
 
572
757
  export { showInstallModal, closeModal, setupModalOutsideClick, uninstallTools };
@@ -1,4 +1,10 @@
1
1
  import { ServerInstallOptions } from '../core/types.js';
2
+ export interface UpdateRequirementsRequestBody {
3
+ requirements: {
4
+ name: string;
5
+ updateVersion: string;
6
+ }[];
7
+ }
2
8
  export interface InstallServersRequestBody {
3
9
  serverList: Record<string, ServerInstallOptions>;
4
10
  }
@@ -5,6 +5,7 @@ import { SUPPORTED_CLIENT_NAMES } from '../core/constants.js';
5
5
  import { serverService } from '../services/ServerService.js';
6
6
  import { openBrowser } from '../utils/osUtils.js';
7
7
  import { Logger } from '../utils/logger.js';
8
+ import { configProvider } from '../core/ConfigurationProvider.js';
8
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
10
  const app = express();
10
11
  // Middleware
@@ -13,9 +14,13 @@ app.use(express.json());
13
14
  // Get available targets
14
15
  app.get('/api/targets', async (req, res) => {
15
16
  try {
17
+ // Get clientMcpSettings
18
+ const clientMcpSettings = await configProvider.getClientMcpSettings();
19
+ // Keep original format but add clientMcpSettings as additional property
16
20
  const response = {
17
21
  success: true,
18
- data: SUPPORTED_CLIENT_NAMES
22
+ data: SUPPORTED_CLIENT_NAMES,
23
+ clientMcpSettings: clientMcpSettings
19
24
  };
20
25
  res.json(response);
21
26
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imcp",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Node.js SDK for Model Context Protocol (MCP)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,11 +27,6 @@ Examples:
27
27
  '--name <name>',
28
28
  'Server name to install'
29
29
  )
30
- .option(
31
- '--force',
32
- 'Force installation even if server already exists',
33
- false
34
- )
35
30
  .option(
36
31
  '--clients <clients>',
37
32
  'Target clients (semicolon separated). Supported values: Cline, MSRooCode, GithubCopilot. If not specified, installs for all clients'
@@ -43,7 +38,6 @@ Examples:
43
38
  .action(async (options: {
44
39
  category: string;
45
40
  name: string;
46
- force: boolean;
47
41
  clients?: string;
48
42
  envs?: string;
49
43
  verbose?: boolean;
@@ -55,19 +49,22 @@ Examples:
55
49
  Logger.log('Local feeds not found, syncing from remote...');
56
50
  await serverService.syncFeeds();
57
51
  }
58
-
59
- const { category, name, verbose, force, clients, envs } = options;
52
+ const { category, name, verbose, clients, envs } = options;
60
53
 
61
- Logger.debug(`Install options: ${JSON.stringify({ category, name, force, verbose, clients, envs })}`);
54
+ Logger.debug(`Install options: ${JSON.stringify({ category, name, verbose, clients, envs })}`);
62
55
 
63
56
  const serverName = name.trim();
64
57
  Logger.debug(`Server name: ${serverName}`);
65
58
 
66
59
  if (!await serverService.validateServerName(category, serverName)) {
67
- Logger.error('Invalid server name or category provided', {
68
- category,
69
- serverName
70
- });
60
+ Logger.error(
61
+ 'Invalid server name or category provided.\n' +
62
+ 'This could be because:\n' +
63
+ ' 1. The server name or category is misspelled\n' +
64
+ ' 2. Your local feeds are outdated\n\n' +
65
+ 'Try running "imcp pull" to update your local feeds from remote.',
66
+ { category, serverName }
67
+ );
71
68
  process.exit(1);
72
69
  }
73
70
 
@@ -111,7 +108,7 @@ Examples:
111
108
  Logger.log(`Installing server: ${serverName}`);
112
109
 
113
110
  const installOptions: ServerInstallOptions = {
114
- force: options.force,
111
+ force: false,
115
112
  ...(parsedClients?.length && { targetClients: parsedClients }),
116
113
  ...(Object.keys(parsedEnvs).length > 0 && { env: parsedEnvs })
117
114
  };
package/src/cli/index.ts CHANGED
@@ -12,6 +12,7 @@ import axios from 'axios';
12
12
  import path from 'path';
13
13
  import { fileURLToPath } from 'url';
14
14
  import fs from 'fs';
15
+ import { compareVersions } from '../utils/versionUtils.js';
15
16
 
16
17
  // Custom error interface for Commander.js errors
17
18
  // ANSI color codes
@@ -32,7 +33,6 @@ async function main(): Promise<void> {
32
33
  program
33
34
  .name('imcp')
34
35
  .description('IMCP (Install Model Context Protocol) CLI')
35
- .version('0.0.1')
36
36
  .option('--verbose', 'Show detailed logs for all commands');
37
37
 
38
38
  // Parse global options first
@@ -84,6 +84,7 @@ process.on('unhandledRejection', (error: unknown) => {
84
84
  /**
85
85
  * Check if there's a newer version of the package available
86
86
  */
87
+
87
88
  async function checkForUpdates(): Promise<void> {
88
89
  try {
89
90
  // Get the current package version
@@ -101,7 +102,8 @@ async function checkForUpdates(): Promise<void> {
101
102
  if (npmResponse.data && npmResponse.data['dist-tags'] && npmResponse.data['dist-tags'].latest) {
102
103
  const latestVersion = npmResponse.data['dist-tags'].latest;
103
104
 
104
- if (latestVersion && latestVersion !== currentVersion) {
105
+ // Compare versions properly to ensure we're only notifying for newer versions
106
+ if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {
105
107
  console.log(`${COLORS.yellow}Update available for ${packageName}: ${currentVersion} → ${latestVersion}${COLORS.reset}`);
106
108
  console.log(`${COLORS.yellow}Run \`npm install -g ${packageName}@latest\` to update${COLORS.reset}`);
107
109
  }