agent-discover 1.0.5 → 1.0.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/ui/app.js CHANGED
@@ -12,7 +12,6 @@
12
12
  let currentTab = 'installed';
13
13
  let searchTimeout = null;
14
14
  let openSections = {}; // track open sections per server: { "serverId-sectionName": true }
15
- let openApprovalDropdown = null; // server id with open dropdown
16
15
 
17
16
  // -------------------------------------------------------------------------
18
17
  // WebSocket
@@ -185,9 +184,6 @@
185
184
  : 'Active'
186
185
  : 'Inactive';
187
186
 
188
- // Approval badge removed — not useful without automatic classification
189
-
190
- // Combined status: active+healthy=green, active+unhealthy=red, inactive=gray
191
187
  var healthStatus = s.health_status || 'unknown';
192
188
 
193
189
  // Error count
@@ -279,8 +275,16 @@
279
275
  esc(s.source || 'local') +
280
276
  '</span>' +
281
277
  '<span>' +
282
- esc(s.transport || 'stdio') +
278
+ (function () {
279
+ var t = s.transport || 'stdio';
280
+ if (t === 'sse') return 'remote sse';
281
+ if (t === 'streamable-http') return 'remote http';
282
+ return 'local stdio';
283
+ })() +
283
284
  '</span>' +
285
+ (s.transport && s.transport !== 'stdio' && s.homepage
286
+ ? '<span style="font-size:11px;color:var(--text-muted)">' + esc(s.homepage) + '</span>'
287
+ : '') +
284
288
  '</div>' +
285
289
  toolSection +
286
290
  actionsSection +
