imcp 0.0.14 → 0.0.16

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 (136) hide show
  1. package/dist/core/ConfigurationProvider.d.ts +1 -0
  2. package/dist/core/ConfigurationProvider.js +15 -0
  3. package/dist/core/InstallationService.js +2 -7
  4. package/dist/core/MCPManager.d.ts +11 -2
  5. package/dist/core/MCPManager.js +24 -1
  6. package/dist/core/RequirementService.js +2 -8
  7. package/dist/core/installers/clients/BaseClientInstaller.d.ts +51 -0
  8. package/dist/core/installers/clients/BaseClientInstaller.js +160 -0
  9. package/dist/core/installers/clients/ClientInstaller.d.ts +16 -9
  10. package/dist/core/installers/clients/ClientInstaller.js +80 -527
  11. package/dist/core/installers/clients/ClientInstallerFactory.d.ts +20 -0
  12. package/dist/core/installers/clients/ClientInstallerFactory.js +37 -0
  13. package/dist/core/installers/clients/ClineInstaller.d.ts +18 -0
  14. package/dist/core/installers/clients/ClineInstaller.js +124 -0
  15. package/dist/core/installers/clients/GithubCopilotInstaller.d.ts +34 -0
  16. package/dist/core/installers/clients/GithubCopilotInstaller.js +162 -0
  17. package/dist/core/installers/clients/MSRooCodeInstaller.d.ts +15 -0
  18. package/dist/core/installers/clients/MSRooCodeInstaller.js +122 -0
  19. package/dist/core/installers/requirements/BaseInstaller.d.ts +11 -34
  20. package/dist/core/installers/requirements/BaseInstaller.js +5 -116
  21. package/dist/core/installers/requirements/CommandInstaller.d.ts +6 -1
  22. package/dist/core/installers/requirements/CommandInstaller.js +7 -0
  23. package/dist/core/installers/requirements/GeneralInstaller.d.ts +6 -1
  24. package/dist/core/installers/requirements/GeneralInstaller.js +9 -4
  25. package/dist/core/installers/requirements/NpmInstaller.d.ts +46 -7
  26. package/dist/core/installers/requirements/NpmInstaller.js +150 -58
  27. package/dist/core/installers/requirements/PipInstaller.d.ts +9 -0
  28. package/dist/core/installers/requirements/PipInstaller.js +66 -28
  29. package/dist/core/onboard/FeedOnboardService.d.ts +50 -13
  30. package/dist/core/onboard/FeedOnboardService.js +263 -88
  31. package/dist/core/onboard/OnboardProcessor.d.ts +79 -0
  32. package/dist/core/onboard/OnboardProcessor.js +290 -0
  33. package/dist/core/onboard/OnboardStatus.d.ts +49 -0
  34. package/dist/core/onboard/OnboardStatus.js +10 -0
  35. package/dist/core/onboard/OnboardStatusManager.d.ts +57 -0
  36. package/dist/core/onboard/OnboardStatusManager.js +176 -0
  37. package/dist/core/types.d.ts +4 -5
  38. package/dist/core/validators/FeedValidator.d.ts +8 -1
  39. package/dist/core/validators/FeedValidator.js +60 -7
  40. package/dist/core/validators/IServerValidator.d.ts +19 -0
  41. package/dist/core/validators/IServerValidator.js +2 -0
  42. package/dist/core/validators/SSEServerValidator.d.ts +15 -0
  43. package/dist/core/validators/SSEServerValidator.js +39 -0
  44. package/dist/core/validators/ServerValidatorFactory.d.ts +24 -0
  45. package/dist/core/validators/ServerValidatorFactory.js +45 -0
  46. package/dist/core/validators/StdioServerValidator.d.ts +46 -0
  47. package/dist/core/validators/StdioServerValidator.js +229 -0
  48. package/dist/services/InstallRequestValidator.d.ts +1 -1
  49. package/dist/services/ServerService.d.ts +9 -6
  50. package/dist/services/ServerService.js +18 -7
  51. package/dist/utils/adoUtils.d.ts +29 -0
  52. package/dist/utils/adoUtils.js +252 -0
  53. package/dist/utils/clientUtils.d.ts +0 -7
  54. package/dist/utils/clientUtils.js +0 -42
  55. package/dist/utils/githubUtils.d.ts +10 -0
  56. package/dist/utils/githubUtils.js +22 -0
  57. package/dist/utils/macroExpressionUtils.d.ts +38 -0
  58. package/dist/utils/macroExpressionUtils.js +116 -0
  59. package/dist/utils/osUtils.d.ts +4 -20
  60. package/dist/utils/osUtils.js +78 -23
  61. package/dist/web/contract/serverContract.d.ts +3 -1
  62. package/dist/web/public/css/notifications.css +48 -17
  63. package/dist/web/public/css/onboard.css +66 -3
  64. package/dist/web/public/index.html +84 -16
  65. package/dist/web/public/js/api.js +3 -6
  66. package/dist/web/public/js/flights/flights.js +127 -0
  67. package/dist/web/public/js/modal/installation.js +5 -5
  68. package/dist/web/public/js/modal/modalSetup.js +3 -2
  69. package/dist/web/public/js/notifications.js +66 -27
  70. package/dist/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +338 -0
  71. package/dist/web/public/js/onboard/formProcessor.js +810 -255
  72. package/dist/web/public/js/onboard/index.js +328 -85
  73. package/dist/web/public/js/onboard/publishHandler.js +132 -0
  74. package/dist/web/public/js/onboard/state.js +61 -17
  75. package/dist/web/public/js/onboard/templates.js +217 -249
  76. package/dist/web/public/js/onboard/uiHandlers.js +679 -117
  77. package/dist/web/public/js/onboard/validationHandlers.js +378 -0
  78. package/dist/web/public/js/serverCategoryList.js +15 -2
  79. package/dist/web/public/onboard.html +191 -45
  80. package/dist/web/public/styles.css +91 -1
  81. package/dist/web/server.d.ts +0 -10
  82. package/dist/web/server.js +131 -22
  83. package/package.json +2 -2
  84. package/src/core/ConfigurationProvider.ts +15 -0
  85. package/src/core/InstallationService.ts +2 -7
  86. package/src/core/MCPManager.ts +26 -1
  87. package/src/core/RequirementService.ts +2 -9
  88. package/src/core/installers/clients/BaseClientInstaller.ts +196 -0
  89. package/src/core/installers/clients/ClientInstaller.ts +97 -608
  90. package/src/core/installers/clients/ClientInstallerFactory.ts +43 -0
  91. package/src/core/installers/clients/ClineInstaller.ts +135 -0
  92. package/src/core/installers/clients/GithubCopilotInstaller.ts +179 -0
  93. package/src/core/installers/clients/MSRooCodeInstaller.ts +133 -0
  94. package/src/core/installers/requirements/BaseInstaller.ts +13 -136
  95. package/src/core/installers/requirements/CommandInstaller.ts +9 -1
  96. package/src/core/installers/requirements/GeneralInstaller.ts +11 -4
  97. package/src/core/installers/requirements/NpmInstaller.ts +178 -61
  98. package/src/core/installers/requirements/PipInstaller.ts +68 -29
  99. package/src/core/onboard/FeedOnboardService.ts +346 -0
  100. package/src/core/onboard/OnboardProcessor.ts +305 -0
  101. package/src/core/onboard/OnboardStatus.ts +55 -0
  102. package/src/core/onboard/OnboardStatusManager.ts +188 -0
  103. package/src/core/types.ts +4 -5
  104. package/src/core/validators/FeedValidator.ts +79 -0
  105. package/src/core/validators/IServerValidator.ts +21 -0
  106. package/src/core/validators/SSEServerValidator.ts +43 -0
  107. package/src/core/validators/ServerValidatorFactory.ts +51 -0
  108. package/src/core/validators/StdioServerValidator.ts +259 -0
  109. package/src/services/InstallRequestValidator.ts +1 -1
  110. package/src/services/ServerService.ts +22 -7
  111. package/src/utils/adoUtils.ts +291 -0
  112. package/src/utils/clientUtils.ts +0 -44
  113. package/src/utils/githubUtils.ts +24 -0
  114. package/src/utils/macroExpressionUtils.ts +121 -0
  115. package/src/utils/osUtils.ts +89 -24
  116. package/src/web/contract/serverContract.ts +74 -0
  117. package/src/web/public/css/notifications.css +48 -17
  118. package/src/web/public/css/onboard.css +107 -0
  119. package/src/web/public/index.html +84 -16
  120. package/src/web/public/js/api.js +3 -6
  121. package/src/web/public/js/flights/flights.js +127 -0
  122. package/src/web/public/js/modal/installation.js +5 -5
  123. package/src/web/public/js/modal/modalSetup.js +3 -2
  124. package/src/web/public/js/notifications.js +66 -27
  125. package/src/web/public/js/onboard/ONBOARDING_PAGE_DESIGN.md +338 -0
  126. package/src/web/public/js/onboard/formProcessor.js +864 -0
  127. package/src/web/public/js/onboard/index.js +374 -0
  128. package/src/web/public/js/onboard/publishHandler.js +132 -0
  129. package/src/web/public/js/onboard/state.js +76 -0
  130. package/src/web/public/js/onboard/templates.js +343 -0
  131. package/src/web/public/js/onboard/uiHandlers.js +758 -0
  132. package/src/web/public/js/onboard/validationHandlers.js +378 -0
  133. package/src/web/public/js/serverCategoryList.js +15 -2
  134. package/src/web/public/onboard.html +296 -0
  135. package/src/web/public/styles.css +91 -1
  136. package/src/web/server.ts +167 -58
