imcp 0.0.6 → 0.0.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.
@@ -105,10 +105,11 @@ export class ConfigurationLoader {
105
105
  * Synchronizes server categories with feeds
106
106
  */
107
107
  static async syncServerCategoriesWithFeeds(configuration) {
108
- configuration.localServerCategories = configuration.localServerCategories.map(server => {
109
- if (configuration.feeds[server.name]) {
110
- server.feedConfiguration = configuration.feeds[server.name];
111
- }
108
+ // Filter out categories that don't have corresponding feeds and update existing ones
109
+ configuration.localServerCategories = configuration.localServerCategories
110
+ .filter(server => configuration.feeds[server.name])
111
+ .map(server => {
112
+ server.feedConfiguration = configuration.feeds[server.name];
112
113
  if (!server.installationStatus ||
113
114
  !server.installationStatus.requirementsStatus ||
114
115
  Object.keys(server.installationStatus.requirementsStatus).length === 0 ||
@@ -118,6 +119,7 @@ export class ConfigurationLoader {
118
119
  }
119
120
  return server;
120
121
  });
122
+ // Add new categories for feeds that don't have a corresponding category
121
123
  const existingServerNames = new Set(configuration.localServerCategories.map(category => category.name));
122
124
  for (const [feedName, feedConfig] of Object.entries(configuration.feeds)) {
123
125
  if (!existingServerNames.has(feedName)) {
@@ -48,17 +48,24 @@ export class ConfigurationProvider {
48
48
  const configDir = path.dirname(this.configPath);
49
49
  await fs.mkdir(configDir, { recursive: true });
50
50
  try {
51
- const config = JSON.parse(await fs.readFile(this.configPath, 'utf8'));
52
- this.configuration = config;
53
- await this.loadFeedsIntoConfiguration(); // Load feeds into configuration
54
- await this.loadClientMCPSettings(); // Load MCP settings for each client
51
+ try {
52
+ const config = JSON.parse(await fs.readFile(this.configPath, 'utf8'));
53
+ this.configuration = config;
54
+ }
55
+ catch (error) {
56
+ if (error.code !== 'ENOENT') {
57
+ throw error;
58
+ }
59
+ // File doesn't exist, use default empty configuration
60
+ await this.saveConfiguration();
61
+ }
62
+ // Always load feeds and client settings, whether file existed or not
63
+ await this.loadFeedsIntoConfiguration();
64
+ await this.loadClientMCPSettings();
55
65
  }
56
66
  catch (error) {
57
- if (error.code !== 'ENOENT') {
58
- throw error;
59
- }
60
- // File doesn't exist, use default empty configuration
61
- await this.saveConfiguration();
67
+ Logger.error('Error during initialization', error);
68
+ throw error;
62
69
  }
63
70
  });
64
71
  }
@@ -256,7 +263,7 @@ export class ConfigurationProvider {
256
263
  });
257
264
  }
258
265
  Logger.debug('Updating local feeds...');
259
- // await fs.rm(LOCAL_FEEDS_DIR, { recursive: true, force: true });
266
+ await fs.rm(LOCAL_FEEDS_DIR, { recursive: true, force: true });
260
267
  const sourceFeedsDir = path.join(this.tempDir, GITHUB_REPO.feedsPath);
261
268
  try {
262
269
  await fs.access(sourceFeedsDir);
@@ -0,0 +1,98 @@
1
+ /* Server item container */
2
+ .server-item {
3
+ cursor: pointer;
4
+ position: relative;
5
+ transition: all 0.2s ease;
6
+ }
7
+
8
+ .server-item-content {
9
+ border: 1px solid #e5e7eb;
10
+ border-radius: 0.5rem;
11
+ padding: 1rem;
12
+ margin-bottom: 1rem;
13
+ background-color: #ffffff;
14
+ transition: all 0.2s ease;
15
+ position: relative;
16
+ display: flex;
17
+ justify-content: space-between;
18
+ align-items: bottom; /* Center items vertically */
19
+ }
20
+
21
+ .server-item:hover .server-item-content {
22
+ border-color: #3b82f6;
23
+ box-shadow: 0 2px 4px rgba(59, 130, 246, 0.1);
24
+ transform: translateY(-1px);
25
+ }
26
+
27
+ /* Details widget */
28
+ .details-widget {
29
+ max-height: 0;
30
+ overflow: hidden;
31
+ transition: max-height 0.3s ease-out;
32
+ background-color: #f8fafc;
33
+ border-radius: 0 0 0.5rem 0.5rem;
34
+ margin-top: -1rem;
35
+ margin-bottom: 1rem;
36
+ border: 1px solid #e5e7eb;
37
+ border-top: none;
38
+ }
39
+
40
+ .details-widget.expanded {
41
+ max-height: 500px; /* Adjust based on content */
42
+ border-color: #3b82f6;
43
+ }
44
+
45
+ .details-widget-content {
46
+ padding: 1rem;
47
+ }
48
+
49
+ .description-text {
50
+ color: #4b5563;
51
+ line-height: 1.5;
52
+ font-size: 0.875rem;
53
+ }
54
+
55
+ /* Expand/collapse animation */
56
+ .server-item-content.expanded {
57
+ border-bottom-left-radius: 0;
58
+ border-bottom-right-radius: 0;
59
+ border-color: #3b82f6;
60
+ }
61
+
62
+ /* Server item content layout */
63
+ .server-item-info {
64
+ flex: 1;
65
+ padding-right: 1rem;
66
+ min-width: 0; /* Prevent content from overflowing */
67
+ }
68
+
69
+ /* Install/Uninstall buttons positioning */
70
+ .action-buttons {
71
+ flex-shrink: 0;
72
+ display: flex;
73
+ align-items: center;
74
+ margin-left: 1rem; /* Add some space between content and button */
75
+ }
76
+
77
+ /* Ensure buttons stay in place on hover */
78
+ .server-item:hover .action-buttons {
79
+ position: relative;
80
+ z-index: 2;
81
+ }
82
+
83
+ /* Button styles */
84
+ .action-buttons button {
85
+ white-space: nowrap;
86
+ padding: 0.5rem 1rem; /* Slightly larger padding for better visibility */
87
+ min-width: 80px; /* Ensure consistent button width */
88
+ text-align: center;
89
+ }
90
+
91
+ /* Status badges layout */
92
+ .server-item-info .flex-wrap {
93
+ margin: -0.25rem; /* Negative margin to offset badge spacing */
94
+ }
95
+
96
+ .server-item-info .flex-wrap > * {
97
+ margin: 0.25rem; /* Even spacing between badges */
98
+ }
@@ -0,0 +1,48 @@
1
+ export class DetailsWidget {
2
+ constructor(container) {
3
+ this.container = container;
4
+ this.isExpanded = false;
5
+ this.init();
6
+ }
7
+
8
+ init() {
9
+ // Create details widget elements
10
+ this.widgetElement = document.createElement('div');
11
+ this.widgetElement.className = 'details-widget';
12
+ this.contentElement = document.createElement('div');
13
+ this.contentElement.className = 'details-widget-content';
14
+ this.widgetElement.appendChild(this.contentElement);
15
+ this.container.appendChild(this.widgetElement);
16
+ }
17
+
18
+ setContent(description) {
19
+ this.contentElement.innerHTML = `
20
+ <div class="description-text">
21
+ ${description || 'No description available.'}
22
+ </div>
23
+ `;
24
+ }
25
+
26
+ toggle() {
27
+ this.isExpanded = !this.isExpanded;
28
+ if (this.isExpanded) {
29
+ this.expand();
30
+ } else {
31
+ this.collapse();
32
+ }
33
+ }
34
+
35
+ expand() {
36
+ this.widgetElement.classList.add('expanded');
37
+ this.container.querySelector('.server-item-content').classList.add('expanded');
38
+ }
39
+
40
+ collapse() {
41
+ this.widgetElement.classList.remove('expanded');
42
+ this.container.querySelector('.server-item-content').classList.remove('expanded');
43
+ }
44
+
45
+ isVisible() {
46
+ return this.isExpanded;
47
+ }
48
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imcp",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "Node.js SDK for Model Context Protocol (MCP)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -133,24 +133,26 @@ export class ConfigurationLoader {
133
133
  * Synchronizes server categories with feeds
134
134
  */
135
135
  private static async syncServerCategoriesWithFeeds(configuration: MCPConfiguration): Promise<MCPConfiguration> {
136
- configuration.localServerCategories = configuration.localServerCategories.map(server => {
137
- if (configuration.feeds[server.name]) {
136
+ // Filter out categories that don't have corresponding feeds and update existing ones
137
+ configuration.localServerCategories = configuration.localServerCategories
138
+ .filter(server => configuration.feeds[server.name])
139
+ .map(server => {
138
140
  server.feedConfiguration = configuration.feeds[server.name];
139
- }
140
141
 
141
- if (
142
- !server.installationStatus ||
143
- !server.installationStatus.requirementsStatus ||
144
- Object.keys(server.installationStatus.requirementsStatus).length === 0 ||
145
- !server.installationStatus.serversStatus ||
146
- Object.keys(server.installationStatus.serversStatus).length < Object.keys(server.feedConfiguration?.mcpServers || []).length
147
- ) {
148
- server.installationStatus = ConfigurationLoader.initializeInstallationStatus(server.feedConfiguration);
149
- }
142
+ if (
143
+ !server.installationStatus ||
144
+ !server.installationStatus.requirementsStatus ||
145
+ Object.keys(server.installationStatus.requirementsStatus).length === 0 ||
146
+ !server.installationStatus.serversStatus ||
147
+ Object.keys(server.installationStatus.serversStatus).length < Object.keys(server.feedConfiguration?.mcpServers || []).length
148
+ ) {
149
+ server.installationStatus = ConfigurationLoader.initializeInstallationStatus(server.feedConfiguration);
150
+ }
150
151
 
151
- return server;
152
- });
152
+ return server;
153
+ });
153
154
 
155
+ // Add new categories for feeds that don't have a corresponding category
154
156
  const existingServerNames = new Set(configuration.localServerCategories.map(category => category.name));
155
157
 
156
158
  for (const [feedName, feedConfig] of Object.entries(configuration.feeds)) {
@@ -63,16 +63,23 @@ export class ConfigurationProvider {
63
63
  await fs.mkdir(configDir, { recursive: true });
64
64
 
65
65
  try {
66
- const config = JSON.parse(await fs.readFile(this.configPath, 'utf8'));
67
- this.configuration = config;
68
- await this.loadFeedsIntoConfiguration(); // Load feeds into configuration
69
- await this.loadClientMCPSettings(); // Load MCP settings for each client
70
- } catch (error) {
71
- if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
72
- throw error;
66
+ try {
67
+ const config = JSON.parse(await fs.readFile(this.configPath, 'utf8'));
68
+ this.configuration = config;
69
+ } catch (error) {
70
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {
71
+ throw error;
72
+ }
73
+ // File doesn't exist, use default empty configuration
74
+ await this.saveConfiguration();
73
75
  }
74
- // File doesn't exist, use default empty configuration
75
- await this.saveConfiguration();
76
+
77
+ // Always load feeds and client settings, whether file existed or not
78
+ await this.loadFeedsIntoConfiguration();
79
+ await this.loadClientMCPSettings();
80
+ } catch (error) {
81
+ Logger.error('Error during initialization', error);
82
+ throw error;
76
83
  }
77
84
  });
78
85
  }
@@ -314,7 +321,7 @@ export class ConfigurationProvider {
314
321
  }
315
322
 
316
323
  Logger.debug('Updating local feeds...');
317
- // await fs.rm(LOCAL_FEEDS_DIR, { recursive: true, force: true });
324
+ await fs.rm(LOCAL_FEEDS_DIR, { recursive: true, force: true });
318
325
  const sourceFeedsDir = path.join(this.tempDir, GITHUB_REPO.feedsPath);
319
326
 
320
327
  try {