imcp 0.0.13 → 0.0.14

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 (44) hide show
  1. package/dist/core/installers/clients/ClientInstaller.js +58 -40
  2. package/dist/core/onboard/FeedOnboardService.d.ts +35 -0
  3. package/dist/core/onboard/FeedOnboardService.js +137 -0
  4. package/dist/core/types.d.ts +2 -1
  5. package/dist/core/validators/FeedValidator.d.ts +13 -0
  6. package/dist/core/validators/FeedValidator.js +27 -0
  7. package/dist/web/contract/serverContract.d.ts +64 -0
  8. package/dist/web/contract/serverContract.js +2 -0
  9. package/dist/web/public/css/onboard.css +44 -0
  10. package/dist/web/public/index.html +17 -13
  11. package/dist/web/public/js/modal/index.js +58 -0
  12. package/dist/web/public/js/modal/installHandler.js +227 -0
  13. package/dist/web/public/js/modal/installModal.js +163 -0
  14. package/dist/web/public/js/modal/installation.js +281 -0
  15. package/dist/web/public/js/modal/loadingModal.js +52 -0
  16. package/dist/web/public/js/modal/loadingUI.js +74 -0
  17. package/dist/web/public/js/modal/messageQueue.js +112 -0
  18. package/dist/web/public/js/modal/modalSetup.js +512 -0
  19. package/dist/web/public/js/modal/modalUI.js +214 -0
  20. package/dist/web/public/js/modal/modalUtils.js +49 -0
  21. package/dist/web/public/js/modal/version.js +20 -0
  22. package/dist/web/public/js/modal/versionUtils.js +20 -0
  23. package/dist/web/public/js/modal.js +25 -1041
  24. package/dist/web/public/js/onboard/formProcessor.js +309 -0
  25. package/dist/web/public/js/onboard/index.js +131 -0
  26. package/dist/web/public/js/onboard/state.js +32 -0
  27. package/dist/web/public/js/onboard/templates.js +375 -0
  28. package/dist/web/public/js/onboard/uiHandlers.js +196 -0
  29. package/dist/web/public/js/serverCategoryDetails.js +43 -17
  30. package/dist/web/public/onboard.html +150 -0
  31. package/package.json +1 -1
  32. package/src/core/installers/clients/ClientInstaller.ts +66 -49
  33. package/src/core/types.ts +2 -1
  34. package/src/web/public/index.html +17 -13
  35. package/src/web/public/js/modal/index.js +58 -0
  36. package/src/web/public/js/modal/installModal.js +163 -0
  37. package/src/web/public/js/modal/installation.js +281 -0
  38. package/src/web/public/js/modal/loadingModal.js +52 -0
  39. package/src/web/public/js/modal/messageQueue.js +112 -0
  40. package/src/web/public/js/modal/modalSetup.js +512 -0
  41. package/src/web/public/js/modal/modalUtils.js +49 -0
  42. package/src/web/public/js/modal/versionUtils.js +20 -0
  43. package/src/web/public/js/modal.js +25 -1041
  44. package/src/web/public/js/serverCategoryDetails.js +43 -17
@@ -6,6 +6,8 @@ import { DetailsWidget } from './detailsWidget.js';
6
6
  const REFRESH_INTERVAL = 2000; // 2 seconds
7
7
  let refreshTimer = null;
8
8
  let activeDetailsWidget = null;
9
+ const MAX_RETRIES = 3;
10
+ const RETRY_DELAY = 1000;
9
11
 
10
12
  // Start refresh timer for installation status
11
13
  function startRefreshTimer(serverName) {
@@ -37,16 +39,28 @@ function startRefreshTimer(serverName) {
37
39
  }, REFRESH_INTERVAL);
38
40
  }
39
41
 