@@ -6,13 +6,45 @@
6
6
  <title>Onboard MCP Category - IMCP</title>
7
7
  <script src="https://cdn.tailwindcss.com"></script>
8
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">
9
+ <!-- Bootstrap CSS is likely not needed if primarily using Tailwind -->
10
+ <!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> -->
10
11
  <link rel="stylesheet" href="styles.css">
11
12
  <link rel="stylesheet" href="css/onboard.css">
13
+ <!-- Highlight.js for JSON syntax highlighting -->
14
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
15
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
12
16
  <link rel="stylesheet" href="css/modal.css">
13
17
  <link rel="stylesheet" href="css/notifications.css">
18
+ <script type="module">
19
+ import flights, { getFlightQueryParameters } from './js/flights/flights.js';
20
+ if (!flights.enableOnboard) {
21
+ // Preserve flight params when redirecting
22
+ window.location.href = `index.html${getFlightQueryParameters()}`;
23
+ }
24
+
25
+ document.addEventListener('DOMContentLoaded', () => {
26
+ const flightQueryString = getFlightQueryParameters();
27
+
28
+ const backToServerLink = document.querySelector('a[href="index.html"]');
29
+ if (backToServerLink) {
30
+ backToServerLink.href = `index.html${flightQueryString}`;
31
+ }
32
+
33
+ // Update cancel buttons in forms
34
+ const cancelButtons = document.querySelectorAll('button[onclick="window.location.href=\'index.html\'"]');
35
+ cancelButtons.forEach(button => {
36
+ button.onclick = () => { window.location.href = `index.html${flightQueryString}`; };
37
+ });
38
+
39
+ const jsonEditorCancelButton = document.querySelector('#jsonEditorActionsContainer button[onclick="window.location.href=\'index.html\'"]');
40
+ if (jsonEditorCancelButton) {
41
+ jsonEditorCancelButton.onclick = () => { window.location.href = `index.html${flightQueryString}`; };
42
+ }
43
+ });
44
+ </script>
14
45
  </head>