@@ -487,20 +491,49 @@
487
491
  .map(function (s, idx) {
488
492
  var pkgs = (s.packages || [])
489
493
  .map(function (p) {
490
- return '<span class="tag">' + esc(p.runtime) + ': ' + esc(p.name) + '</span>';
494
+ var rt = p.runtime || 'stdio';
495
+ var color =
496
+ rt === 'streamable-http'
497
+ ? 'var(--accent, #5d8da8)'
498
+ : rt === 'sse'
499
+ ? 'var(--orange, #e67e22)'
500
+ : 'var(--green, #27ae60)';
501
+ return (
502
+ '<span class="tag" style="border-color:' +
503
+ color +
504
+ ';color:' +
505
+ color +
506
+ '">' +
507
+ esc(rt) +
508
+ ': ' +
509
+ esc(p.name) +
510
+ '</span>'
511
+ );
491
512
  })
492
513
  .join('');
493
514
 
494
515
  var safeName = (s.name || '').replace(/\//g, '-');
495
516
  var isInstalled =
496
517
  installedNames.indexOf(safeName) !== -1 || installedNames.indexOf(s.name) !== -1;
497
- var installBtn = isInstalled
498
- ? '<button class="btn-install btn-installed" disabled><span class="material-symbols-outlined" style="font-size:14px">check_circle</span>Installed</button>'
499
- : '<button class="btn-install" data-browse-idx="' +
518
+
519
+ // All transport types are supported (stdio, sse, streamable-http)
520
+ var isRemoteOnly = false;
521
+
522
+ var installBtn;
523
+ if (isInstalled) {
524
+ installBtn =
525
+ '<button class="btn-install btn-installed" disabled><span class="material-symbols-outlined" style="font-size:14px">check_circle</span>Installed</button>';
526
+ } else if (isRemoteOnly) {
527
+ installBtn =
528
+ '<button class="btn-install" disabled title="Remote server — not supported for local activation"><span class="material-symbols-outlined" style="font-size:14px">cloud_off</span>Remote only</button>';
529
+ } else {
530
+ installBtn =
531
+ '<button class="btn-install" data-browse-idx="' +
500
532
  idx +
501
533
  '" onclick="window.__installFromBrowse(' +
502
534
  idx +
503
535
  ', this)"><span class="material-symbols-outlined" style="font-size:14px">download</span>Install</button>';
536
+ }
504
537
 
505
538
  return (
506
539
  '<div class="server-card">' +
@@ -545,13 +578,16 @@
545
578
  window.__activateServer = function (id) {
546
579
  fetch('/api/servers/' + id + '/activate', { method: 'POST' })
547
580
  .then(function (r) {
548
- return r.json();
549
- })
550
- .then(function () {
551
- // State will refresh via WebSocket
581
+ return r.json().then(function (data) {
582
+ if (data.error) {
583
+ showToast('Activation failed: ' + data.error, 'error');
584
+ } else if (data.status === 'activated') {
585
+ showToast('Activated with ' + (data.tool_count || 0) + ' tools', 'success');
586
+ }
587
+ });
552
588
  })
553
589
  .catch(function (err) {
554
- console.error('Activate failed:', err);
590
+ showToast('Activation failed: ' + err.message, 'error');
555
591
  });
556
592
  };
557
593
 
@@ -591,29 +627,54 @@
591
627
  '<span class="material-symbols-outlined" style="font-size:14px">hourglass_top</span>Installing...';
592
628
 
593
629
  var safeName = (server.name || '').replace(/\//g, '-');
594
- var npmPkg = safeName;
595
- // Try to derive npm package name from registry name (e.g. "io.github.user/pkg" -> "@user/pkg")
596
- var parts = (server.name || '').split('/');
597
- if (parts.length >= 2) {
598
- npmPkg = parts[parts.length - 1];
630
+ // Detect transport and build config
631
+ var pkg = (server.packages || [])[0];
632
+ var transport = (pkg && (pkg.transport || pkg.runtime)) || 'stdio';
633
+ var remoteUrl = pkg && pkg.url ? pkg.url : null;
634
+
635
+ var serverData = {
636
+ name: safeName,
637
+ description: server.description || '',
638
+ source: 'registry',
639
+ transport: transport,
640
+ tags: ['marketplace'],
641
+ };
642
+
643
+ if (transport === 'streamable-http' || transport === 'sse') {
644
+ serverData.homepage = remoteUrl || server.repository || '';
645
+ } else {
646
+ // stdio / node / python — default to npx
647
+ serverData.transport = 'stdio';
648
+ serverData.command = 'npx';
649
+ serverData.args = ['-y', pkg ? pkg.name || server.name : server.name || safeName];
599
650
  }
651
+
600
652
  fetch('/api/servers', {
601
653
  method: 'POST',
602
654
  headers: { 'Content-Type': 'application/json' },
603
- body: JSON.stringify({
604
- name: safeName,
605
- description: server.description || '',
606
- command: 'npx',
607
- args: ['-y', server.name || npmPkg],
608
- source: 'registry',
609
- tags: ['marketplace'],
610
- }),
655
+ body: JSON.stringify(serverData),
611
656
  })
612
657
  .then(function (r) {
613
658
  if (!r.ok) throw new Error('Install failed');
614
659
  return r.json();
615
660
  })
616
- .then(function () {
661
+ .then(function (data) {
662
+ if (serverData.command === 'npx' && data && data.id) {
663
+ btn.innerHTML =
664
+ '<span class="material-symbols-outlined" style="font-size:14px">downloading</span>Downloading...';
665
+ return fetch('/api/servers/' + data.id + '/preinstall', { method: 'POST' })
666
+ .then(function () {
667
+ btn.innerHTML =
668
+ '<span class="material-symbols-outlined" style="font-size:14px">check_circle</span>Ready';
669
+ btn.classList.add('btn-installed');
670
+ })
671
+ .catch(function () {
672
+ // Download failed but install succeeded
673
+ btn.innerHTML =
674
+ '<span class="material-symbols-outlined" style="font-size:14px">check_circle</span>Installed';
675
+ btn.classList.add('btn-installed');
676
+ });
677
+ }
617
678
  btn.innerHTML =
618
679
  '<span class="material-symbols-outlined" style="font-size:14px">check_circle</span>Installed';
619
680
  btn.classList.add('btn-installed');
@@ -635,30 +696,80 @@
635
696
  var pkg = (input ? input.value : '').trim();
636
697
  if (!pkg) return;
637
698
 
638
- var safeName = pkg.replace(/@/g, '').replace(/\//g, '-');
639
- fetch('/api/servers', {
640
- method: 'POST',
641
- headers: { 'Content-Type': 'application/json' },
642
- body: JSON.stringify({
643
- name: safeName,
644
- command: 'npx',
645
- args: ['-y', pkg],
646
- description: 'Installed from npm: ' + pkg,
647
- source: 'registry',
648
- tags: ['npm'],
649
- }),
650
- })
699
+ // Find the install button and show spinner
700
+ var btn = input ? input.parentElement.querySelector('.btn-install') : null;
701
+ var origHtml = btn ? btn.innerHTML : '';
702
+ if (btn) {
703
+ btn.disabled = true;
704
+ btn.innerHTML =
705
+ '<span class="material-symbols-outlined" style="font-size:14px">hourglass_top</span> Checking...';
706
+ }
707
+
708
+ fetch('/api/npm-check?package=' + encodeURIComponent(pkg))
651
709
  .then(function (r) {
652
- if (!r.ok) throw new Error('Install failed');
653
710
  return r.json();
654
711
  })
655
- .then(function () {
656
- showToast('Installed ' + pkg, 'success');
657
- if (input) input.value = '';
712
+ .then(function (data) {
713
+ if (!data.exists) {
714
+ showToast('Package not found on npm', 'error');
715
+ if (btn) {
716
+ btn.disabled = false;
717
+ btn.innerHTML = origHtml;
718
+ }
719
+ return;
720
+ }
721
+
722
+ var safeName = pkg.replace(/@/g, '').replace(/\//g, '-');
723
+ return fetch('/api/servers', {
724
+ method: 'POST',
725
+ headers: { 'Content-Type': 'application/json' },
726
+ body: JSON.stringify({
727
+ name: safeName,
728
+ command: 'npx',
729
+ args: ['-y', pkg],
730
+ description: 'Installed from npm: ' + pkg,
731
+ source: 'registry',
732
+ tags: ['npm'],
733
+ }),
734
+ })
735
+ .then(function (r) {
736
+ if (!r.ok) throw new Error('Install failed');
737
+ return r.json();
738
+ })
739
+ .then(function (data) {
740
+ if (data && data.id) {
741
+ if (btn) {
742
+ btn.innerHTML =
743
+ '<span class="material-symbols-outlined" style="font-size:14px">downloading</span> Downloading...';
744
+ }
745
+ return fetch('/api/servers/' + data.id + '/preinstall', { method: 'POST' })
746
+ .then(function () {
747
+ showToast('Installed and downloaded ' + pkg, 'success');
748
+ })
749
+ .catch(function () {
750
+ showToast(
751
+ 'Installed ' + pkg + ' (download will happen on first activate)',
752
+ 'success',
753
+ );
754
+ });
755
+ }
756
+ showToast('Installed ' + pkg, 'success');
757
+ })
758
+ .then(function () {
759
+ if (input) input.value = '';
760
+ if (btn) {
761
+ btn.disabled = false;
762
+ btn.innerHTML = origHtml;
763
+ }
764
+ });
658
765
  })
659
766
  .catch(function (err) {
660
767
  console.error('npm install failed:', err);
661
768
  showToast('Install failed: ' + err.message, 'error');
769
+ if (btn) {
770
+ btn.disabled = false;
771
+ btn.innerHTML = origHtml;
772
+ }
662
773
  });
663
774
  };
664
775
 
@@ -702,29 +813,6 @@
702
813
  render();
703
814
  };
704
815
 
705
- window.__toggleApprovalDropdown = function (serverId) {
706
- openApprovalDropdown = openApprovalDropdown === serverId ? null : serverId;
707
- render();
708
- };
709
-
710
- window.__setApproval = function (serverId, status) {
711
- openApprovalDropdown = null;
712
- fetch('/api/servers/' + serverId, {
713
- method: 'PUT',
714
- headers: { 'Content-Type': 'application/json' },
715
- body: JSON.stringify({ approval_status: status }),
716
- })
717
- .then(function (r) {
718
- return r.json();
719
- })
720
- .then(function () {
721
- showToast('Approval status set to ' + status, 'success');
722
- })
723
- .catch(function () {
724
- showToast('Failed to update approval status', 'error');
725
- });
726
- };
727
-
728
816
  window.__checkHealth = function (serverId) {
729
817
  fetch('/api/servers/' + serverId + '/health', { method: 'POST' })
730
818
  .then(function (r) {
@@ -855,17 +943,6 @@
855
943
  }, 3000);
856
944
  }
857
945
 
858
- // -------------------------------------------------------------------------
859
- // Close approval dropdown on outside click
860
- // -------------------------------------------------------------------------
861
-
862
- document.addEventListener('click', function (e) {
863
- if (openApprovalDropdown !== null && !e.target.closest('.approval-badge')) {
864
- openApprovalDropdown = null;
865
- render();
866
- }
867
- });
868
-
869
946
  // -------------------------------------------------------------------------
870
947
  // Init
871
948
  // -------------------------------------------------------------------------
@@ -697,65 +697,6 @@ body {
697
697
  color: #e57373;
698
698
  }
699
699
 
700
- /* ---------------------------------------------------------------------------
701
- Approval badges
702
- --------------------------------------------------------------------------- */
703
-
704
- .approval-badge {
705
- font-size: 11px;
706
- padding: 2px 8px;
707
- border-radius: 4px;
708
- font-weight: 500;
709
- cursor: pointer;
710
- position: relative;
711
- }
712
-
713
- .approval-experimental {
714
- color: #e89b3e;
715
- border: 1px solid rgba(232, 155, 62, 0.3);
716
- }
717
-
718
- .approval-approved {
719
- color: #4caf50;
720
- border: 1px solid rgba(76, 175, 80, 0.3);
721
- }
722
-
723
- .approval-production {
724
- color: var(--accent);
725
- border: 1px solid rgba(93, 141, 168, 0.3);
726
- }
727
-
728
- .approval-dropdown {
729
- position: absolute;
730
- top: 100%;
731
- left: 0;
732
- margin-top: 4px;
733
- background: var(--bg-elevated);
734
- border: 1px solid var(--border);
735
- border-radius: 6px;
736
- box-shadow: var(--shadow-md);
737
- z-index: 10;
738
- min-width: 120px;
739
- overflow: hidden;
740
- }
741
-
742
- .approval-dropdown-item {
743
- display: block;
744
- width: 100%;
745
- padding: 6px 12px;
746
- border: none;
747
- background: transparent;
748
- color: var(--text);
749
- font-family: var(--font-ui);
750
- font-size: 12px;
751
- text-align: left;
752
- cursor: pointer;
753
- }
754
-
755
- .approval-dropdown-item:hover {
756
- background: var(--bg-hover);
757
- }
758
-
759
700
  /* ---------------------------------------------------------------------------
760
701
  Health dot
761
702
  --------------------------------------------------------------------------- */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-discover",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "mcpName": "io.github.keshrath/agent-discover",
5
5
  "description": "MCP server registry and marketplace — discover, install, activate, and manage MCP tools on demand",
6
6
  "type": "module",