40
- // Show server details
41
- async function showServerDetails(serverName) {
42
+ // Show server details with retry mechanism
43
+ async function showServerDetails(serverName, retryCount = 0) {
42
44
  console.log("Showing details for:", serverName);
43
45
  try {
44
46
  localStorage.setItem('lastSelectedCategory', serverName);
47
+
48
+ // If server data is not available, attempt to fetch it
49
+ if (allServerCategoriesData.length === 0) {
50
+ await fetchServerCategories();
51
+ }
52
+
45
53
  const server = allServerCategoriesData.find(s => s.name === serverName);
46
54
  const detailsDiv = document.getElementById('serverCategoryDetails');
47
55
 
48
56
  if (!server) {
49
- throw new Error('Server data not found');
57
+ if (retryCount < MAX_RETRIES) {
58
+ console.log(`Server data not found, retrying (${retryCount + 1}/${MAX_RETRIES})...`);
59
+ await new Promise(resolve => setTimeout(resolve, RETRY_DELAY));
60
+ await fetchServerCategories(); // Refresh the data
61
+ return showServerDetails(serverName, retryCount + 1);
62
+ }
63
+ throw new Error('Server data not found after retries');
50
64
  }
51
65
 
52
66
  detailsDiv.innerHTML = `
@@ -168,12 +182,24 @@ async function renderServersList(serverCategory) {
168
182
  <div class="server-item-header">
169
183
  <div class="flex items-center">
170
184
  <h5 class="font-semibold text-gray-800">${mcpServer.displayName || mcpServer.name}</h5>
171
- ${mcpServer.repository || serverCategory.feedConfiguration?.repository ? `
172
- <a href="${mcpServer.repository || serverCategory.feedConfiguration?.repository}" target="_blank" class="ml-2 text-blue-600 hover:text-blue-800">
173
- <svg class="w-5 h-5 shadow-md rounded-full p-1 hover:shadow-lg transition-shadow duration-200" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
174
- <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"/>
175
- </svg>
176
- </a>` : ''}
185
+ ${mcpServer.repository || serverCategory.feedConfiguration?.repository ? (() => {
186
+ const repoUrl = mcpServer.repository || serverCategory.feedConfiguration?.repository;
187
+ const isGithub = repoUrl.toLowerCase().includes('github.com');
188
+ return `
189
+ <a href="${repoUrl}" target="_blank" class="ml-2 flex items-center">
190
+ <span class="text-xs px-2 py-1 bg-gray-100 rounded-md flex items-center text-gray-700 hover:bg-gray-200 transition-colors duration-200">
191
+ ${isGithub ? `
192
+ <svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
193
+ <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"/>
194
+ </svg>
195
+ GitHub` : `
196
+ <svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
197
+ <path d="M21.721 12.752a9.711 9.711 0 00-.945-5.003 1.743 1.743 0 01-1.339-1.647c0-.522.236-1.01.62-1.341a9.707 9.707 0 00-3.62-2.087 1.744 1.744 0 01-2.113-1.334A9.721 9.721 0 0012 1.016 9.721 9.721 0 009.676 1.3 1.744 1.744 0 017.562 2.634a9.707 9.707 0 00-3.62 2.087 1.744 1.744 0 00-.048 2.32 9.711 9.711 0 00-.945 5.003 9.712 9.712 0 00.945 5.003 1.744 1.744 0 01.048 2.32 9.707 9.707 0 003.62 2.087 1.744 1.744 0 012.114 1.334A9.721 9.721 0 0012 22.982a9.721 9.721 0 002.324-.284 1.744 1.744 0 012.114-1.334 9.707 9.707 0 003.62-2.087 1.744 1.744 0 01.048-2.32 9.711 9.711 0 00.945-5.003z"/>
198
+ </svg>
199
+ Website`}
200
+ </span>
201
+ </a>`
202
+ })() : ''}
177
203
  </div>
178
204
  <p class="text-sm text-gray-600 mb-1">${mcpServer.description || 'No description'}</p>
179
205
  </div>
@@ -181,20 +207,20 @@ async function renderServersList(serverCategory) {
181
207
  <span class="text-xs font-semibold mb-2">Client Status:</span>
182
208
  <div class="flex flex-wrap gap-2">
183
209
  ${availableTargets.map(client => {
184
- const status = (serverCategory.installationStatus?.serversStatus[mcpServer.name]?.installedStatus || {})[client];
185
- const isInstalled = status?.status === 'completed';
186
- return `
210
+ const status = (serverCategory.installationStatus?.serversStatus[mcpServer.name]?.installedStatus || {})[client];
211
+ const isInstalled = status?.status === 'completed';
212
+ return `
187
213
  <span class="text-xs flex items-center ${isInstalled ? 'text-green-600 bg-green-50' : 'text-gray-600 bg-gray-50'} px-3 py-1 rounded-full shadow">
188
214
  <svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
189
215
  ${isInstalled
190
- ? '<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>'
191
- : '<path d="M7 3.5A1.5 1.5 0 018.5 2h3.879a1.5 1.5 0 011.06.44l3.122 3.12A1.5 1.5 0 0117 6.622V12.5a1.5 1.5 0 01-1.5 1.5h-1v-3.379a1.5 1.5 0 00-.44-1.06L10.94 6.44A1.5 1.5 0 009.879 6H7V3.5z M6 6h2.879A1.5 1.5 0 0110 7.5v1.379a1.5 1.5 0 01-.44 1.06L6.44 13.06A1.5 1.5 0 015.379 13H4.5A1.5 1.5 0 013 11.5V7.5A1.5 1.5 0 014.5 6H6z"></path>'
192
- }
216
+ ? '<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>'
217
+ : '<path d="M7 3.5A1.5 1.5 0 018.5 2h3.879a1.5 1.5 0 011.06.44l3.122 3.12A1.5 1.5 0 0117 6.622V12.5a1.5 1.5 0 01-1.5 1.5h-1v-3.379a1.5 1.5 0 00-.44-1.06L10.94 6.44A1.5 1.5 0 009.879 6H7V3.5z M6 6h2.879A1.5 1.5 0 0110 7.5v1.379a1.5 1.5 0 01-.44 1.06L6.44 13.06A1.5 1.5 0 015.379 13H4.5A1.5 1.5 0 013 11.5V7.5A1.5 1.5 0 014.5 6H6z"></path>'
218
+ }
193
219
  </svg>
194
220
  ${client}
195
221
  </span>
196
222
  `;
197
- }).join('')}
223
+ }).join('')}
198
224
  </div>