15
46
  <body class="bg-gray-50 min-h-screen">
47
+ <div class="alert-container"></div>
16
48
  <div class="container mx-auto px-4 py-6">
17
49
  <div class="flex items-center justify-between mb-8">
18
50
  <h1 class="text-3xl font-bold text-gray-900 flex items-center">
@@ -25,7 +57,7 @@
25
57
  </a>
26
58
  </div>
27
59
 
28
- <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-8 max-w-4xl mx-auto">
60
+ <div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6 max-w-6xl mx-auto">
29
61
  <!-- Tab Navigation -->
30
62
  <div class="mb-6 border-b border-gray-200">
31
63
  <nav class="flex space-x-8" aria-label="Tabs">
@@ -36,115 +68,229 @@
36
68
  Create New Server in Existing Category
37
69
  </button>
38
70
  </nav>
71
+ <!-- View Mode Toggle Switch -->
72
+ <div class="flex justify-end mt-2 mb-4">
73
+ <label for="viewModeToggle" class="flex items-center cursor-pointer">
74
+ <span class="mr-3 text-sm font-medium text-gray-700">Form View</span>
75
+ <div class="relative">
76
+ <input type="checkbox" id="viewModeToggle" class="sr-only peer">
77
+ <div class="w-10 h-6 bg-gray-200 rounded-full peer peer-focus:ring-2 peer-focus:ring-blue-300 peer-checked:bg-blue-600 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all"></div>
78
+ </div>
79
+ <span class="ml-3 text-sm font-medium text-gray-700">JSON View</span>
80
+ </label>
81
+ </div>
39
82
  </div>
40
83
  <!-- Tab Panels -->
41
84
  <div id="panel-create-category">
42
- <form id="onboardForm" class="space-y-8">
85
+ <form id="onboardForm" class="space-y-6">
43
86
  <!-- Basic Information -->
44
87
  <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
88
+ <h2 onclick="toggleSectionContent('basicInformationContent', this.querySelector('.toggle-icon'))" class="text-xl font-semibold text-gray-900 flex items-center justify-between mb-4 cursor-pointer">
89
+ <span class="flex items-center">
90
+ <i class='bx bx-info-circle mr-2 text-blue-600'></i>
91
+ Basic Information
92
+ </span>
93
+ <i class='bx bx-chevron-down toggle-icon text-xl text-gray-500'></i>
48
94
  </h2>
49
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
95
+ <div id="basicInformationContent" class="grid grid-cols-1 md:grid-cols-2 gap-4 p-6 bg-white rounded-lg border border-gray-200 shadow-sm">
50
96
  <div>
