imcp 0.0.11 → 0.0.13
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/cli/commands/uninstall.js +14 -6
- package/dist/core/ConfigurationProvider.d.ts +3 -1
- package/dist/core/ConfigurationProvider.js +85 -25
- package/dist/core/InstallationService.d.ts +17 -0
- package/dist/core/InstallationService.js +127 -61
- package/dist/core/MCPManager.d.ts +1 -0
- package/dist/core/MCPManager.js +30 -5
- package/dist/core/RequirementService.d.ts +4 -4
- package/dist/core/RequirementService.js +11 -7
- package/dist/core/ServerSchemaLoader.js +2 -2
- package/dist/core/ServerSchemaProvider.d.ts +1 -1
- package/dist/core/ServerSchemaProvider.js +15 -10
- package/dist/core/constants.d.ts +14 -1
- package/dist/core/constants.js +4 -1
- package/dist/core/installers/clients/ExtensionInstaller.js +3 -0
- package/dist/core/installers/requirements/PipInstaller.js +10 -5
- package/dist/core/types.d.ts +10 -0
- package/dist/services/ServerService.d.ts +12 -1
- package/dist/services/ServerService.js +39 -9
- package/dist/utils/githubAuth.js +0 -10
- package/dist/utils/githubUtils.d.ts +16 -0
- package/dist/utils/githubUtils.js +55 -39
- package/dist/utils/osUtils.js +1 -1
- package/dist/web/public/css/detailsWidget.css +189 -57
- package/dist/web/public/css/modal.css +42 -0
- package/dist/web/public/css/serverDetails.css +35 -18
- package/dist/web/public/index.html +2 -0
- package/dist/web/public/js/detailsWidget.js +175 -60
- package/dist/web/public/js/modal.js +93 -29
- package/dist/web/public/js/notifications.js +34 -35
- package/dist/web/public/js/serverCategoryDetails.js +182 -120
- package/dist/web/server.js +38 -2
- package/package.json +3 -4
- package/src/cli/commands/uninstall.ts +16 -6
- package/src/core/ConfigurationProvider.ts +102 -25
- package/src/core/InstallationService.ts +176 -62
- package/src/core/MCPManager.ts +36 -5
- package/src/core/RequirementService.ts +12 -8
- package/src/core/ServerSchemaLoader.ts +48 -0
- package/src/core/ServerSchemaProvider.ts +137 -0
- package/src/core/constants.ts +16 -3
- package/src/core/installers/clients/ExtensionInstaller.ts +3 -0
- package/src/core/installers/requirements/PipInstaller.ts +10 -5
- package/src/core/types.ts +11 -1
- package/src/services/ServerService.ts +41 -8
- package/src/utils/githubAuth.ts +14 -27
- package/src/utils/githubUtils.ts +84 -47
- package/src/utils/osUtils.ts +1 -1
- package/src/web/public/css/detailsWidget.css +235 -0
- package/src/web/public/css/modal.css +42 -0
- package/src/web/public/css/serverDetails.css +126 -0
- package/src/web/public/index.html +2 -0
- package/src/web/public/js/detailsWidget.js +264 -0
- package/src/web/public/js/modal.js +93 -29
- package/src/web/public/js/notifications.js +34 -35
- package/src/web/public/js/serverCategoryDetails.js +182 -120
- package/src/web/server.ts +52 -3
|
@@ -1,34 +1,38 @@
|
|
|
1
1
|
import { allServerCategoriesData, fetchServerCategories } from './api.js';
|
|
2
2
|
import { showInstallModal } from './modal.js';
|
|
3
3
|
import { showToast, showConfirm } from './notifications.js';
|
|
4
|
+
import { DetailsWidget } from './detailsWidget.js';
|
|
4
5
|
|
|
5
6
|
const REFRESH_INTERVAL = 2000; // 2 seconds
|
|
6
7
|
let refreshTimer = null;
|
|
8
|
+
let activeDetailsWidget = null;
|
|
7
9
|
|
|
8
10
|
// Start refresh timer for installation status
|
|
9
11
|
function startRefreshTimer(serverName) {
|
|
10
|
-
// Clear existing timer if any
|
|
11
12
|
if (refreshTimer) {
|
|
12
13
|
clearInterval(refreshTimer);
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
// Setup new refresh timer
|
|
16
16
|
refreshTimer = setInterval(async () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
17
|
+
try {
|
|
18
|
+
const server = allServerCategoriesData.find(s => s.name === serverName);
|
|
19
|
+
if (!server?.installationStatus?.serversStatus) return;
|
|
20
|
+
|
|
21
|
+
const hasPendingInstallation = Object.values(server.installationStatus.serversStatus).some(serverStatus =>
|
|
22
|
+
Object.values(serverStatus.installedStatus || {}).some(status =>
|
|
23
|
+
status.status === 'pending' || status.status === 'in-progress'
|
|
24
|
+
)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
if (hasPendingInstallation) {
|
|
28
|
+
await fetchServerCategories();
|
|
29
|
+
await showServerDetails(serverName);
|
|
30
|
+
} else {
|
|
31
|
+
clearInterval(refreshTimer);
|
|
32
|
+
}
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error('Error in refresh timer:', error);
|
|
35
|
+
clearInterval(refreshTimer);
|
|
32
36
|
}
|
|
33
37
|
}, REFRESH_INTERVAL);
|
|
34
38
|
}
|
|
@@ -36,108 +40,177 @@ function startRefreshTimer(serverName) {
|
|
|
36
40
|
// Show server details
|
|
37
41
|
async function showServerDetails(serverName) {
|
|
38
42
|
console.log("Showing details for:", serverName);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!server) {
|
|
45
|
-
detailsDiv.innerHTML = '<p class="text-red-500">Error: Server data not found.</p>';
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
43
|
+
try {
|
|
44
|
+
localStorage.setItem('lastSelectedCategory', serverName);
|
|
45
|
+
const server = allServerCategoriesData.find(s => s.name === serverName);
|
|
46
|
+
const detailsDiv = document.getElementById('serverCategoryDetails');
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
item.classList.remove('bg-blue-100', 'border-blue-300');
|
|
52
|
-
if (item.dataset.serverName === serverName) {
|
|
53
|
-
item.classList.add('bg-blue-100', 'border-blue-300');
|
|
48
|
+
if (!server) {
|
|
49
|
+
throw new Error('Server data not found');
|
|
54
50
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
<div class="h-4 bg-gray-200 rounded w-5/6"></div>
|
|
51
|
+
|
|
52
|
+
detailsDiv.innerHTML = `
|
|
53
|
+
<h3 class="text-xl font-semibold mb-2 text-gray-800">${server.displayName || server.name}</h3>
|
|
54
|
+
<p class="mb-4"><span class="font-semibold">Description:</span> ${server.description || 'N/A'}</p>
|
|
55
|
+
<div id="toolMcpsList" class="mt-4">
|
|
56
|
+
<div class="animate-pulse flex space-x-4">
|
|
57
|
+
<div class="flex-1 space-y-4 py-1">
|
|
58
|
+
<div class="h-4 bg-gray-200 rounded w-3/4"></div>
|
|
59
|
+
<div class="space-y-2">
|
|
60
|
+
<div class="h-4 bg-gray-200 rounded"></div>
|
|
61
|
+
<div class="h-4 bg-gray-200 rounded w-5/6"></div>
|
|
62
|
+
</div>
|
|
68
63
|
</div>
|
|
69
64
|
</div>
|
|
70
65
|
</div>
|
|
71
|
-
|
|
72
|
-
`;
|
|
66
|
+
`;
|
|
73
67
|
|
|
74
|
-
// Asynchronously load and render the servers list
|
|
75
|
-
try {
|
|
76
68
|
const serversListHtml = await renderServersList(server);
|
|
77
|
-
document.getElementById('toolMcpsList')
|
|
69
|
+
const toolMcpsList = document.getElementById('toolMcpsList');
|
|
70
|
+
if (!toolMcpsList) {
|
|
71
|
+
throw new Error('toolMcpsList element not found');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
toolMcpsList.innerHTML = serversListHtml;
|
|
75
|
+
|
|
76
|
+
// Setup server items click handlers
|
|
77
|
+
const serverItems = document.querySelectorAll('.server-item-content');
|
|
78
|
+
console.log(`Found ${serverItems.length} server items`);
|
|
79
|
+
|
|
80
|
+
serverItems.forEach(item => {
|
|
81
|
+
const mcpServerName = item.dataset.serverName;
|
|
82
|
+
console.log(`Setting up click handler for server: ${mcpServerName}`);
|
|
83
|
+
|
|
84
|
+
const mcpServer = server.feedConfiguration?.mcpServers?.find(
|
|
85
|
+
s => s.name === mcpServerName
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
if (mcpServer) {
|
|
89
|
+
const detailsWidget = new DetailsWidget(item);
|
|
90
|
+
|
|
91
|
+
// Initially set description
|
|
92
|
+
detailsWidget.setContent(mcpServer.description);
|
|
93
|
+
|
|
94
|
+
// Fetch and display schema when expanded
|
|
95
|
+
const fetchSchema = async () => {
|
|
96
|
+
try {
|
|
97
|
+
const response = await fetch(`/api/categories/${server.name}/servers/${mcpServerName}/schema`);
|
|
98
|
+
if (!response.ok) return;
|
|
99
|
+
|
|
100
|
+
const result = await response.json();
|
|
101
|
+
if (result.success && result.data) {
|
|
102
|
+
detailsWidget.setContent(result.data);
|
|
103
|
+
}
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error('Error fetching schema:', error);
|
|
106
|
+
// Silently fail - don't show error in UI
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
item.addEventListener('click', async (event) => {
|
|
111
|
+
if (!event.target.closest('button')) {
|
|
112
|
+
if (detailsWidget === activeDetailsWidget) {
|
|
113
|
+
// Only toggle if clicking the currently active item
|
|
114
|
+
detailsWidget.toggle();
|
|
115
|
+
if (!detailsWidget.isVisible()) {
|
|
116
|
+
activeDetailsWidget = null;
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
// Expand the clicked item without collapsing others
|
|
120
|
+
detailsWidget.expand();
|
|
121
|
+
activeDetailsWidget = detailsWidget;
|
|
122
|
+
await fetchSchema();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
startRefreshTimer(serverName);
|
|
78
130
|
} catch (error) {
|
|
79
|
-
console.error('Error
|
|
80
|
-
document.getElementById('
|
|
131
|
+
console.error('Error in showServerDetails:', error);
|
|
132
|
+
const detailsDiv = document.getElementById('serverCategoryDetails');
|
|
133
|
+
if (detailsDiv) {
|
|
134
|
+
detailsDiv.innerHTML = `<p class="text-red-500">Error loading server details: ${error.message}</p>`;
|
|
135
|
+
}
|
|
81
136
|
showToast(`Error loading server details: ${error.message}`, 'error');
|
|
82
137
|
}
|
|
83
|
-
|
|
84
|
-
// Start monitoring installation status
|
|
85
|
-
startRefreshTimer(serverName);
|
|
86
138
|
}
|
|
87
139
|
|
|
88
|
-
// Render tools list
|
|
89
140
|
async function renderServersList(serverCategory) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (!serverCategory.feedConfiguration?.mcpServers) {
|
|
95
|
-
return '<p class="text-gray-500">No MCP Servers found for this server.</p>';
|
|
96
|
-
}
|
|
141
|
+
try {
|
|
142
|
+
const targetResponse = await fetch('/api/targets');
|
|
143
|
+
const targetData = await targetResponse.json();
|
|
144
|
+
const availableTargets = targetData.success ? targetData.data : [];
|
|
97
145
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
146
|
+
if (!serverCategory.feedConfiguration?.mcpServers) {
|
|
147
|
+
return '<p class="text-gray-500">No MCP Servers found for this server.</p>';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const mcpServers = serverCategory.feedConfiguration.mcpServers;
|
|
151
|
+
if (mcpServers.length === 0) {
|
|
152
|
+
return '<p class="text-gray-500">No MCP Servers found for this server.</p>';
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let toolsHtml = `
|
|
156
|
+
<div class="flex justify-between items-center mb-4">
|
|
157
|
+
<h2 class="text-lg font-semibold text-gray-600">MCP Servers</h2>
|
|
158
|
+
</div>`;
|
|
159
|
+
|
|
160
|
+
mcpServers.forEach(mcpServer => {
|
|
161
|
+
const isInstalled = mcpServer.installed;
|
|
162
|
+
const envRequirements = mcpServer.installation?.['env:'] || mcpServer.installation?.env || {};
|
|
163
|
+
const hasEnvRequirements = Object.keys(envRequirements).length > 0;
|
|
102
164
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
<
|
|
119
|
-
<p class="text-sm text-gray-600 mb-1">${mcpServer.description || 'No description'}</p>
|
|
120
|
-
<div class="flex flex-col">
|
|
165
|
+
toolsHtml += `
|
|
166
|
+
<div class="server-item-content" data-server-name="${mcpServer.name}">
|
|
167
|
+
<div class="server-item-info" style="width: 100%; box-sizing: border-box;">
|
|
168
|
+
<div class="server-item-header">
|
|
169
|
+
<div class="flex items-center">
|
|
170
|
+
<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>` : ''}
|
|
177
|
+
</div>
|
|
178
|
+
<p class="text-sm text-gray-600 mb-1">${mcpServer.description || 'No description'}</p>
|
|
179
|
+
</div>
|
|
180
|
+
<div class="flex flex-col mt-3">
|
|
121
181
|
<span class="text-xs font-semibold mb-2">Client Status:</span>
|
|
122
182
|
<div class="flex flex-wrap gap-2">
|
|
123
183
|
${availableTargets.map(client => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
184
|
+
const status = (serverCategory.installationStatus?.serversStatus[mcpServer.name]?.installedStatus || {})[client];
|
|
185
|
+
const isInstalled = status?.status === 'completed';
|
|
186
|
+
return `
|
|
127
187
|
<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">
|
|
128
188
|
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
129
189
|
${isInstalled
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
+
}
|
|
133
193
|
</svg>
|
|
134
194
|
${client}
|
|
135
195
|
</span>
|
|
136
196
|
`;
|
|
137
|
-
|
|
197
|
+
}).join('')}
|
|
138
198
|
</div>
|
|
139
199
|
</div>
|
|
140
|
-
|
|
200
|
+
<div class="action-buttons">
|
|
201
|
+
${!isInstalled ? `
|
|
202
|
+
<button onclick="event.stopPropagation(); window.showInstallModal('${serverCategory.name}', '${mcpServer.name}')"
|
|
203
|
+
class="bg-blue-500 hover:bg-blue-700 text-white text-xs font-bold py-2 px-4 rounded-full shadow-sm transition duration-150 ease-in-out">
|
|
204
|
+
Setup
|
|
205
|
+
</button>
|
|
206
|
+
` : `
|
|
207
|
+
<button onclick="event.stopPropagation(); window.uninstallTools('${serverCategory.name}', ['${mcpServer.name}'])"
|
|
208
|
+
class="bg-red-500 hover:bg-red-700 text-white text-sm font-bold py-2 px-4 rounded-full shadow-sm transition duration-150 ease-in-out">
|
|
209
|
+
Uninstall
|
|
210
|
+
</button>
|
|
211
|
+
`}
|
|
212
|
+
</div>
|
|
213
|
+
${hasEnvRequirements ? `<div class="mt-3 text-xs text-blue-600">
|
|
141
214
|
<svg class="w-3 h-3 inline mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
142
215
|
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd"></path>
|
|
143
216
|
</svg>
|
|
@@ -145,34 +218,21 @@ async function renderServersList(serverCategory) {
|
|
|
145
218
|
</div>` : ''}
|
|
146
219
|
</div>
|
|
147
220
|
</div>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
class="bg-blue-500 hover:bg-blue-700 text-white text-sm font-bold py-1 px-3 rounded-full shadow-sm transition duration-150 ease-in-out">
|
|
151
|
-
Install
|
|
152
|
-
</button>
|
|
153
|
-
` : `
|
|
154
|
-
<div class="flex items-center gap-2">
|
|
155
|
-
<button onclick="event.stopPropagation(); window.uninstallTools('${serverCategory.name}', ['${mcpServer.name}'])"
|
|
156
|
-
class="bg-red-500 hover:bg-red-700 text-white text-sm font-bold py-1 px-3 rounded transition duration-150 ease-in-out">
|
|
157
|
-
Uninstall
|
|
158
|
-
</button>
|
|
159
|
-
</div>
|
|
160
|
-
`}
|
|
161
|
-
</div>
|
|
162
|
-
`;
|
|
163
|
-
});
|
|
221
|
+
`;
|
|
222
|
+
});
|
|
164
223
|
|
|
165
|
-
|
|
224
|
+
return toolsHtml;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
console.error('Error in renderServersList:', error);
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
166
229
|
}
|
|
167
230
|
|
|
168
|
-
// Uninstall tools
|
|
169
231
|
window.uninstallTools = async function (serverName, toolList) {
|
|
170
|
-
const confirmed = await showConfirm(`Are you sure you want to uninstall ${toolList.length} tool(s)?`);
|
|
171
|
-
if (!confirmed) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
232
|
try {
|
|
233
|
+
const confirmed = await showConfirm(`Are you sure you want to uninstall ${toolList.length} tool(s)?`);
|
|
234
|
+
if (!confirmed) return;
|
|
235
|
+
|
|
176
236
|
const response = await fetch(`/api/categories/${serverName}/uninstall`, {
|
|
177
237
|
method: 'POST',
|
|
178
238
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -190,21 +250,23 @@ window.uninstallTools = async function (serverName, toolList) {
|
|
|
190
250
|
}
|
|
191
251
|
|
|
192
252
|
showToast('Tools uninstalled successfully!', 'success');
|
|
193
|
-
await fetchServerCategories();
|
|
194
|
-
await showServerDetails(serverName);
|
|
253
|
+
await fetchServerCategories();
|
|
254
|
+
await showServerDetails(serverName);
|
|
195
255
|
} catch (error) {
|
|
196
256
|
console.error('Error uninstalling tools:', error);
|
|
197
257
|
showToast(`Error uninstalling tools: ${error.message}`, 'error');
|
|
198
258
|
}
|
|
199
259
|
}
|
|
200
260
|
|
|
201
|
-
// Make showServerDetails available in window scope and handle async
|
|
202
261
|
window.showServerDetails = async function (serverName) {
|
|
203
262
|
try {
|
|
204
263
|
await showServerDetails(serverName);
|
|
205
264
|
} catch (error) {
|
|
206
|
-
console.error('Error
|
|
207
|
-
document.getElementById('serverCategoryDetails')
|
|
265
|
+
console.error('Error in window.showServerDetails:', error);
|
|
266
|
+
const detailsDiv = document.getElementById('serverCategoryDetails');
|
|
267
|
+
if (detailsDiv) {
|
|
268
|
+
detailsDiv.innerHTML = `<p class="text-red-500">Error loading server details: ${error.message}</p>`;
|
|
269
|
+
}
|
|
208
270
|
showToast(`Error loading server details: ${error.message}`, 'error');
|
|
209
271
|
}
|
|
210
272
|
};
|
package/src/web/server.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import express, { Request, Response } from 'express';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
+
import { ServerSchema } from '../core/ServerSchemaProvider.js';
|
|
5
|
+
|
|
4
6
|
import { SUPPORTED_CLIENT_NAMES } from '../core/constants.js';
|
|
5
7
|
import { serverService } from '../services/ServerService.js';
|
|
6
8
|
import { openBrowser } from '../utils/osUtils.js';
|
|
@@ -32,7 +34,11 @@ export interface InstallServersRequestBody {
|
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
interface UninstallServersRequestBody {
|
|
35
|
-
serverList: string
|
|
37
|
+
serverList: Record<string, { removeData?: boolean }>;
|
|
38
|
+
options: {
|
|
39
|
+
targets: string[];
|
|
40
|
+
removeData?: boolean;
|
|
41
|
+
};
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
interface ApiResponse<T> {
|
|
@@ -86,6 +92,35 @@ app.get('/api/categories', async (req: Request<{}, {}, {}, ListQueryParams>, res
|
|
|
86
92
|
error: message
|
|
87
93
|
});
|
|
88
94
|
}
|
|
95
|
+
|
|
96
|
+
// Get server schema
|
|
97
|
+
app.get('/api/categories/:categoryName/servers/:serverName/schema', async (req: Request<{ categoryName: string; serverName: string }>, res: Response) => {
|
|
98
|
+
try {
|
|
99
|
+
const { categoryName, serverName } = req.params;
|
|
100
|
+
const schema = await serverService.getServerSchema(categoryName, serverName);
|
|
101
|
+
|
|
102
|
+
if (!schema) {
|
|
103
|
+
return res.status(404).json({
|
|
104
|
+
success: false,
|
|
105
|
+
error: `Schema not found for server ${serverName} in category ${categoryName}`
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const response: ApiResponse<ServerSchema> = {
|
|
110
|
+
success: true,
|
|
111
|
+
data: schema
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
res.json(response);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
117
|
+
res.status(500).json({
|
|
118
|
+
success: false,
|
|
119
|
+
error: `Failed to get schema for server ${req.params.serverName} in category ${req.params.categoryName}: ${message}`
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
89
124
|
});
|
|
90
125
|
|
|
91
126
|
// Get categories data (including feed configuration)
|
|
@@ -155,15 +190,29 @@ app.post('/api/categories/:categoryName/uninstall', async (req: Request<{ catego
|
|
|
155
190
|
const { categoryName } = req.params;
|
|
156
191
|
const { serverList } = req.body;
|
|
157
192
|
|
|
158
|
-
if (!
|
|
193
|
+
if (!serverList || Object.keys(serverList).length === 0) {
|
|
159
194
|
return res.status(400).json({
|
|
160
195
|
success: false,
|
|
161
196
|
error: 'Invalid tool list provided'
|
|
162
197
|
});
|
|
163
198
|
}
|
|
164
199
|
|
|
200
|
+
const { options } = req.body;
|
|
201
|
+
if (!options?.targets || options.targets.length === 0) {
|
|
202
|
+
return res.status(400).json({
|
|
203
|
+
success: false,
|
|
204
|
+
error: 'No target clients specified'
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
165
208
|
const results = await Promise.all(
|
|
166
|
-
serverList.map(serverName
|
|
209
|
+
Object.entries(serverList).map(([serverName, serverOptions]) =>
|
|
210
|
+
serverService.uninstallMcpServer(categoryName, serverName, {
|
|
211
|
+
...serverOptions,
|
|
212
|
+
targets: options.targets,
|
|
213
|
+
removeData: options.removeData ?? serverOptions.removeData
|
|
214
|
+
})
|
|
215
|
+
)
|
|
167
216
|
);
|
|
168
217
|
|
|
169
218
|
const { success, messages } = serverService.formatOperationResults(results);
|