199
225
  </div>
200
226
  <div class="action-buttons">
@@ -271,4 +297,4 @@ window.showServerDetails = async function (serverName) {
271
297
  }
272
298
  };
273
299
 
274
- export { showServerDetails };
300
+ export { showServerDetails };
@@ -0,0 +1,150 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Onboard MCP Category - IMCP</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link href="https://unpkg.com/boxicons@2.1.4/css/boxicons.min.css" rel="stylesheet">
9
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
10
+ <link rel="stylesheet" href="styles.css">
11
+ <link rel="stylesheet" href="css/onboard.css">
12
+ <link rel="stylesheet" href="css/modal.css">
13
+ <link rel="stylesheet" href="css/notifications.css">
14
+ </head>
15
+ <body class="bg-gray-50 min-h-screen">
16
+ <div class="container mx-auto px-4 py-6">
17
+ <div class="flex items-center justify-between mb-8">
18
+ <h1 class="text-3xl font-bold text-gray-900 flex items-center">
19
+ <i class='bx bx-server mr-3 text-blue-600'></i>
20
+ Onboard MCP Category
21
+ </h1>
22
+ <a href="index.html" class="text-gray-600 hover:text-gray-900 flex items-center">
23
+ <i class='bx bx-arrow-back mr-2'></i>
24
+ Back to Servers
25
+ </a>
26
+ </div>
27
+
28
+ <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-8 max-w-4xl mx-auto">
29
+ <!-- Tab Navigation -->
30
+ <div class="mb-6 border-b border-gray-200">
31
+ <nav class="flex space-x-8" aria-label="Tabs">
32
+ <button id="tab-create-category" class="py-2 px-4 text-blue-600 border-b-2 border-blue-600 font-semibold focus:outline-none" type="button">
33
+ Create New Server Category
34
+ </button>
35
+ <button id="tab-create-server" class="py-2 px-4 text-gray-600 border-b-2 border-transparent hover:text-blue-600 hover:border-blue-600 font-semibold focus:outline-none" type="button">
36
+ Create New Server in Existing Category
37
+ </button>
38
+ </nav>
39
+ </div>
40
+ <!-- Tab Panels -->
41
+ <div id="panel-create-category">
42
+ <form id="onboardForm" class="space-y-8">
43
+ <!-- Basic Information -->
44
+ <div class="space-y-4">
45
+ <h2 class="text-xl font-semibold text-gray-900 flex items-center mb-4">
46
+ <i class='bx bx-info-circle mr-2 text-blue-600'></i>
47
+ Basic Information
48
+ </h2>
49
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
50
+ <div>
51
+ <label class="block text-sm font-medium text-gray-700 mb-1">Category Name*</label>
52
+ <input type="text" name="name" required
53
+ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
54
+ placeholder="e.g., ai-coder-tools">
55
+ </div>
56
+ <div>
57
+ <label class="block text-sm font-medium text-gray-700 mb-1">Display Name*</label>
58
+ <input type="text" name="displayName" required
59
+ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
60
+ placeholder="e.g., Coder Tools">
61
+ </div>
62
+ <div class="md:col-span-2">
63
+ <label class="block text-sm font-medium text-gray-700 mb-1">Description</label>
64
+ <textarea name="description" rows="3"
65
+ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
66
+ placeholder="Describe the purpose and capabilities of this server category"></textarea>
67
+ </div>
68
+ <div class="md:col-span-2">
69
+ <label class="block text-sm font-medium text-gray-700 mb-1">Repository URL</label>
70
+ <input type="url" name="repository"
71
+ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
72
+ placeholder="e.g., https://github.com/organization/repository">
73
+ </div>
74
+ </div>
75
+ </div>
76
+ <!-- MCP Servers (with requirements merged in) -->
77
+ <div class="space-y-4">
78
+ <h2 class="text-xl font-semibold text-gray-900 flex items-center mb-4">
79
+ <i class='bx bx-server mr-2 text-blue-600'></i>
80
+ MCP Servers (Requirements managed per server)
81
+ </h2>
82
+ <div id="serversList" class="space-y-6">
83
+ <!-- Server configurations will be added here dynamically -->
84
+ </div>
85
+ <button type="button" onclick="addServer()"
86
+ class="px-4 py-2 border border-gray-300 rounded-lg text-gray-600 hover:bg-gray-50 flex items-center">
87
+ <i class='bx bx-plus mr-2'></i>
88
+ Add Server
89
+ </button>
90
+ </div>
91
+ <div class="flex justify-end space-x-4 pt-6 border-t">
92
+ <button type="button" onclick="window.location.href='index.html'"
93
+ class="px-6 py-2.5 border border-gray-300 rounded-lg text-gray-600 hover:bg-gray-50">
94
+ Cancel
95
+ </button>
96
+ <button type="submit"
97
+ class="px-6 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 flex items-center">
98
+ <i class='bx bx-save mr-2'></i>
99
+ Save Category
100
+ </button>
101
+ </div>
102
+ </form>
103
+ </div>
104
+ <div id="panel-create-server" class="hidden">
105
+ <form id="onboardServerForm" class="space-y-8">
106
+ <!-- Select Existing Category -->
107
+ <div class="space-y-4">
108
+ <h2 class="text-xl font-semibold text-gray-900 flex items-center mb-4">
109
+ <i class='bx bx-category mr-2 text-blue-600'></i>
110
+ Select Server Category
111
+ </h2>
112
+ <select id="existingCategorySelect" name="category" required
113
+ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
114
+ <option value="">Loading...</option>
115
+ </select>
116
+ </div>
117
+ <!-- MCP Server Dropdown -->
118
+ <div class="space-y-4">
119
+ <h2 class="text-xl font-semibold text-gray-900 flex items-center mb-4">
120
+ <i class='bx bx-server mr-2 text-blue-600'></i>
121
+ MCP Server
122
+ </h2>
123
+ <select id="existingServerSelect" name="server" required
124
+ class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
125
+ <option value="">Select MCP Server</option>
126
+ <option value="__create_new__">Create New</option>
127
+ </select>
128
+ </div>
129
+ <!-- MCP Server Details (readonly or editable) -->
130
+ <div id="serverDetailsContainer">
131
+ <!-- Server details will be rendered here -->
132
+ </div>
133
+ <div class="flex justify-end space-x-4 pt-6 border-t">
134
+ <button type="button" onclick="window.location.href='index.html'"
135
+ class="px-6 py-2.5 border border-gray-300 rounded-lg text-gray-600 hover:bg-gray-50">
136
+ Cancel
137
+ </button>
138
+ <button type="submit"
139
+ class="px-6 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 flex items-center">
140
+ <i class='bx bx-save mr-2'></i>
141
+ Save Server
142
+ </button>
143
+ </div>
144
+ </form>
145
+ </div>
146
+ </div>
147
+
148
+ <script src="js/onboard/index.js" type="module"></script>
149
+ </body>
150
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imcp",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "Node.js SDK for Model Context Protocol (MCP)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -373,6 +373,7 @@ export class ClientInstaller {
373
373
 
374
374
  // Clone the base installation configuration to avoid modifying the original serverConfig
375
375
  const installConfig = JSON.parse(JSON.stringify(serverConfig.installation));
376
+ installConfig.mode = serverConfig.mode
376
377
  const pythonEnv = options.settings?.pythonEnv;
377
378
  let pythonDir: string | null = null;
378
379
 
@@ -606,46 +607,54 @@ export class ClientInstaller {
606
607
  settings.mcpServers = {};
607
608
  }
608
609
 
609
- // Special handling for Windows when command is npx for Cline and MSROO clients
610
- // Use a copy to avoid modifying the passed installConfig directly if needed elsewhere
611
- const serverConfigForClient = { ...installConfig };
612
- if (process.platform === 'win32' &&
613
- serverConfigForClient.command === 'npx' &&
614
- (clientName === 'Cline' || clientName === 'MSRooCode' || clientName === 'MSROO')) {
615
- // Update command to cmd
616
- serverConfigForClient.command = 'cmd';
617
-
618
- // Add /c and npx at the beginning of args
619
- serverConfigForClient.args = ['/c', 'npx', ...serverConfigForClient.args];
620
-
621
- // Add APPDATA environment variable pointing to npm directory
622
- if (!serverConfigForClient.env) {
623
- serverConfigForClient.env = {};
610
+ if (installConfig.mode === 'stdio') {
611
+ // Special handling for Windows when command is npx for Cline and MSROO clients
612
+ // Use a copy to avoid modifying the passed installConfig directly if needed elsewhere
613
+ const serverConfigForClient = { ...installConfig };
614
+ if (process.platform === 'win32' &&
615
+ serverConfigForClient.command === 'npx' &&
616
+ (clientName === 'Cline' || clientName === 'MSRooCode' || clientName === 'MSROO')) {
617
+ // Update command to cmd
618
+ serverConfigForClient.command = 'cmd';
619
+
620
+ // Add /c and npx at the beginning of args
621
+ serverConfigForClient.args = ['/c', 'npx', ...serverConfigForClient.args];
622
+
623
+ // Add APPDATA environment variable pointing to npm directory
624
+ if (!serverConfigForClient.env) {
625
+ serverConfigForClient.env = {};
626
+ }
627
+
628
+ // Dynamically get npm path and set APPDATA to it
629
+ const npmPath = await this.getNpmPath();
630
+ serverConfigForClient.env['APPDATA'] = npmPath;
631
+ Logger.debug(`Windows npx fix: command=${serverConfigForClient.command}, args=${serverConfigForClient.args.join(' ')}, env=${JSON.stringify(serverConfigForClient.env)}`);
632
+ }
633
+ // Convert backslashes to forward slashes in args paths
634
+ if (serverConfigForClient.args) {
635
+ serverConfigForClient.args = serverConfigForClient.args.map((arg: string) =>
636
+ typeof arg === 'string' ? arg.replace(/\\/g, '/') : arg
637
+ );
624
638
  }
625
639
 
626
- // Dynamically get npm path and set APPDATA to it
627
- const npmPath = await this.getNpmPath();
628
- serverConfigForClient.env['APPDATA'] = npmPath;
629
- Logger.debug(`Windows npx fix: command=${serverConfigForClient.command}, args=${serverConfigForClient.args.join(' ')}, env=${JSON.stringify(serverConfigForClient.env)}`);
630
- }
631
- // Convert backslashes to forward slashes in args paths
632
- if (serverConfigForClient.args) {
633
- serverConfigForClient.args = serverConfigForClient.args.map((arg: string) =>
634
- typeof arg === 'string' ? arg.replace(/\\/g, '/') : arg
635
- );
640
+ // Add or update the server configuration
641
+ settings.mcpServers[serverName] = {
642
+ command: serverConfigForClient.command,
643
+ args: serverConfigForClient.args,
644
+ env: serverConfigForClient.env,
645
+ autoApprove: [],
646
+ disabled: false,
647
+ alwaysAllow: []
648
+ };
649
+ Logger.debug(`Updating ${settingPath} for ${serverName}: ${JSON.stringify(settings.mcpServers[serverName])}`);
650
+ } else if (installConfig.mode === 'sse') {
651
+ // Handle SSE mode for Cline and MSRoo clients
652
+ settings.mcpServers[serverName] = {
653
+ type: 'sse',
654
+ url: installConfig.url
655
+ };
636
656
  }
637
657
 
638
- // Add or update the server configuration
639
- settings.mcpServers[serverName] = {
640
- command: serverConfigForClient.command,
641
- args: serverConfigForClient.args,
642
- env: serverConfigForClient.env,
643
- autoApprove: [],
644
- disabled: false,
645
- alwaysAllow: []
646
- };
647
- Logger.debug(`Updating ${settingPath} for ${serverName}: ${JSON.stringify(settings.mcpServers[serverName])}`);
648
-
649
658
  // Write the updated settings back to the file
650
659
  await writeJsonFile(settingPath, settings);
651
660
  }
@@ -673,20 +682,28 @@ export class ClientInstaller {
673
682
  // Use a copy to avoid modifying the passed installConfig directly
674
683
  const serverConfigForClient = { ...installConfig };
675
684
 
676
- // Convert backslashes to forward slashes in args paths
677
- if (serverConfigForClient.args) {
678
- serverConfigForClient.args = serverConfigForClient.args.map((arg: string) =>
679
- typeof arg === 'string' ? arg.replace(/\\/g, '/') : arg
680
- );
681
- }
685
+ if (installConfig.mode === 'stdio') {
686
+ if (serverConfigForClient.args) {
687
+ serverConfigForClient.args = serverConfigForClient.args.map((arg: string) =>
688
+ typeof arg === 'string' ? arg.replace(/\\/g, '/') : arg
689
+ );
690
+ }
682
691
 
683
- // Add or update the server configuration
684
- settings.mcp.servers[serverName] = {
685
- command: serverConfigForClient.command,
686
- args: serverConfigForClient.args,
687
- env: serverConfigForClient.env
688
- };
689
- Logger.debug(`Updating ${settingPath} for ${serverName}: ${JSON.stringify(settings.mcp.servers[serverName])}`);
692
+ // Add or update the server configuration
693
+ settings.mcp.servers[serverName] = {
694
+ command: serverConfigForClient.command,
695
+ args: serverConfigForClient.args,
696
+ env: serverConfigForClient.env
697
+ };
698
+ Logger.debug(`Updating ${settingPath} for ${serverName}: ${JSON.stringify(settings.mcp.servers[serverName])}`);
699
+ }
700
+ else if (installConfig.mode === 'sse') {
701
+ // Handle SSE mode for Github Copilot
702
+ settings.mcp.servers[serverName] = {
703
+ type: 'sse',
704
+ url: installConfig.url
705
+ };
706
+ }
690
707
 
691
708
  // Write the updated settings back to the file
692
709
  await writeJsonFile(settingPath, settings);
package/src/core/types.ts CHANGED
@@ -99,6 +99,7 @@ export interface InstallationConfig {
99
99
  command: string;
100
100
  args: string[]; // Can use ${packageSource} as template variable for installation path
101
101
  env?: Record<string, EnvVariableConfig>; // Note the colon in property name
102
+ url?: string; // URL for sse mode
102
103
  }
103
104
 
104
105
  export interface DependencyConfig {
@@ -115,7 +116,7 @@ export interface DependencyConfig {
115
116
  export interface McpConfig {
116
117
  name: string;
117
118
  description: string;
118
- mode: 'stdio' | 'http'; // Currently only stdio mode is supported in ai-coder-tools
119
+ mode: 'stdio' | 'sse'; // Currently only stdio mode is supported in ai-coder-tools
119
120
  dependencies?: DependencyConfig;
120
121
  schemas?: string; // Path to the schema file
121
122
  repository?: string; // Repository URL for the server
@@ -162,19 +162,23 @@
162
162
  setupSearch();
163
163
  setupModalOutsideClick();
164
164
 
165
- // Check URL parameters for category
166
- const urlParams = new URLSearchParams(window.location.search);
167
- const categoryParam = urlParams.get('category');
168
-
169
- // If we have a category parameter or last selected category
170
- const lastSelected = categoryParam || localStorage.getItem('lastSelectedCategory');
171
-
172
- // First fetch categories
173
- await fetchServerCategories();
174
-
175
- // Then show the selected category if it exists
176
- if (lastSelected) {
177
- showServerDetails(lastSelected);
165
+ try {
166
+ // First fetch categories and wait for completion
167
+ await fetchServerCategories();
168
+
169
+ // Check URL parameters for category
170
+ const urlParams = new URLSearchParams(window.location.search);
171
+ const categoryParam = urlParams.get('category');
172
+
173
+ // If we have a category parameter or last selected category
174
+ const lastSelected = categoryParam || localStorage.getItem('lastSelectedCategory');
175
+
176
+ // Only show details after data is loaded
177
+ if (lastSelected) {
178
+ await showServerDetails(lastSelected);
179
+ }
180
+ } catch (error) {
181
+ console.error('Error during initialization:', error);
178
182
  }
179
183
  });
180
184
  </script>
@@ -0,0 +1,58 @@
1
+ // Import all modal-related functionality
2
+ import { compareVersions } from './versionUtils.js';
3
+ import { delayedAppendInstallLoadingMessage } from './messageQueue.js';
4
+ import { showInstallLoadingModal, appendInstallLoadingMessage, hideInstallLoadingModal } from './loadingModal.js';
5
+ import { closeModal, setupModalOutsideClick } from './modalUtils.js';
6
+ import { handleBulkClientInstall, uninstallTools } from './installation.js';
7
+ import { showInstallModal } from './installModal.js';
8
+ import {
9
+ setupClientItems,
10
+ setupEnvironmentVariables,
11
+ setupInstallationArguments,
12
+ setupServerRequirements,
13
+ setupFormSubmitHandler
14
+ } from './modalSetup.js';
15
+
16
+ // Export all modal functionality
17
+ export {
18
+ // Version utilities
19
+ compareVersions,
20
+
21
+ // Message queue
22
+ delayedAppendInstallLoadingMessage,
23
+
24
+ // Loading modal
25
+ showInstallLoadingModal,
26
+ appendInstallLoadingMessage,
27
+ hideInstallLoadingModal,
28
+
29
+ // Modal utilities
30
+ closeModal,
31
+ setupModalOutsideClick,
32
+
33
+ // Installation
34
+ handleBulkClientInstall,
35
+ uninstallTools,
36
+
37
+ // Install modal
38
+ showInstallModal,
39
+
40
+ // Modal setup
41
+ setupClientItems,
42
+ setupEnvironmentVariables,
43
+ setupInstallationArguments,
44
+ setupServerRequirements,
45
+ setupFormSubmitHandler
46
+ };
47
+
48
+ // Initialize modal functionality
49
+ document.addEventListener('DOMContentLoaded', () => {
50
+ setupModalOutsideClick();
51
+ });
52
+
53
+ // Make certain functions available globally
54
+ window.showInstallModal = showInstallModal;
55
+ window.showInstallLoadingModal = showInstallLoadingModal;
56
+ window.appendInstallLoadingMessage = appendInstallLoadingMessage;
57
+ window.hideInstallLoadingModal = hideInstallLoadingModal;
58
+ window.uninstallTools = uninstallTools;