51
97
  <label class="block text-sm font-medium text-gray-700 mb-1">Category Name*</label>
52
98
  <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"
99
+ class="w-full px-3 py-1.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
54
100
  placeholder="e.g., ai-coder-tools">
55
101
  </div>
56
102
  <div>
57
103
  <label class="block text-sm font-medium text-gray-700 mb-1">Display Name*</label>
58
104
  <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"
105
+ class="w-full px-3 py-1.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
60
106
  placeholder="e.g., Coder Tools">
61
107
  </div>
62
108
  <div class="md:col-span-2">
63
109
  <label class="block text-sm font-medium text-gray-700 mb-1">Description</label>
64
110
  <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"
111
+ class="w-full px-3 py-1.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
66
112
  placeholder="Describe the purpose and capabilities of this server category"></textarea>
67
113
  </div>
68
114
  <div class="md:col-span-2">
69
115
  <label class="block text-sm font-medium text-gray-700 mb-1">Repository URL</label>
70
116
  <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"
117
+ class="w-full px-3 py-1.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
72
118
  placeholder="e.g., https://github.com/organization/repository">
73
119
  </div>
74
120
  </div>
75
121
  </div>
76
- <!-- MCP Servers (with requirements merged in) -->
122
+ <!-- MCP Servers -->
77
123
  <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 -->
124
+ <div class="flex justify-between items-center mb-4">
125
+ <h2 class="text-xl font-semibold text-gray-900 flex items-center">
126
+ <i class='bx bx-server mr-2 text-blue-600'></i>
127
+ MCP Servers
128
+ </h2>
129
+ <button type="button" onclick="addServer()"
130
+ class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 flex items-center text-sm">
131
+ <i class='bx bx-plus mr-2'></i>
132
+ Add MCP Server
133
+ </button>
134
+ </div>
135
+ <div id="serversList" class="space-y-4">
136
+ <!-- Server configurations will be added here dynamically by serverTemplate -->
84
137
  </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
138
  </div>
91
139
  <div class="flex justify-end space-x-4 pt-6 border-t">
92
140
  <button type="button" onclick="window.location.href='index.html'"
93
141
  class="px-6 py-2.5 border border-gray-300 rounded-lg text-gray-600 hover:bg-gray-50">
94
142
  Cancel
95
143
  </button>
96
- <button type="submit"
144
+ <button type="button" id="validateButtonNewCategory"
145
+ class="px-6 py-2.5 bg-green-500 text-white rounded-lg hover:bg-green-600 flex items-center">
146
+ <i class='bx bx-check-shield mr-2'></i>
147
+ Validate
148
+ </button>
149
+ <button type="submit" id="publishButtonNewCategory"
97
150
  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
151
+ <i class='bx bxs-cloud-upload mr-2'></i>
152
+ Publish
100
153
  </button>
101
154
  </div>
155
+ <!-- Validation Status Panel -->
156
+ <div id="validationStatusPanelNewCategory" class="hidden p-6 bg-gray-50 rounded-lg border border-gray-200">
157
+ <h3 onclick="toggleSectionContent('validationStatusContentNewCategory', this.querySelector('.toggle-icon'))" class="cursor-pointer text-lg font-semibold text-gray-800 mb-3 flex items-center justify-between">
158
+ <span class="flex items-center">
159
+ <i class='bx bx-analyse mr-2 text-blue-600'></i>Validation Status
160
+ </span>
161
+ <i class='bx bx-chevron-down toggle-icon text-xl text-gray-500'></i>
162
+ </h3>
163
+ <div id="validationStatusContentNewCategory" class="text-sm text-gray-700 space-y-2">
164
+ <!-- Validation messages will be displayed here -->
165
+ </div>
166
+ </div>
102
167
  </form>
103
168
  </div>
104
169
  <div id="panel-create-server" class="hidden">
105
- <form id="onboardServerForm" class="space-y-8">
170
+ <form id="onboardServerForm" class="space-y-6">
106
171
  <!-- Select Existing Category -->
107
172
  <div class="space-y-4">
108
173
  <h2 class="text-xl font-semibold text-gray-900 flex items-center mb-4">
109
174
  <i class='bx bx-category mr-2 text-blue-600'></i>
110
175
  Select Server Category
111
176
  </h2>
112
- <select id="existingCategorySelect" name="category" required
177
+ <select id="existingCategorySelect" name="categoryName" required
113
178
  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>
179
+ <option value="">Loading categories...</option>
115
180
  </select>
116
181
  </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
