imcp 0.0.12 → 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.
- package/dist/core/ConfigurationProvider.d.ts +2 -1
- package/dist/core/ConfigurationProvider.js +20 -24
- 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 +3 -0
- package/dist/core/RequirementService.d.ts +4 -4
- package/dist/core/RequirementService.js +11 -7
- package/dist/core/ServerSchemaProvider.d.ts +1 -1
- package/dist/core/ServerSchemaProvider.js +15 -10
- package/dist/core/constants.d.ts +3 -0
- package/dist/core/constants.js +4 -1
- package/dist/core/installers/clients/ClientInstaller.js +58 -40
- package/dist/core/installers/requirements/PipInstaller.js +10 -5
- package/dist/core/onboard/FeedOnboardService.d.ts +35 -0
- package/dist/core/onboard/FeedOnboardService.js +137 -0
- package/dist/core/types.d.ts +6 -1
- package/dist/core/validators/FeedValidator.d.ts +13 -0
- package/dist/core/validators/FeedValidator.js +27 -0
- package/dist/services/ServerService.d.ts +5 -0
- package/dist/services/ServerService.js +15 -0
- package/dist/utils/githubAuth.js +0 -10
- package/dist/utils/githubUtils.d.ts +16 -0
- package/dist/utils/githubUtils.js +55 -39
- package/dist/web/contract/serverContract.d.ts +64 -0
- package/dist/web/contract/serverContract.js +2 -0
- package/dist/web/public/css/detailsWidget.css +157 -32
- package/dist/web/public/css/onboard.css +44 -0
- package/dist/web/public/css/serverDetails.css +35 -19
- package/dist/web/public/index.html +16 -10
- package/dist/web/public/js/detailsWidget.js +43 -40
- package/dist/web/public/js/modal/index.js +58 -0
- package/dist/web/public/js/modal/installHandler.js +227 -0
- package/dist/web/public/js/modal/installModal.js +163 -0
- package/dist/web/public/js/modal/installation.js +281 -0
- package/dist/web/public/js/modal/loadingModal.js +52 -0
- package/dist/web/public/js/modal/loadingUI.js +74 -0
- package/dist/web/public/js/modal/messageQueue.js +112 -0
- package/dist/web/public/js/modal/modalSetup.js +512 -0
- package/dist/web/public/js/modal/modalUI.js +214 -0
- package/dist/web/public/js/modal/modalUtils.js +49 -0
- package/dist/web/public/js/modal/version.js +20 -0
- package/dist/web/public/js/modal/versionUtils.js +20 -0
- package/dist/web/public/js/modal.js +25 -1041
- package/dist/web/public/js/onboard/formProcessor.js +309 -0
- package/dist/web/public/js/onboard/index.js +131 -0
- package/dist/web/public/js/onboard/state.js +32 -0
- package/dist/web/public/js/onboard/templates.js +375 -0
- package/dist/web/public/js/onboard/uiHandlers.js +196 -0
- package/dist/web/public/js/serverCategoryDetails.js +211 -123
- package/dist/web/public/onboard.html +150 -0
- package/dist/web/server.js +25 -0
- package/package.json +3 -4
- package/src/core/ConfigurationProvider.ts +37 -29
- package/src/core/InstallationService.ts +176 -62
- package/src/core/MCPManager.ts +4 -0
- 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 +4 -1
- package/src/core/installers/clients/ClientInstaller.ts +66 -49
- package/src/core/installers/requirements/PipInstaller.ts +10 -5
- package/src/core/types.ts +6 -1
- package/src/services/ServerService.ts +15 -0
- package/src/utils/githubAuth.ts +14 -27
- package/src/utils/githubUtils.ts +84 -47
- package/src/web/public/css/detailsWidget.css +235 -0
- package/src/web/public/css/serverDetails.css +126 -0
- package/src/web/public/index.html +16 -10
- package/src/web/public/js/detailsWidget.js +264 -0
- package/src/web/public/js/modal/index.js +58 -0
- package/src/web/public/js/modal/installModal.js +163 -0
- package/src/web/public/js/modal/installation.js +281 -0
- package/src/web/public/js/modal/loadingModal.js +52 -0
- package/src/web/public/js/modal/messageQueue.js +112 -0
- package/src/web/public/js/modal/modalSetup.js +512 -0
- package/src/web/public/js/modal/modalUtils.js +49 -0
- package/src/web/public/js/modal/versionUtils.js +20 -0
- package/src/web/public/js/modal.js +25 -1041
- package/src/web/public/js/serverCategoryDetails.js +211 -123
- package/src/web/server.ts +31 -0
|
@@ -1,143 +1,242 @@
|
|
|
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;
|
|
9
|
+
const MAX_RETRIES = 3;
|
|
10
|
+
const RETRY_DELAY = 1000;
|
|
7
11
|
|
|
8
12
|
// Start refresh timer for installation status
|
|
9
13
|
function startRefreshTimer(serverName) {
|
|
10
|
-
// Clear existing timer if any
|
|
11
14
|
if (refreshTimer) {
|
|
12
15
|
clearInterval(refreshTimer);
|
|
13
16
|
}
|
|
14
17
|
|
|
15
|
-
// Setup new refresh timer
|
|
16
18
|
refreshTimer = setInterval(async () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
try {
|
|
20
|
+
const server = allServerCategoriesData.find(s => s.name === serverName);
|
|
21
|
+
if (!server?.installationStatus?.serversStatus) return;
|
|
22
|
+
|
|
23
|
+
const hasPendingInstallation = Object.values(server.installationStatus.serversStatus).some(serverStatus =>
|
|
24
|
+
Object.values(serverStatus.installedStatus || {}).some(status =>
|
|
25
|
+
status.status === 'pending' || status.status === 'in-progress'
|
|
26
|
+
)
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
if (hasPendingInstallation) {
|
|
30
|
+
await fetchServerCategories();
|
|
31
|
+
await showServerDetails(serverName);
|
|
32
|
+
} else {
|
|
33
|
+
clearInterval(refreshTimer);
|
|
34
|
+
}
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error('Error in refresh timer:', error);
|
|
37
|
+
clearInterval(refreshTimer);
|
|
32
38
|
}
|
|
33
39
|
}, REFRESH_INTERVAL);
|
|
34
40
|
}
|
|
35
41
|
|
|
36
|
-
// Show server details
|
|
37
|
-
async function showServerDetails(serverName) {
|
|
42
|
+
// Show server details with retry mechanism
|
|
43
|
+
async function showServerDetails(serverName, retryCount = 0) {
|
|
38
44
|
console.log("Showing details for:", serverName);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const server = allServerCategoriesData.find(s => s.name === serverName);
|
|
42
|
-
const detailsDiv = document.getElementById('serverCategoryDetails');
|
|
43
|
-
|
|
44
|
-
if (!server) {
|
|
45
|
-
detailsDiv.innerHTML = '<p class="text-red-500">Error: Server data not found.</p>';
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
45
|
+
try {
|
|
46
|
+
localStorage.setItem('lastSelectedCategory', serverName);
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (item.dataset.serverName === serverName) {
|
|
53
|
-
item.classList.add('bg-blue-100', 'border-blue-300');
|
|
48
|
+
// If server data is not available, attempt to fetch it
|
|
49
|
+
if (allServerCategoriesData.length === 0) {
|
|
50
|
+
await fetchServerCategories();
|
|
54
51
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
52
|
+
|
|
53
|
+
const server = allServerCategoriesData.find(s => s.name === serverName);
|
|
54
|
+
const detailsDiv = document.getElementById('serverCategoryDetails');
|
|
55
|
+
|
|
56
|
+
if (!server) {
|
|
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');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
detailsDiv.innerHTML = `
|
|
67
|
+
<h3 class="text-xl font-semibold mb-2 text-gray-800">${server.displayName || server.name}</h3>
|
|
68
|
+
<p class="mb-4"><span class="font-semibold">Description:</span> ${server.description || 'N/A'}</p>
|
|
69
|
+
<div id="toolMcpsList" class="mt-4">
|
|
70
|
+
<div class="animate-pulse flex space-x-4">
|
|
71
|
+
<div class="flex-1 space-y-4 py-1">
|
|
72
|
+
<div class="h-4 bg-gray-200 rounded w-3/4"></div>
|
|
73
|
+
<div class="space-y-2">
|
|
74
|
+
<div class="h-4 bg-gray-200 rounded"></div>
|
|
75
|
+
<div class="h-4 bg-gray-200 rounded w-5/6"></div>
|
|
76
|
+
</div>
|
|
68
77
|
</div>
|
|
69
78
|
</div>
|
|
70
79
|
</div>
|
|
71
|
-
|
|
72
|
-
`;
|
|
80
|
+
`;
|
|
73
81
|
|
|
74
|
-
// Asynchronously load and render the servers list
|
|
75
|
-
try {
|
|
76
82
|
const serversListHtml = await renderServersList(server);
|
|
77
|
-
document.getElementById('toolMcpsList')
|
|
83
|
+
const toolMcpsList = document.getElementById('toolMcpsList');
|
|
84
|
+
if (!toolMcpsList) {
|
|
85
|
+
throw new Error('toolMcpsList element not found');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
toolMcpsList.innerHTML = serversListHtml;
|
|
89
|
+
|
|
90
|
+
// Setup server items click handlers
|
|
91
|
+
const serverItems = document.querySelectorAll('.server-item-content');
|
|
92
|
+
console.log(`Found ${serverItems.length} server items`);
|
|
93
|
+
|
|
94
|
+
serverItems.forEach(item => {
|
|
95
|
+
const mcpServerName = item.dataset.serverName;
|
|
96
|
+
console.log(`Setting up click handler for server: ${mcpServerName}`);
|
|
97
|
+
|
|
98
|
+
const mcpServer = server.feedConfiguration?.mcpServers?.find(
|
|
99
|
+
s => s.name === mcpServerName
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
if (mcpServer) {
|
|
103
|
+
const detailsWidget = new DetailsWidget(item);
|
|
104
|
+
|
|
105
|
+
// Initially set description
|
|
106
|
+
detailsWidget.setContent(mcpServer.description);
|
|
107
|
+
|
|
108
|
+
// Fetch and display schema when expanded
|
|
109
|
+
const fetchSchema = async () => {
|
|
110
|
+
try {
|
|
111
|
+
const response = await fetch(`/api/categories/${server.name}/servers/${mcpServerName}/schema`);
|
|
112
|
+
if (!response.ok) return;
|
|
113
|
+
|
|
114
|
+
const result = await response.json();
|
|
115
|
+
if (result.success && result.data) {
|
|
116
|
+
detailsWidget.setContent(result.data);
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error('Error fetching schema:', error);
|
|
120
|
+
// Silently fail - don't show error in UI
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
item.addEventListener('click', async (event) => {
|
|
125
|
+
if (!event.target.closest('button')) {
|
|
126
|
+
if (detailsWidget === activeDetailsWidget) {
|
|
127
|
+
// Only toggle if clicking the currently active item
|
|
128
|
+
detailsWidget.toggle();
|
|
129
|
+
if (!detailsWidget.isVisible()) {
|
|
130
|
+
activeDetailsWidget = null;
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
// Expand the clicked item without collapsing others
|
|
134
|
+
detailsWidget.expand();
|
|
135
|
+
activeDetailsWidget = detailsWidget;
|
|
136
|
+
await fetchSchema();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
startRefreshTimer(serverName);
|
|
78
144
|
} catch (error) {
|
|
79
|
-
console.error('Error
|
|
80
|
-
document.getElementById('
|
|
145
|
+
console.error('Error in showServerDetails:', error);
|
|
146
|
+
const detailsDiv = document.getElementById('serverCategoryDetails');
|
|
147
|
+
if (detailsDiv) {
|
|
148
|
+
detailsDiv.innerHTML = `<p class="text-red-500">Error loading server details: ${error.message}</p>`;
|
|
149
|
+
}
|
|
81
150
|
showToast(`Error loading server details: ${error.message}`, 'error');
|
|
82
151
|
}
|
|
83
|
-
|
|
84
|
-
// Start monitoring installation status
|
|
85
|
-
startRefreshTimer(serverName);
|
|
86
152
|
}
|
|
87
153
|
|
|
88
|
-
// Render tools list
|
|
89
154
|
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
|
-
}
|
|
155
|
+
try {
|
|
156
|
+
const targetResponse = await fetch('/api/targets');
|
|
157
|
+
const targetData = await targetResponse.json();
|
|
158
|
+
const availableTargets = targetData.success ? targetData.data : [];
|
|
97
159
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
160
|
+
if (!serverCategory.feedConfiguration?.mcpServers) {
|
|
161
|
+
return '<p class="text-gray-500">No MCP Servers found for this server.</p>';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const mcpServers = serverCategory.feedConfiguration.mcpServers;
|
|
165
|
+
if (mcpServers.length === 0) {
|
|
166
|
+
return '<p class="text-gray-500">No MCP Servers found for this server.</p>';
|
|
167
|
+
}
|
|
102
168
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
169
|
+
let toolsHtml = `
|
|
170
|
+
<div class="flex justify-between items-center mb-4">
|
|
171
|
+
<h2 class="text-lg font-semibold text-gray-600">MCP Servers</h2>
|
|
172
|
+
</div>`;
|
|
173
|
+
|
|
174
|
+
mcpServers.forEach(mcpServer => {
|
|
175
|
+
const isInstalled = mcpServer.installed;
|
|
176
|
+
const envRequirements = mcpServer.installation?.['env:'] || mcpServer.installation?.env || {};
|
|
177
|
+
const hasEnvRequirements = Object.keys(envRequirements).length > 0;
|
|
178
|
+
|
|
179
|
+
toolsHtml += `
|
|
180
|
+
<div class="server-item-content" data-server-name="${mcpServer.name}">
|
|
181
|
+
<div class="server-item-info" style="width: 100%; box-sizing: border-box;">
|
|
182
|
+
<div class="server-item-header">
|
|
183
|
+
<div class="flex items-center">
|
|
184
|
+
<h5 class="font-semibold text-gray-800">${mcpServer.displayName || mcpServer.name}</h5>
|
|
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
|
+
})() : ''}
|
|
203
|
+
</div>
|
|
204
|
+
<p class="text-sm text-gray-600 mb-1">${mcpServer.description || 'No description'}</p>
|
|
205
|
+
</div>
|
|
206
|
+
<div class="flex flex-col mt-3">
|
|
121
207
|
<span class="text-xs font-semibold mb-2">Client Status:</span>
|
|
122
208
|
<div class="flex flex-wrap gap-2">
|
|
123
209
|
${availableTargets.map(client => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
210
|
+
const status = (serverCategory.installationStatus?.serversStatus[mcpServer.name]?.installedStatus || {})[client];
|
|
211
|
+
const isInstalled = status?.status === 'completed';
|
|
212
|
+
return `
|
|
127
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">
|
|
128
214
|
<svg class="w-3 h-3 mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
129
215
|
${isInstalled
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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
|
+
}
|
|
133
219
|
</svg>
|
|
134
220
|
${client}
|
|
135
221
|
</span>
|
|
136
222
|
`;
|
|
137
|
-
|
|
223
|
+
}).join('')}
|
|
138
224
|
</div>
|
|
139
225
|
</div>
|
|
140
|
-
|
|
226
|
+
<div class="action-buttons">
|
|
227
|
+
${!isInstalled ? `
|
|
228
|
+
<button onclick="event.stopPropagation(); window.showInstallModal('${serverCategory.name}', '${mcpServer.name}')"
|
|
229
|
+
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">
|
|
230
|
+
Setup
|
|
231
|
+
</button>
|
|
232
|
+
` : `
|
|
233
|
+
<button onclick="event.stopPropagation(); window.uninstallTools('${serverCategory.name}', ['${mcpServer.name}'])"
|
|
234
|
+
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">
|
|
235
|
+
Uninstall
|
|
236
|
+
</button>
|
|
237
|
+
`}
|
|
238
|
+
</div>
|
|
239
|
+
${hasEnvRequirements ? `<div class="mt-3 text-xs text-blue-600">
|
|
141
240
|
<svg class="w-3 h-3 inline mr-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
|
142
241
|
<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
242
|
</svg>
|
|
@@ -145,34 +244,21 @@ async function renderServersList(serverCategory) {
|
|
|
145
244
|
</div>` : ''}
|
|
146
245
|
</div>
|
|
147
246
|
</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
|
-
});
|
|
247
|
+
`;
|
|
248
|
+
});
|
|
164
249
|
|
|
165
|
-
|
|
250
|
+
return toolsHtml;
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.error('Error in renderServersList:', error);
|
|
253
|
+
throw error;
|
|
254
|
+
}
|
|
166
255
|
}
|
|
167
256
|
|
|
168
|
-
// Uninstall tools
|
|
169
257
|
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
258
|
try {
|
|
259
|
+
const confirmed = await showConfirm(`Are you sure you want to uninstall ${toolList.length} tool(s)?`);
|
|
260
|
+
if (!confirmed) return;
|
|
261
|
+
|
|
176
262
|
const response = await fetch(`/api/categories/${serverName}/uninstall`, {
|
|
177
263
|
method: 'POST',
|
|
178
264
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -190,23 +276,25 @@ window.uninstallTools = async function (serverName, toolList) {
|
|
|
190
276
|
}
|
|
191
277
|
|
|
192
278
|
showToast('Tools uninstalled successfully!', 'success');
|
|
193
|
-
await fetchServerCategories();
|
|
194
|
-
await showServerDetails(serverName);
|
|
279
|
+
await fetchServerCategories();
|
|
280
|
+
await showServerDetails(serverName);
|
|
195
281
|
} catch (error) {
|
|
196
282
|
console.error('Error uninstalling tools:', error);
|
|
197
283
|
showToast(`Error uninstalling tools: ${error.message}`, 'error');
|
|
198
284
|
}
|
|
199
285
|
}
|
|
200
286
|
|
|
201
|
-
// Make showServerDetails available in window scope and handle async
|
|
202
287
|
window.showServerDetails = async function (serverName) {
|
|
203
288
|
try {
|
|
204
289
|
await showServerDetails(serverName);
|
|
205
290
|
} catch (error) {
|
|
206
|
-
console.error('Error
|
|
207
|
-
document.getElementById('serverCategoryDetails')
|
|
291
|
+
console.error('Error in window.showServerDetails:', error);
|
|
292
|
+
const detailsDiv = document.getElementById('serverCategoryDetails');
|
|
293
|
+
if (detailsDiv) {
|
|
294
|
+
detailsDiv.innerHTML = `<p class="text-red-500">Error loading server details: ${error.message}</p>`;
|
|
295
|
+
}
|
|
208
296
|
showToast(`Error loading server details: ${error.message}`, 'error');
|
|
209
297
|
}
|
|
210
298
|
};
|
|
211
299
|
|
|
212
|
-
export { showServerDetails };
|
|
300
|
+
export { showServerDetails };
|
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';
|
|
@@ -90,6 +92,35 @@ app.get('/api/categories', async (req: Request<{}, {}, {}, ListQueryParams>, res
|
|
|
90
92
|
error: message
|
|
91
93
|
});
|
|
92
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
|
+
|
|
93
124
|
});
|
|
94
125
|
|
|
95
126
|
// Get categories data (including feed configuration)
|