182
+
183
+ <!-- Basic Information (Read-only after category selection) -->
184
+ <div id="existingCategoryBasicInfoContainer" class="hidden space-y-4">
185
+ <h2 onclick="toggleSectionContent('existingCategoryBasicInformationContent', this.querySelector('.toggle-icon'))" class="text-xl font-semibold text-gray-900 flex items-center justify-between mb-4 cursor-pointer">
186
+ <span class="flex items-center">
187
+ <i class='bx bx-info-circle mr-2 text-blue-600'></i>
188
+ Basic Information (Read-only)
189
+ </span>
190
+ <i class='bx bx-chevron-down toggle-icon text-xl text-gray-500'></i>
122
191
  </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>
192
+ <div id="existingCategoryBasicInformationContent" class="grid grid-cols-1 md:grid-cols-2 gap-4 p-6 bg-white rounded-lg border border-gray-200 shadow-sm">
193
+ <div>
194
+ <label class="block text-sm font-medium text-gray-700 mb-1">Category Name</label>
195
+ <input type="text" name="name" readonly class="w-full px-3 py-1.5 border border-gray-300 rounded-lg bg-gray-100 cursor-not-allowed">
196
+ </div>
197
+ <div>
198
+ <label class="block text-sm font-medium text-gray-700 mb-1">Display Name</label>
199
+ <input type="text" name="displayName" readonly class="w-full px-3 py-1.5 border border-gray-300 rounded-lg bg-gray-100 cursor-not-allowed">
200
+ </div>
201
+ <div class="md:col-span-2">
202
+ <label class="block text-sm font-medium text-gray-700 mb-1">Description</label>
203
+ <textarea name="description" rows="3" readonly class="w-full px-3 py-1.5 border border-gray-300 rounded-lg bg-gray-100 cursor-not-allowed"></textarea>
204
+ </div>
205
+ <div class="md:col-span-2">
206
+ <label class="block text-sm font-medium text-gray-700 mb-1">Repository URL</label>
207
+ <input type="url" name="repository" readonly class="w-full px-3 py-1.5 border border-gray-300 rounded-lg bg-gray-100 cursor-not-allowed">
208
+ </div>
209
+ </div>
128
210
  </div>
129
- <!-- MCP Server Details (readonly or editable) -->
130
- <div id="serverDetailsContainer">
131
- <!-- Server details will be rendered here -->
211
+
212
+ <!-- MCP Servers (Existing read-only, new ones editable) -->
213
+ <div id="existingCategoryMcpServersContainer" class="hidden space-y-4">
214
+ <div class="flex justify-between items-center mb-4">
215
+ <h2 class="text-xl font-semibold text-gray-900 flex items-center">
216
+ <i class='bx bx-server mr-2 text-blue-600'></i>
217
+ MCP Servers
218
+ </h2>
219
+ <button type="button" id="addServerToExistingCategoryBtn"
220
+ class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 flex items-center text-sm">
221
+ <i class='bx bx-plus mr-2'></i>
222
+ Add MCP Server
223
+ </button>
224
+ </div>
225
+ <div id="existingCategoryServersList" class="space-y-4">
226
+ <!-- Server configurations will be added here: existing ones read-only, new ones editable -->
227
+ </div>
132
228
  </div>
229
+
230
+ <!-- Action Buttons -->
133
231
  <div class="flex justify-end space-x-4 pt-6 border-t">
134
232
  <button type="button" onclick="window.location.href='index.html'"
135
233
  class="px-6 py-2.5 border border-gray-300 rounded-lg text-gray-600 hover:bg-gray-50">
136
234
  Cancel
137
235
  </button>
138
- <button type="submit"
236
+ <button type="button" id="validateButtonExistingCategory"
237
+ class="px-6 py-2.5 bg-green-500 text-white rounded-lg hover:bg-green-600 flex items-center">
238
+ <i class='bx bx-check-shield mr-2'></i>
239
+ Validate
240
+ </button>
241
+ <button type="submit" id="publishButtonExistingCategory"
139
242
  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
243
+ <i class='bx bxs-cloud-upload mr-2'></i>
244
+ Publish
142
245
  </button>
143
246
  </div>
247
+
248
+ <!-- Validation Status Panel -->
249
+ <div id="validationStatusPanelExistingCategory" class="hidden p-6 bg-gray-50 rounded-lg border border-gray-200">
250
+ <h3 onclick="toggleSectionContent('validationStatusContentExistingCategoryTab', this.querySelector('.toggle-icon'))" class="cursor-pointer text-lg font-semibold text-gray-800 mb-3 flex items-center justify-between">
251
+ <span class="flex items-center">
252
+ <i class='bx bx-analyse mr-2 text-blue-600'></i>Validation Status
253
+ </span>
254
+ <i class='bx bx-chevron-down toggle-icon text-xl text-gray-500'></i>
255
+ </h3>
256
+ <div id="validationStatusContentExistingCategoryTab" class="text-sm text-gray-700 space-y-2">
257
+ <!-- Validation messages will be displayed here -->
258
+ </div>
259
+ </div>
144
260
  </form>
145
261
  </div>
262
+
263
+ <!-- JSON Editor Panel -->
264
+ <div id="panel-json-editor" class="hidden">
265
+ <h2 class="text-xl font-semibold text-gray-900 flex items-center mb-4">
266
+ <i class='bx bx-code-alt mr-2 text-blue-600'></i>
267
+ Edit Configuration as JSON
268
+ </h2>
269
+ <div class="relative">
270
+ <button type="button" onclick="copyJsonToClipboard()" title="Copy JSON to clipboard"
271
+ class="absolute top-2 right-2 z-10 px-3 py-1.5 text-xs bg-gray-200 hover:bg-gray-300 text-gray-700 rounded-md flex items-center">
272
+ <i class='bx bx-copy mr-1'></i> Copy
273
+ </button>
274
+ <textarea id="jsonEditorTextarea" rows="20"
275
+ class="w-full px-3 py-2 font-mono text-sm border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
276
+ placeholder="JSON configuration will appear here..."></textarea>
277
+ </div>
278
+ <div id="jsonEditorActionsContainer" class="flex justify-end space-x-4 pt-6 border-t mt-6">
279
+ <!-- "Apply JSON to Form" button removed -->
280
+ <button type="button" onclick="window.location.href='index.html'"
281
+ class="px-6 py-2.5 border border-gray-300 rounded-lg text-gray-600 hover:bg-gray-50">
282
+ Cancel
283
+ </button>
284
+ <button type="button" id="saveJsonButton"
285
+ class="px-6 py-2.5 bg-blue-600 text-white rounded-lg hover:bg-blue-700 flex items-center">
286
+ <i class='bx bxs-cloud-upload mr-2'></i>
287
+ Publish JSON
288
+ </button>
289
+ </div>
290
+ </div>
146
291
  </div>
147
292
 
148
293
  <script src="js/onboard/index.js" type="module"></script>
294
+ <!-- Highlight.js script can be removed if not using <pre><code> for JSON -->
149
295
  </body>
150
296
  </html>
@@ -152,4 +152,94 @@ body {
152
152
  outline: none;
153
153
  border-color: #2563eb;
154
154
  box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
155
- }
155
+ }
156
+
157
+ /* Onboarding form styles */
158
+
159
+ /* Form field styles */
160
+ input[type="text"],
161
+ input[type="url"],
162
+ select,
163
+ textarea {
164
+ transition: all 0.2s ease;
165
+ }
166
+
167
+ input[type="text"]:focus,
168
+ input[type="url"]:focus,
169
+ select:focus,
170
+ textarea:focus {
171
+ outline: none;
172
+ border-color: #2563eb;
173
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
174
+ }
175
+
176
+ /* Radio button styles */
177
+ input[type="radio"] {
178
+ width: 1rem;
179
+ height: 1rem;
180
+ border: 2px solid #d1d5db;
181
+ border-radius: 50%;
182
+ transition: all 0.2s ease;
183
+ }
184
+
185
+ input[type="radio"]:checked {
186
+ border-color: #2563eb;
187
+ background-color: #2563eb;
188
+ }
189
+
190
+ /* Remove button styles */
191
+ .remove-button {
192
+ color: #dc2626;
193
+ transition: all 0.2s ease;
194
+ }
195
+
196
+ .remove-button:hover {
197
+ color: #b91c1c;
198
+ background-color: #fee2e2;
199
+ }
200
+
201
+ /* Add button styles */
202
+ .add-button {
203
+ background-color: #f3f4f6;
204
+ transition: all 0.2s ease;
205
+ }
206
+
207
+ .add-button:hover {
208
+ background-color: #e5e7eb;
209
+ transform: translateY(-1px);
210
+ }
211
+
212
+ /* Form section headings */
213
+ .section-heading {
214
+ color: #1f2937;
215
+ font-size: 1.25rem;
216
+ font-weight: 600;
217
+ margin-bottom: 1rem;
218
+ display: flex;
219
+ align-items: center;
220
+ }
221
+
222
+ .section-heading i {
223
+ color: #2563eb;
224
+ margin-right: 0.5rem;
225
+ }
226
+
227
+ /* Required field indicator */
228
+ .required-field::after {
229
+ content: "*";
230
+ color: #dc2626;
231
+ margin-left: 0.25rem;
232
+ }
233
+
234
+ /* Form grid layouts */
235
+ .form-grid {
236
+ display: grid;
237
+ gap: 1rem;
238
+ margin-bottom: 1.5rem;
239
+ }
240
+
241
+ @media (min-width: 768px) {
242
+ .form-grid {
243
+ grid-template-columns: repeat(2, 1fr);
244
+ }
245
+ }
@@ -1,11 +1 @@
1
- import { ServerInstallOptions } from '../core/types.js';
2
- export interface UpdateRequirementsRequestBody {
3
- requirements: {
4
- name: string;
5
- updateVersion: string;
6
- }[];
7
- }
8
- export interface InstallServersRequestBody {
9
- serverList: Record<string, ServerInstallOptions>;
10
- }
11
1
  export declare function startWebServer(port?: number): Promise<void>;
@@ -1,11 +1,14 @@
1
1
  import express from 'express';
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import { OnboardingProcessStatus } from '../core/onboard/OnboardStatus.js';
4
5
  import { SUPPORTED_CLIENT_NAMES } from '../core/constants.js';
5
6
  import { serverService } from '../services/ServerService.js';
7
+ import { feedOnboardService } from '../core/onboard/FeedOnboardService.js';
6
8
  import { openBrowser } from '../utils/osUtils.js';
7
9
  import { Logger } from '../utils/logger.js';
8
10
  import { configProvider } from '../core/ConfigurationProvider.js';
11
+ import { onboardStatusManager } from '../core/onboard/OnboardStatusManager.js';
9
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
13
  const app = express();
11
14
  // Middleware
@@ -52,31 +55,31 @@ app.get('/api/categories', async (req, res) => {
52
55
  error: message
53
56
  });
54
57
  }
55
- // Get server schema
56
- app.get('/api/categories/:categoryName/servers/:serverName/schema', async (req, res) => {
57
- try {
58
- const { categoryName, serverName } = req.params;
59
- const schema = await serverService.getServerSchema(categoryName, serverName);
60
- if (!schema) {
61
- return res.status(404).json({
62
- success: false,
63
- error: `Schema not found for server ${serverName} in category ${categoryName}`
64
- });
65
- }
66
- const response = {
67
- success: true,
68
- data: schema
69
- };
70
- res.json(response);
71
- }
72
- catch (error) {
73
- const message = error instanceof Error ? error.message : 'Unknown error';
74
- res.status(500).json({
58
+ });
59
+ // Get server schema
60
+ app.get('/api/categories/:categoryName/servers/:serverName/schema', async (req, res) => {
61
+ try {
62
+ const { categoryName, serverName } = req.params;
63
+ const schema = await serverService.getServerSchema(categoryName, serverName);
64
+ if (!schema) {
65
+ return res.status(404).json({
75
66
  success: false,
76
- error: `Failed to get schema for server ${req.params.serverName} in category ${req.params.categoryName}: ${message}`
67
+ error: `Schema not found for server ${serverName} in category ${categoryName}`
77
68
  });
78
69
  }
79
- });
70
+ const response = {
71
+ success: true,
72
+ data: schema
73
+ };
74
+ res.json(response);
75
+ }
76
+ catch (error) {
77
+ const message = error instanceof Error ? error.message : 'Unknown error';
78
+ res.status(500).json({
79
+ success: false,
80
+ error: `Failed to get schema for server ${req.params.serverName} in category ${req.params.categoryName}: ${message}`
81
+ });
82
+ }
80
83
  });
81
84
  // Get categories data (including feed configuration)
82
85
  app.get('/api/categories/:categoryName', async (req, res) => {
@@ -103,6 +106,7 @@ app.get('/api/categories/:categoryName', async (req, res) => {
103
106
  });
104
107
  }
105
108
  });
109
+ // Handle server category onboarding
106
110
  // Install servers for a category
107
111
  app.post('/api/categories/:categoryName/install', async (req, res) => {
108
112
  try {
@@ -130,6 +134,111 @@ app.post('/api/categories/:categoryName/install', async (req, res) => {
130
134
  });
131
135
  }
132
136
  });
137
+ // Handle server category onboarding
138
+ app.post('/api/categories/onboard', async (req, res) => {
139
+ try {
140
+ const { categoryData, forExistingCategory } = req.body; // Extract forExistingCategory from request body
141
+ // Basic validation for categoryData presence and essential fields for this endpoint
142
+ if (!categoryData || !categoryData.name || !categoryData.displayName) {
143
+ return res.status(400).json({
144
+ success: false,
145
+ error: 'Category data, including name and display name, is required.'
146
+ });
147
+ }
148
+ // categoryData is now expected to be a FeedConfiguration object directly from the client
149
+ const feedConfiguration = categoryData;
150
+ // Structural validation is now primarily handled by FeedOnboardService.validateStaticConfig
151
+ // The service will throw an error if the structure is invalid, which will be caught by the catch block below.
152
+ const operationResult = await feedOnboardService.onboardFeed(feedConfiguration, forExistingCategory);
153
+ // The response now directly reflects the OperationStatus returned by the service.
154
+ // The client will use data.onboardingId (which is the categoryName) to poll for status updates.
155
+ const response = {
156
+ success: operationResult.status !== OnboardingProcessStatus.FAILED, // Or a more nuanced success check
157
+ // Ensure data.onboardingId is the categoryName for polling
158
+ data: { ...operationResult, onboardingId: feedConfiguration.name }
159
+ };
160
+ res.status(operationResult.status === OnboardingProcessStatus.FAILED ? 500 : 200).json(response);
161
+ }
162
+ catch (error) {
163
+ const message = error instanceof Error ? error.message : 'Unknown error';
164
+ res.status(500).json({
165
+ success: false,
166
+ error: `Failed to ${req.body.isUpdate ? 'update' : 'create'} server category: ${message}`
167
+ });
168
+ }
169
+ });
170
+ // Validate feed configuration
171
+ app.post('/api/categories/onboard/validate', async (req, res) => {
172
+ try {
173
+ const { categoryData, forExistingCategory } = req.body;
174
+ if (!categoryData || !categoryData.name) {
175
+ return res.status(400).json({
176
+ success: false,
177
+ error: 'Category name is required in categoryData for validation.'
178
+ });
179
+ }
180
+ // categoryData is now expected to be a FeedConfiguration object directly from the client
181
+ const feedConfigurationToValidate = categoryData;
182
+ // Structural validation is now primarily handled by FeedOnboardService.validateStaticConfig
183
+ // The service will throw an error if the structure is invalid, which will be caught by the catch block below.
184
+ // Call the service, which now returns OperationStatus & { feedConfiguration? }
185
+ // serverName parameter has been removed from validateFeed
186
+ const validationOperationResult = await feedOnboardService.validateFeed(feedConfigurationToValidate, forExistingCategory);
187
+ // The response includes the operation status and the feed configuration that was validated.
188
+ // The client will use data.onboardingId (which is the categoryName) to poll for status updates.
189
+ const response = {
190
+ success: validationOperationResult.status !== OnboardingProcessStatus.FAILED,
191
+ // Ensure data.onboardingId is the categoryName for polling
192
+ data: { ...validationOperationResult, onboardingId: feedConfigurationToValidate.name }
193
+ };
194
+ res.status(validationOperationResult.status === OnboardingProcessStatus.FAILED ? 500 : 200).json(response);
195
+ }
196
+ catch (error) {
197
+ const message = error instanceof Error ? error.message : 'Unknown error';
198
+ res.status(500).json({
199
+ success: false,
200
+ error: `Failed to validate server category: ${message}`
201
+ });
202
+ }
203
+ });
204
+ // Get category onboarding/validation operation status
205
+ app.get('/api/categories/:categoryName/onboard/status', async (req, res) => {
206
+ try {
207
+ const { categoryName } = req.params;
208
+ // categoryName is now the identifier for the operation status
209
+ const status = await onboardStatusManager.getStatus(categoryName);
210
+ if (!status) {
211
+ return res.status(404).json({
212
+ success: false,
213
+ error: `No active operation found for category ${categoryName}`
214
+ });
215
+ }
216
+ // Construct the response data based on the retrieved OnboardStatus
217
+ const responseData = {
218
+ onboardingId: status.onboardingId, // This will be the categoryName
219
+ status: status.status,
220
+ message: status.currentStep || status.errorMessage || 'Processing...',
221
+ lastQueried: new Date().toISOString(),
222
+ ...(status.validationStatus && { validationStatus: status.validationStatus }),
223
+ ...(status.prInfo && { prInfo: status.prInfo }),
224
+ ...(status.result && { result: status.result }),
225
+ ...(status.errorMessage && { errorMessage: status.errorMessage }),
226
+ ...(status.operationType && { operationType: status.operationType }),
227
+ };
228
+ const response = {
229
+ success: true,
230
+ data: responseData
231
+ };
232
+ res.json(response);
233
+ }
234
+ catch (error) {
235
+ const message = error instanceof Error ? error.message : 'Unknown error';
236
+ res.status(500).json({
237
+ success: false,
238
+ error: `Failed to get operation status for category ${req.params.categoryName}: ${message}`
239
+ });
240
+ }
241
+ });
133
242
  // Uninstall tools from a server
134
243
  app.post('/api/categories/:categoryName/uninstall', async (req, res) => {
135
244
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imcp",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "description": "Node.js SDK for Model Context Protocol (MCP)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -15,7 +15,7 @@
15
15
  "test": "jest",
16
16
  "lint": "eslint src --ext .ts",
17
17
  "format": "prettier --write \"src/**/*.ts\"",
18
- "copy-public": "xcopy /E /I /Y src\\web\\public dist\\web\\public"
18
+ "copy-public": "node -e \"const fs=require('fs'); const path=require('path'); const cp=require('child_process'); const cmd=process.platform==='win32' ? 'xcopy /E /I /Y src\\\\web\\\\public dist\\\\web\\\\public' : 'cp -r src/web/public dist/web/'; cp.execSync(cmd)\""
19
19
  },
20
20
  "keywords": [
21
21
  "mcp",