@samanhappy/mcphub 1.0.10 → 1.0.12
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/README.fr.md +1 -0
- package/README.md +3 -0
- package/README.zh.md +1 -0
- package/dist/cli/commands/tools.js +4 -0
- package/dist/cli/commands/tools.js.map +1 -1
- package/dist/controllers/contextCostController.js +24 -0
- package/dist/controllers/contextCostController.js.map +1 -0
- package/dist/controllers/discoveryController.js +203 -0
- package/dist/controllers/discoveryController.js.map +1 -0
- package/dist/controllers/oauthCallbackController.js +3 -8
- package/dist/controllers/oauthCallbackController.js.map +1 -1
- package/dist/controllers/serverController.js +51 -1
- package/dist/controllers/serverController.js.map +1 -1
- package/dist/dao/SystemConfigDaoDbImpl.js +6 -0
- package/dist/dao/SystemConfigDaoDbImpl.js.map +1 -1
- package/dist/db/entities/SystemConfig.js +8 -0
- package/dist/db/entities/SystemConfig.js.map +1 -1
- package/dist/db/repositories/SystemConfigRepository.js +2 -0
- package/dist/db/repositories/SystemConfigRepository.js.map +1 -1
- package/dist/routes/index.js +16 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/services/contextCostService.js +101 -0
- package/dist/services/contextCostService.js.map +1 -0
- package/dist/services/groupService.js +1 -1
- package/dist/services/groupService.js.map +1 -1
- package/dist/services/hostedRuntimeCatalogService.js +2 -1
- package/dist/services/hostedRuntimeCatalogService.js.map +1 -1
- package/dist/services/mcpService.js +266 -104
- package/dist/services/mcpService.js.map +1 -1
- package/dist/services/openApiGeneratorService.js +5 -4
- package/dist/services/openApiGeneratorService.js.map +1 -1
- package/dist/services/smartRoutingService.js +63 -30
- package/dist/services/smartRoutingService.js.map +1 -1
- package/dist/services/toolResultCompressionService.js +360 -0
- package/dist/services/toolResultCompressionService.js.map +1 -0
- package/dist/services/vectorSearchService.js +3 -1
- package/dist/services/vectorSearchService.js.map +1 -1
- package/dist/utils/mcpApps.js +43 -0
- package/dist/utils/mcpApps.js.map +1 -0
- package/dist/utils/migration.js +2 -0
- package/dist/utils/migration.js.map +1 -1
- package/dist/utils/serialization.js +17 -1
- package/dist/utils/serialization.js.map +1 -1
- package/dist/utils/smartRouting.js +6 -0
- package/dist/utils/smartRouting.js.map +1 -1
- package/dist/utils/tokenCost.js +71 -0
- package/dist/utils/tokenCost.js.map +1 -0
- package/frontend/dist/assets/{ActivityPage-RTpGLfzM.js → ActivityPage-BPfkCkM3.js} +2 -2
- package/frontend/dist/assets/{ActivityPage-RTpGLfzM.js.map → ActivityPage-BPfkCkM3.js.map} +1 -1
- package/frontend/dist/assets/{ConfirmDialog-CxlizGia.js → ConfirmDialog-Cag_haxr.js} +2 -2
- package/frontend/dist/assets/{ConfirmDialog-CxlizGia.js.map → ConfirmDialog-Cag_haxr.js.map} +1 -1
- package/frontend/dist/assets/Dashboard-BvEkS4H1.js +2 -0
- package/frontend/dist/assets/Dashboard-BvEkS4H1.js.map +1 -0
- package/frontend/dist/assets/{DeleteDialog-DRbWonMu.js → DeleteDialog-BBfJpiiD.js} +2 -2
- package/frontend/dist/assets/{DeleteDialog-DRbWonMu.js.map → DeleteDialog-BBfJpiiD.js.map} +1 -1
- package/frontend/dist/assets/{EndpointCopy-BtPORuga.js → EndpointCopy-KhSo4Y6F.js} +2 -2
- package/frontend/dist/assets/{EndpointCopy-BtPORuga.js.map → EndpointCopy-KhSo4Y6F.js.map} +1 -1
- package/frontend/dist/assets/GroupsPage-CLkFTxqd.js +33 -0
- package/frontend/dist/assets/GroupsPage-CLkFTxqd.js.map +1 -0
- package/frontend/dist/assets/{LoginPage-Nks21Yj0.js → LoginPage-lM-z_O3X.js} +2 -2
- package/frontend/dist/assets/{LoginPage-Nks21Yj0.js.map → LoginPage-lM-z_O3X.js.map} +1 -1
- package/frontend/dist/assets/{LogsPage-CoupcpK1.js → LogsPage-CS9OFma4.js} +2 -2
- package/frontend/dist/assets/LogsPage-CS9OFma4.js.map +1 -0
- package/frontend/dist/assets/{MarketPage-PwkvXlle.js → MarketPage-9LSDiVvR.js} +2 -2
- package/frontend/dist/assets/{MarketPage-PwkvXlle.js.map → MarketPage-9LSDiVvR.js.map} +1 -1
- package/frontend/dist/assets/{Pagination-BFi-X7qY.js → Pagination-DBAu79mv.js} +2 -2
- package/frontend/dist/assets/{Pagination-BFi-X7qY.js.map → Pagination-DBAu79mv.js.map} +1 -1
- package/frontend/dist/assets/{PromptsPage-DQiX0bAK.js → PromptsPage-CPFRMMgV.js} +2 -2
- package/frontend/dist/assets/{PromptsPage-DQiX0bAK.js.map → PromptsPage-CPFRMMgV.js.map} +1 -1
- package/frontend/dist/assets/{ResourcesPage-Dltmu_Ze.js → ResourcesPage-DJ_7k1MF.js} +2 -2
- package/frontend/dist/assets/{ResourcesPage-Dltmu_Ze.js.map → ResourcesPage-DJ_7k1MF.js.map} +1 -1
- package/frontend/dist/assets/ServersPage-BtPOdp4X.js +37 -0
- package/frontend/dist/assets/ServersPage-BtPOdp4X.js.map +1 -0
- package/frontend/dist/assets/SettingsPage-CyYl7pb8.js +12 -0
- package/frontend/dist/assets/SettingsPage-CyYl7pb8.js.map +1 -0
- package/frontend/dist/assets/{StatusDot-BRb7WUcz.js → StatusDot-CZZGigtR.js} +2 -2
- package/frontend/dist/assets/{StatusDot-BRb7WUcz.js.map → StatusDot-CZZGigtR.js.map} +1 -1
- package/frontend/dist/assets/{ToggleGroup-tIqxkae6.js → ToggleGroup-C24CNPSz.js} +2 -2
- package/frontend/dist/assets/{ToggleGroup-tIqxkae6.js.map → ToggleGroup-C24CNPSz.js.map} +1 -1
- package/frontend/dist/assets/{UsersPage-DNMaUcUn.js → UsersPage-CLXhNpvg.js} +2 -2
- package/frontend/dist/assets/{UsersPage-DNMaUcUn.js.map → UsersPage-CLXhNpvg.js.map} +1 -1
- package/frontend/dist/assets/contextCost-mvvSAnFv.js +2 -0
- package/frontend/dist/assets/contextCost-mvvSAnFv.js.map +1 -0
- package/frontend/dist/assets/{framework-vendor-BUhDPOUZ.js → framework-vendor-DeqnZ0v6.js} +5 -5
- package/frontend/dist/assets/{framework-vendor-BUhDPOUZ.js.map → framework-vendor-DeqnZ0v6.js.map} +1 -1
- package/frontend/dist/assets/i18n-vendor-DP1IRITP.js +10 -0
- package/frontend/dist/assets/i18n-vendor-DP1IRITP.js.map +1 -0
- package/frontend/dist/assets/{icons-vendor-CKgJB3SC.js → icons-vendor-IYX_ppgH.js} +2 -2
- package/frontend/dist/assets/{icons-vendor-CKgJB3SC.js.map → icons-vendor-IYX_ppgH.js.map} +1 -1
- package/frontend/dist/assets/{index-B9E3ygVt.css → index-D8V2fxz_.css} +1 -1
- package/frontend/dist/assets/index-DRcTlhkb.js +3 -0
- package/frontend/dist/assets/index-DRcTlhkb.js.map +1 -0
- package/frontend/dist/assets/{resourceService-BuhqcwTn.js → resourceService-jx5dJGUy.js} +2 -2
- package/frontend/dist/assets/{resourceService-BuhqcwTn.js.map → resourceService-jx5dJGUy.js.map} +1 -1
- package/frontend/dist/assets/useSettingsData-B4hMPWdK.js +2 -0
- package/frontend/dist/assets/{useSettingsData-iQpBXEjX.js.map → useSettingsData-B4hMPWdK.js.map} +1 -1
- package/frontend/dist/assets/{variableDetection-GTKqOf1F.js → variableDetection-Dnh8qFpO.js} +2 -2
- package/frontend/dist/assets/{variableDetection-GTKqOf1F.js.map → variableDetection-Dnh8qFpO.js.map} +1 -1
- package/frontend/dist/index.html +5 -5
- package/package.json +8 -8
- package/frontend/dist/assets/Dashboard-KV-zezVb.js +0 -2
- package/frontend/dist/assets/Dashboard-KV-zezVb.js.map +0 -1
- package/frontend/dist/assets/GroupsPage-BhNYw74w.js +0 -33
- package/frontend/dist/assets/GroupsPage-BhNYw74w.js.map +0 -1
- package/frontend/dist/assets/LogsPage-CoupcpK1.js.map +0 -1
- package/frontend/dist/assets/ServersPage-CcbF8dGi.js +0 -37
- package/frontend/dist/assets/ServersPage-CcbF8dGi.js.map +0 -1
- package/frontend/dist/assets/SettingsPage-BbRB2fCw.js +0 -12
- package/frontend/dist/assets/SettingsPage-BbRB2fCw.js.map +0 -1
- package/frontend/dist/assets/i18n-vendor-Kbr87Ofu.js +0 -2
- package/frontend/dist/assets/i18n-vendor-Kbr87Ofu.js.map +0 -1
- package/frontend/dist/assets/index-C6LZBP3G.js +0 -3
- package/frontend/dist/assets/index-C6LZBP3G.js.map +0 -1
- package/frontend/dist/assets/useServerData-C9R1u5V4.js +0 -2
- package/frontend/dist/assets/useServerData-C9R1u5V4.js.map +0 -1
- package/frontend/dist/assets/useSettingsData-iQpBXEjX.js +0 -2
|
@@ -22,8 +22,10 @@ import { initializeAllOAuthClients } from './oauthService.js';
|
|
|
22
22
|
import { createOAuthProvider } from './mcpOAuthProvider.js';
|
|
23
23
|
import { initSmartRoutingService, getSmartRoutingTools, handleSearchToolsRequest, handleDescribeToolRequest, isSmartRoutingGroup, } from './smartRoutingService.js';
|
|
24
24
|
import { getActivityLoggingService } from './activityLoggingService.js';
|
|
25
|
+
import { maybeCompressToolResult } from './toolResultCompressionService.js';
|
|
25
26
|
import { assertHostedToolAllowed, filterHostedTools, reserveHostedToolCall, settleHostedToolCall, } from './hostedAuthService.js';
|
|
26
27
|
import { formatErrorForLogging, sanitizeStringForLogging, summarizeErrorForLogging, } from '../utils/serialization.js';
|
|
28
|
+
import { MCP_APPS_CAPABILITIES, filterModelVisibleTools, hasMcpAppsCapability, isAppOnlyTool, stripMcpAppsMetadata, } from '../utils/mcpApps.js';
|
|
27
29
|
const servers = {};
|
|
28
30
|
import { setupClientKeepAlive } from './keepAliveService.js';
|
|
29
31
|
/**
|
|
@@ -194,18 +196,26 @@ export const notifyToolChanged = async (name, options) => {
|
|
|
194
196
|
await registerAllTools(false, name, options);
|
|
195
197
|
broadcastToolListChanged();
|
|
196
198
|
};
|
|
197
|
-
|
|
199
|
+
const broadcastListChanged = (listType, sendNotification) => {
|
|
198
200
|
Object.values(servers).forEach((server) => {
|
|
199
|
-
server
|
|
200
|
-
.sendToolListChanged()
|
|
201
|
-
.catch((error) => {
|
|
202
|
-
console.warn('Failed to send tool list changed notification:', error.message);
|
|
203
|
-
})
|
|
201
|
+
sendNotification(server)
|
|
204
202
|
.then(() => {
|
|
205
|
-
console.log(
|
|
203
|
+
console.log(`${listType} list changed notification sent successfully`);
|
|
204
|
+
})
|
|
205
|
+
.catch((error) => {
|
|
206
|
+
console.warn(`Failed to send ${listType} list changed notification:`, error.message);
|
|
206
207
|
});
|
|
207
208
|
});
|
|
208
209
|
};
|
|
210
|
+
export const broadcastToolListChanged = () => {
|
|
211
|
+
broadcastListChanged('tool', (server) => server.sendToolListChanged());
|
|
212
|
+
};
|
|
213
|
+
export const broadcastResourceListChanged = () => {
|
|
214
|
+
broadcastListChanged('resource', (server) => server.sendResourceListChanged());
|
|
215
|
+
};
|
|
216
|
+
export const broadcastPromptListChanged = () => {
|
|
217
|
+
broadcastListChanged('prompt', (server) => server.sendPromptListChanged());
|
|
218
|
+
};
|
|
209
219
|
export const updateServerInfoVisibility = (serverName, visibility) => {
|
|
210
220
|
const serverInfo = getServerByName(serverName);
|
|
211
221
|
if (!serverInfo) {
|
|
@@ -230,8 +240,11 @@ export const syncToolEmbedding = async (serverName, toolName) => {
|
|
|
230
240
|
console.warn(`Tool not found: ${toolName} on server: ${serverName}`);
|
|
231
241
|
return;
|
|
232
242
|
}
|
|
243
|
+
if (isAppOnlyTool(tool)) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
233
246
|
// Save tool as vector embedding for search
|
|
234
|
-
|
|
247
|
+
syncToolsAsVectorEmbeddings(serverName, [tool]).catch((error) => {
|
|
235
248
|
console.warn(`[EMBED_SYNC_ERROR] Failed to sync embedding for tool "${toolName}" on server "${serverName}"`);
|
|
236
249
|
console.error('Error syncing single tool embedding', { serverName, toolName, error });
|
|
237
250
|
});
|
|
@@ -245,26 +258,122 @@ const cleanInputSchema = (schema) => {
|
|
|
245
258
|
delete cleanedSchema.$schema;
|
|
246
259
|
return cleanedSchema;
|
|
247
260
|
};
|
|
261
|
+
export const normalizeToolForCache = (serverName, tool) => {
|
|
262
|
+
return {
|
|
263
|
+
...tool,
|
|
264
|
+
name: `${serverName}${getNameSeparator()}${tool.name}`,
|
|
265
|
+
description: tool.description || '',
|
|
266
|
+
inputSchema: cleanInputSchema(tool.inputSchema || {}),
|
|
267
|
+
};
|
|
268
|
+
};
|
|
269
|
+
const syncToolsAsVectorEmbeddings = async (serverName, tools, options) => {
|
|
270
|
+
const modelVisibleTools = filterModelVisibleTools(tools);
|
|
271
|
+
if (modelVisibleTools.length === 0) {
|
|
272
|
+
await removeServerToolEmbeddings(serverName);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
await saveToolsAsVectorEmbeddings(serverName, modelVisibleTools, options);
|
|
276
|
+
};
|
|
248
277
|
// Normalize prompt payload to satisfy MCP ListPrompts response schema
|
|
249
278
|
const normalizePromptForList = (prompt) => {
|
|
250
279
|
return {
|
|
280
|
+
...prompt,
|
|
251
281
|
name: prompt.name,
|
|
252
282
|
title: prompt.title || prompt.name,
|
|
253
283
|
description: prompt.description || '',
|
|
254
284
|
arguments: Array.isArray(prompt.arguments) ? prompt.arguments : [],
|
|
255
285
|
};
|
|
256
286
|
};
|
|
287
|
+
const normalizePromptForCache = (serverName, prompt) => {
|
|
288
|
+
return normalizePromptForList({
|
|
289
|
+
...prompt,
|
|
290
|
+
name: `${serverName}${getNameSeparator()}${prompt.name}`,
|
|
291
|
+
});
|
|
292
|
+
};
|
|
257
293
|
// Normalize resource payload to avoid nullable DB fields violating MCP schema
|
|
258
294
|
const normalizeResourceForList = (resource) => {
|
|
259
295
|
return {
|
|
296
|
+
...resource,
|
|
260
297
|
uri: resource.uri,
|
|
261
298
|
name: resource.name || '',
|
|
262
299
|
description: resource.description || '',
|
|
263
300
|
mimeType: resource.mimeType || '',
|
|
264
301
|
};
|
|
265
302
|
};
|
|
303
|
+
const normalizeResourceForCache = (resource) => {
|
|
304
|
+
return normalizeResourceForList(resource);
|
|
305
|
+
};
|
|
266
306
|
// Store all server information
|
|
267
307
|
let serverInfos = [];
|
|
308
|
+
export const updateServerToolsCache = (serverInfo, tools, options) => {
|
|
309
|
+
serverInfo.tools = tools.map((tool) => normalizeToolForCache(serverInfo.name, tool));
|
|
310
|
+
syncToolsAsVectorEmbeddings(serverInfo.name, serverInfo.tools, {
|
|
311
|
+
reportProgress: options?.reportEmbeddingProgress === true,
|
|
312
|
+
}).catch(() => {
|
|
313
|
+
console.warn('[EMBED_SYNC_ERROR] Failed to sync tool embeddings');
|
|
314
|
+
});
|
|
315
|
+
};
|
|
316
|
+
const updateServerPromptsCache = (serverInfo, prompts) => {
|
|
317
|
+
serverInfo.prompts = prompts.map((prompt) => normalizePromptForCache(serverInfo.name, prompt));
|
|
318
|
+
};
|
|
319
|
+
const updateServerResourcesCache = (serverInfo, resources) => {
|
|
320
|
+
serverInfo.resources = resources.map(normalizeResourceForCache);
|
|
321
|
+
};
|
|
322
|
+
const logListChangedRefreshError = (listType) => {
|
|
323
|
+
console.warn(`Failed to refresh ${listType} list after upstream notification`);
|
|
324
|
+
};
|
|
325
|
+
const createUpstreamMcpClient = (name, getServerInfo) => {
|
|
326
|
+
return new Client({
|
|
327
|
+
name: `mcp-client-${name}`,
|
|
328
|
+
version: '1.0.0',
|
|
329
|
+
}, {
|
|
330
|
+
capabilities: MCP_APPS_CAPABILITIES,
|
|
331
|
+
listChanged: {
|
|
332
|
+
tools: {
|
|
333
|
+
onChanged: (error, tools) => {
|
|
334
|
+
const serverInfo = getServerInfo();
|
|
335
|
+
if (error) {
|
|
336
|
+
logListChangedRefreshError('tool');
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (!serverInfo || !tools) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
updateServerToolsCache(serverInfo, tools);
|
|
343
|
+
broadcastToolListChanged();
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
prompts: {
|
|
347
|
+
onChanged: (error, prompts) => {
|
|
348
|
+
const serverInfo = getServerInfo();
|
|
349
|
+
if (error) {
|
|
350
|
+
logListChangedRefreshError('prompt');
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (!serverInfo || !prompts) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
updateServerPromptsCache(serverInfo, prompts);
|
|
357
|
+
broadcastPromptListChanged();
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
resources: {
|
|
361
|
+
onChanged: (error, resources) => {
|
|
362
|
+
const serverInfo = getServerInfo();
|
|
363
|
+
if (error) {
|
|
364
|
+
logListChangedRefreshError('resource');
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (!serverInfo || !resources) {
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
updateServerResourcesCache(serverInfo, resources);
|
|
371
|
+
broadcastResourceListChanged();
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
});
|
|
376
|
+
};
|
|
268
377
|
// Normalize and infer server type for safe client display
|
|
269
378
|
const normalizeServerType = (type) => {
|
|
270
379
|
if (!type)
|
|
@@ -679,12 +788,7 @@ const callToolWithReconnect = async (serverInfo, toolParams, options, maxRetries
|
|
|
679
788
|
// Recreate transport using helper function
|
|
680
789
|
const newTransport = await createTransportFromConfig(serverInfo.name, server);
|
|
681
790
|
// Create new client
|
|
682
|
-
const client =
|
|
683
|
-
name: `mcp-client-${serverInfo.name}`,
|
|
684
|
-
version: '1.0.0',
|
|
685
|
-
}, {
|
|
686
|
-
capabilities: {},
|
|
687
|
-
});
|
|
791
|
+
const client = createUpstreamMcpClient(serverInfo.name, () => serverInfo);
|
|
688
792
|
// Reconnect with new transport
|
|
689
793
|
await client.connect(newTransport, serverInfo.options || {});
|
|
690
794
|
// Update server info with new client and transport
|
|
@@ -694,19 +798,7 @@ const callToolWithReconnect = async (serverInfo, toolParams, options, maxRetries
|
|
|
694
798
|
// Reload tools list after reconnection
|
|
695
799
|
try {
|
|
696
800
|
const tools = await client.listTools({}, serverInfo.options || {});
|
|
697
|
-
serverInfo
|
|
698
|
-
name: `${serverInfo.name}${getNameSeparator()}${tool.name}`,
|
|
699
|
-
description: tool.description || '',
|
|
700
|
-
inputSchema: cleanInputSchema(tool.inputSchema || {}),
|
|
701
|
-
}));
|
|
702
|
-
// Save tools as vector embeddings for search
|
|
703
|
-
saveToolsAsVectorEmbeddings(serverInfo.name, serverInfo.tools).catch((error) => {
|
|
704
|
-
console.warn(`[EMBED_SYNC_ERROR] Failed to sync tool embeddings after reconnect for server "${serverInfo.name}"`);
|
|
705
|
-
console.error('Error syncing tool embeddings after reconnect', {
|
|
706
|
-
serverName: serverInfo.name,
|
|
707
|
-
error: summarizeErrorForLogging(error),
|
|
708
|
-
});
|
|
709
|
-
});
|
|
801
|
+
updateServerToolsCache(serverInfo, tools.tools);
|
|
710
802
|
}
|
|
711
803
|
catch (listToolsError) {
|
|
712
804
|
console.warn('Failed to reload tools after reconnection', {
|
|
@@ -850,7 +942,7 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
850
942
|
serverInfo.openApiClient = openApiClient;
|
|
851
943
|
console.log(`Successfully initialized OpenAPI server: ${name} with ${mcpTools.length} tools`);
|
|
852
944
|
// Save tools as vector embeddings for search
|
|
853
|
-
|
|
945
|
+
syncToolsAsVectorEmbeddings(name, mcpTools, {
|
|
854
946
|
reportProgress: options?.reportEmbeddingProgress === true && serverName === name,
|
|
855
947
|
}).catch((error) => {
|
|
856
948
|
console.warn(`[EMBED_SYNC_ERROR] Failed to sync OpenAPI embeddings for server "${name}"`);
|
|
@@ -875,12 +967,8 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
875
967
|
else {
|
|
876
968
|
transport = await createTransportFromConfig(name, expandedConf);
|
|
877
969
|
}
|
|
878
|
-
const
|
|
879
|
-
|
|
880
|
-
version: '1.0.0',
|
|
881
|
-
}, {
|
|
882
|
-
capabilities: {},
|
|
883
|
-
});
|
|
970
|
+
const serverInfoRef = {};
|
|
971
|
+
const client = createUpstreamMcpClient(name, () => serverInfoRef.current);
|
|
884
972
|
// Get request options from server configuration, with fallbacks
|
|
885
973
|
const serverRequestOptions = expandedConf.options || {};
|
|
886
974
|
const defaultRequestTimeout = Number(process.env.DEFAULT_REQUEST_TIMEOUT) || 60000;
|
|
@@ -911,6 +999,7 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
911
999
|
createTime: Date.now(),
|
|
912
1000
|
config: expandedConf, // Store reference to expanded config
|
|
913
1001
|
};
|
|
1002
|
+
serverInfoRef.current = serverInfo;
|
|
914
1003
|
const pendingAuth = expandedConf.oauth?.pendingAuthorization;
|
|
915
1004
|
if (pendingAuth) {
|
|
916
1005
|
serverInfo.status = 'oauth_required';
|
|
@@ -937,20 +1026,8 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
937
1026
|
.listTools({}, initRequestOptions || requestOptions)
|
|
938
1027
|
.then((tools) => {
|
|
939
1028
|
console.log(`Successfully listed ${tools.tools.length} tools for server: ${name}`);
|
|
940
|
-
serverInfo
|
|
941
|
-
|
|
942
|
-
description: tool.description || '',
|
|
943
|
-
inputSchema: cleanInputSchema(tool.inputSchema || {}),
|
|
944
|
-
}));
|
|
945
|
-
// Save tools as vector embeddings for search
|
|
946
|
-
saveToolsAsVectorEmbeddings(name, serverInfo.tools, {
|
|
947
|
-
reportProgress: options?.reportEmbeddingProgress === true && serverName === name,
|
|
948
|
-
}).catch((embeddingError) => {
|
|
949
|
-
console.warn(`[EMBED_SYNC_ERROR] Failed to sync tool embeddings for connected server "${name}"`);
|
|
950
|
-
console.error('Error syncing tool embeddings for connected server', {
|
|
951
|
-
serverName: name,
|
|
952
|
-
error: summarizeErrorForLogging(embeddingError),
|
|
953
|
-
});
|
|
1029
|
+
updateServerToolsCache(serverInfo, tools.tools, {
|
|
1030
|
+
reportEmbeddingProgress: options?.reportEmbeddingProgress === true && serverName === name,
|
|
954
1031
|
});
|
|
955
1032
|
})
|
|
956
1033
|
.catch((error) => {
|
|
@@ -966,12 +1043,7 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
966
1043
|
.listPrompts({}, initRequestOptions || requestOptions)
|
|
967
1044
|
.then((prompts) => {
|
|
968
1045
|
console.log(`Successfully listed ${prompts.prompts.length} prompts for server: ${name}`);
|
|
969
|
-
serverInfo
|
|
970
|
-
name: `${name}${getNameSeparator()}${prompt.name}`,
|
|
971
|
-
title: prompt.title,
|
|
972
|
-
description: prompt.description,
|
|
973
|
-
arguments: prompt.arguments,
|
|
974
|
-
}));
|
|
1046
|
+
updateServerPromptsCache(serverInfo, prompts.prompts);
|
|
975
1047
|
})
|
|
976
1048
|
.catch((error) => {
|
|
977
1049
|
console.error('Failed to list prompts for server', {
|
|
@@ -986,12 +1058,7 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
986
1058
|
.listResources({}, initRequestOptions || requestOptions)
|
|
987
1059
|
.then((resources) => {
|
|
988
1060
|
console.log(`Successfully listed ${resources.resources.length} resources for server: ${name}`);
|
|
989
|
-
serverInfo
|
|
990
|
-
uri: resource.uri,
|
|
991
|
-
name: resource.name,
|
|
992
|
-
description: resource.description,
|
|
993
|
-
mimeType: resource.mimeType,
|
|
994
|
-
}));
|
|
1061
|
+
updateServerResourcesCache(serverInfo, resources.resources);
|
|
995
1062
|
})
|
|
996
1063
|
.catch((error) => {
|
|
997
1064
|
console.error('Failed to list resources for server', {
|
|
@@ -1360,6 +1427,48 @@ export const toggleServerStatus = async (name, enabled) => {
|
|
|
1360
1427
|
return { success: false, message: 'Failed to toggle server status' };
|
|
1361
1428
|
}
|
|
1362
1429
|
};
|
|
1430
|
+
const getMcpAppsRouteContext = async (sessionId, group) => {
|
|
1431
|
+
if (!sessionId ||
|
|
1432
|
+
isSmartRoutingGroup(group) ||
|
|
1433
|
+
!hasMcpAppsCapability(servers[sessionId]?.getClientCapabilities())) {
|
|
1434
|
+
return { enabled: false };
|
|
1435
|
+
}
|
|
1436
|
+
const { filteredServerInfos } = await getFilteredServerInfosForGroup(group);
|
|
1437
|
+
if (filteredServerInfos.length !== 1 ||
|
|
1438
|
+
filteredServerInfos[0].status !== 'connected' ||
|
|
1439
|
+
!filteredServerInfos[0].client) {
|
|
1440
|
+
return { enabled: false };
|
|
1441
|
+
}
|
|
1442
|
+
return {
|
|
1443
|
+
enabled: true,
|
|
1444
|
+
serverInfo: filteredServerInfos[0],
|
|
1445
|
+
};
|
|
1446
|
+
};
|
|
1447
|
+
const normalizeToolNameForServer = (serverName, toolName) => {
|
|
1448
|
+
const prefix = `${serverName}${getNameSeparator()}`;
|
|
1449
|
+
return toolName.startsWith(prefix) ? toolName.substring(prefix.length) : toolName;
|
|
1450
|
+
};
|
|
1451
|
+
const findToolOnServer = (serverInfo, toolName, allowRawName) => {
|
|
1452
|
+
return serverInfo.tools.find((tool) => tool.name === toolName ||
|
|
1453
|
+
(allowRawName && normalizeToolNameForServer(serverInfo.name, tool.name) === toolName));
|
|
1454
|
+
};
|
|
1455
|
+
const assertToolAvailableForRoute = (tool, appsRouteContext) => {
|
|
1456
|
+
if (isAppOnlyTool(tool) && !appsRouteContext.enabled) {
|
|
1457
|
+
throw new Error(`Tool '${tool.name}' is only available to MCP Apps`);
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
const projectToolForDownstream = (serverName, tool, appsRouteContext) => {
|
|
1461
|
+
if (!appsRouteContext.enabled && isAppOnlyTool(tool)) {
|
|
1462
|
+
return undefined;
|
|
1463
|
+
}
|
|
1464
|
+
const projectedTool = appsRouteContext.enabled ? tool : stripMcpAppsMetadata(tool);
|
|
1465
|
+
return {
|
|
1466
|
+
...projectedTool,
|
|
1467
|
+
name: appsRouteContext.enabled
|
|
1468
|
+
? normalizeToolNameForServer(serverName, projectedTool.name)
|
|
1469
|
+
: projectedTool.name,
|
|
1470
|
+
};
|
|
1471
|
+
};
|
|
1363
1472
|
export const handleListToolsRequest = async (_, extra) => {
|
|
1364
1473
|
const sessionId = extra.sessionId || '';
|
|
1365
1474
|
const group = getGroup(sessionId);
|
|
@@ -1370,6 +1479,7 @@ export const handleListToolsRequest = async (_, extra) => {
|
|
|
1370
1479
|
return getSmartRoutingTools(group);
|
|
1371
1480
|
}
|
|
1372
1481
|
const { filteredServerInfos, serverConfigsByName } = await getFilteredServerInfosForGroup(group);
|
|
1482
|
+
const appsRouteContext = await getMcpAppsRouteContext(sessionId, group);
|
|
1373
1483
|
const allTools = [];
|
|
1374
1484
|
for (const serverInfo of filteredServerInfos) {
|
|
1375
1485
|
if (serverInfo.tools && serverInfo.tools.length > 0) {
|
|
@@ -1386,7 +1496,10 @@ export const handleListToolsRequest = async (_, extra) => {
|
|
|
1386
1496
|
description: toolConfig?.description || tool.description, // Use custom description if available
|
|
1387
1497
|
};
|
|
1388
1498
|
});
|
|
1389
|
-
allTools.push(...toolsWithCustomDescriptions)
|
|
1499
|
+
allTools.push(...toolsWithCustomDescriptions.flatMap((tool) => {
|
|
1500
|
+
const projectedTool = projectToolForDownstream(serverInfo.name, tool, appsRouteContext);
|
|
1501
|
+
return projectedTool ? [projectedTool] : [];
|
|
1502
|
+
}));
|
|
1390
1503
|
}
|
|
1391
1504
|
}
|
|
1392
1505
|
return {
|
|
@@ -1405,6 +1518,7 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1405
1518
|
// Fallback to extra for backward compatibility (e.g., direct API calls)
|
|
1406
1519
|
const group = requestContextService.getGroupContext() || extra?.group || getGroup(sessionId) || undefined;
|
|
1407
1520
|
const username = requestContextService.getUsernameContext() || extra?.username || undefined;
|
|
1521
|
+
let appsRouteContext = { enabled: false };
|
|
1408
1522
|
const keyId = bearerKeyContext.keyId || extra?.keyId || undefined;
|
|
1409
1523
|
const keyName = bearerKeyContext.keyName || extra?.keyName || undefined;
|
|
1410
1524
|
const sourceIp = requestContextService.getRequestContext()?.remoteAddress || undefined;
|
|
@@ -1425,6 +1539,7 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1425
1539
|
});
|
|
1426
1540
|
};
|
|
1427
1541
|
try {
|
|
1542
|
+
appsRouteContext = await getMcpAppsRouteContext(sessionId, group);
|
|
1428
1543
|
// Special handling for smart routing tools
|
|
1429
1544
|
if (request.params.name === 'search_tools') {
|
|
1430
1545
|
const { query, limit = 10 } = request.params.arguments || {};
|
|
@@ -1443,7 +1558,10 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1443
1558
|
}
|
|
1444
1559
|
const { arguments: toolArgs } = request.params.arguments || {};
|
|
1445
1560
|
let targetServerInfo;
|
|
1446
|
-
if (
|
|
1561
|
+
if (appsRouteContext.enabled) {
|
|
1562
|
+
targetServerInfo = appsRouteContext.serverInfo;
|
|
1563
|
+
}
|
|
1564
|
+
else if (extra && extra.server) {
|
|
1447
1565
|
targetServerInfo = getServerByName(extra.server);
|
|
1448
1566
|
}
|
|
1449
1567
|
else {
|
|
@@ -1456,10 +1574,11 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1456
1574
|
throw new Error(`No available servers found with tool: ${toolName}`);
|
|
1457
1575
|
}
|
|
1458
1576
|
// Check if the tool exists on the server
|
|
1459
|
-
const
|
|
1460
|
-
if (!
|
|
1577
|
+
const tool = findToolOnServer(targetServerInfo, toolName, appsRouteContext.enabled);
|
|
1578
|
+
if (!tool) {
|
|
1461
1579
|
throw new Error(`Tool '${toolName}' not found on server '${targetServerInfo.name}'`);
|
|
1462
1580
|
}
|
|
1581
|
+
assertToolAvailableForRoute(tool, appsRouteContext);
|
|
1463
1582
|
// Handle OpenAPI servers differently
|
|
1464
1583
|
if (targetServerInfo.openApiClient) {
|
|
1465
1584
|
// For OpenAPI servers, use the OpenAPI client
|
|
@@ -1472,11 +1591,7 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1472
1591
|
arguments: summarizeArgumentsForLogging(finalArgs),
|
|
1473
1592
|
});
|
|
1474
1593
|
// Remove server prefix from tool name if present
|
|
1475
|
-
const
|
|
1476
|
-
const prefix = `${targetServerInfo.name}${separator}`;
|
|
1477
|
-
const cleanToolName = toolName.startsWith(prefix)
|
|
1478
|
-
? toolName.substring(prefix.length)
|
|
1479
|
-
: toolName;
|
|
1594
|
+
const cleanToolName = normalizeToolNameForServer(targetServerInfo.name, toolName);
|
|
1480
1595
|
// Extract passthrough headers from extra or request context
|
|
1481
1596
|
let passthroughHeaders;
|
|
1482
1597
|
let requestHeaders = null;
|
|
@@ -1528,14 +1643,18 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1528
1643
|
keyName,
|
|
1529
1644
|
sourceIp,
|
|
1530
1645
|
});
|
|
1531
|
-
return {
|
|
1646
|
+
return await maybeCompressToolResult({
|
|
1532
1647
|
content: [
|
|
1533
1648
|
{
|
|
1534
1649
|
type: 'text',
|
|
1535
1650
|
text: JSON.stringify(result),
|
|
1536
1651
|
},
|
|
1537
1652
|
],
|
|
1538
|
-
}
|
|
1653
|
+
}, {
|
|
1654
|
+
serverName: targetServerInfo.name,
|
|
1655
|
+
toolName: cleanToolName,
|
|
1656
|
+
group,
|
|
1657
|
+
});
|
|
1539
1658
|
}
|
|
1540
1659
|
// Call the tool on the target server (MCP servers)
|
|
1541
1660
|
const client = targetServerInfo.client;
|
|
@@ -1549,11 +1668,7 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1549
1668
|
serverName: targetServerInfo.name,
|
|
1550
1669
|
arguments: summarizeArgumentsForLogging(finalArgs),
|
|
1551
1670
|
});
|
|
1552
|
-
const
|
|
1553
|
-
const prefix = `${targetServerInfo.name}${separator}`;
|
|
1554
|
-
const cleanToolName = toolName.startsWith(prefix)
|
|
1555
|
-
? toolName.substring(prefix.length)
|
|
1556
|
-
: toolName;
|
|
1671
|
+
const cleanToolName = normalizeToolNameForServer(targetServerInfo.name, toolName);
|
|
1557
1672
|
await reserveHostedIfNeeded(targetServerInfo.name, cleanToolName);
|
|
1558
1673
|
const result = await callToolWithReconnect(targetServerInfo, {
|
|
1559
1674
|
name: cleanToolName,
|
|
@@ -1585,23 +1700,29 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1585
1700
|
sourceIp,
|
|
1586
1701
|
errorMessage: result.isError ? 'Tool returned error response' : undefined,
|
|
1587
1702
|
});
|
|
1588
|
-
return result
|
|
1703
|
+
return await maybeCompressToolResult(result, {
|
|
1704
|
+
serverName: targetServerInfo.name,
|
|
1705
|
+
toolName: cleanToolName,
|
|
1706
|
+
group,
|
|
1707
|
+
});
|
|
1589
1708
|
}
|
|
1590
1709
|
// Regular tool handling
|
|
1591
|
-
const serverInfo =
|
|
1592
|
-
|
|
1710
|
+
const serverInfo = appsRouteContext.enabled
|
|
1711
|
+
? appsRouteContext.serverInfo
|
|
1712
|
+
: getServerByTool(request.params.name);
|
|
1713
|
+
const tool = serverInfo
|
|
1714
|
+
? findToolOnServer(serverInfo, request.params.name, appsRouteContext.enabled)
|
|
1715
|
+
: undefined;
|
|
1716
|
+
if (!serverInfo || !tool) {
|
|
1593
1717
|
throw new Error(`Server not found: ${request.params.name}`);
|
|
1594
1718
|
}
|
|
1719
|
+
assertToolAvailableForRoute(tool, appsRouteContext);
|
|
1595
1720
|
// Handle OpenAPI servers differently
|
|
1596
1721
|
if (serverInfo.openApiClient) {
|
|
1597
1722
|
// For OpenAPI servers, use the OpenAPI client
|
|
1598
1723
|
const openApiClient = serverInfo.openApiClient;
|
|
1599
1724
|
// Remove server prefix from tool name if present
|
|
1600
|
-
const
|
|
1601
|
-
const prefix = `${serverInfo.name}${separator}`;
|
|
1602
|
-
const cleanToolName = request.params.name.startsWith(prefix)
|
|
1603
|
-
? request.params.name.substring(prefix.length)
|
|
1604
|
-
: request.params.name;
|
|
1725
|
+
const cleanToolName = normalizeToolNameForServer(serverInfo.name, request.params.name);
|
|
1605
1726
|
console.log('Invoking OpenAPI tool', {
|
|
1606
1727
|
toolName: cleanToolName,
|
|
1607
1728
|
serverName: serverInfo.name,
|
|
@@ -1659,25 +1780,25 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1659
1780
|
keyName,
|
|
1660
1781
|
sourceIp,
|
|
1661
1782
|
});
|
|
1662
|
-
return {
|
|
1783
|
+
return await maybeCompressToolResult({
|
|
1663
1784
|
content: [
|
|
1664
1785
|
{
|
|
1665
1786
|
type: 'text',
|
|
1666
1787
|
text: JSON.stringify(result),
|
|
1667
1788
|
},
|
|
1668
1789
|
],
|
|
1669
|
-
}
|
|
1790
|
+
}, {
|
|
1791
|
+
serverName: serverInfo.name,
|
|
1792
|
+
toolName: cleanToolName,
|
|
1793
|
+
group,
|
|
1794
|
+
});
|
|
1670
1795
|
}
|
|
1671
1796
|
// Handle MCP servers
|
|
1672
1797
|
const client = serverInfo.client;
|
|
1673
1798
|
if (!client) {
|
|
1674
1799
|
throw new Error(`Client not found for server: ${serverInfo.name}`);
|
|
1675
1800
|
}
|
|
1676
|
-
const
|
|
1677
|
-
const prefix = `${serverInfo.name}${separator}`;
|
|
1678
|
-
const cleanToolName = request.params.name.startsWith(prefix)
|
|
1679
|
-
? request.params.name.substring(prefix.length)
|
|
1680
|
-
: request.params.name;
|
|
1801
|
+
const cleanToolName = normalizeToolNameForServer(serverInfo.name, request.params.name);
|
|
1681
1802
|
await reserveHostedIfNeeded(serverInfo.name, cleanToolName);
|
|
1682
1803
|
const result = await callToolWithReconnect(serverInfo, { ...request.params, name: cleanToolName }, serverInfo.options || {});
|
|
1683
1804
|
await settleHostedIfNeeded({
|
|
@@ -1706,7 +1827,11 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1706
1827
|
sourceIp,
|
|
1707
1828
|
errorMessage: result.isError ? 'Tool returned error response' : undefined,
|
|
1708
1829
|
});
|
|
1709
|
-
return result
|
|
1830
|
+
return await maybeCompressToolResult(result, {
|
|
1831
|
+
serverName: serverInfo.name,
|
|
1832
|
+
toolName: cleanToolName,
|
|
1833
|
+
group,
|
|
1834
|
+
});
|
|
1710
1835
|
}
|
|
1711
1836
|
catch (error) {
|
|
1712
1837
|
console.error('Error handling CallToolRequest', summarizeErrorForLogging(error));
|
|
@@ -1860,6 +1985,7 @@ export const handleListResourcesRequest = async (_, extra) => {
|
|
|
1860
1985
|
const sessionId = extra.sessionId || '';
|
|
1861
1986
|
const group = getGroup(sessionId);
|
|
1862
1987
|
console.log(`Handling ListResourcesRequest for group: ${group}`);
|
|
1988
|
+
const appsRouteContext = await getMcpAppsRouteContext(sessionId, group);
|
|
1863
1989
|
// Start with built-in resources (only enabled ones)
|
|
1864
1990
|
const builtinResources = await getBuiltinResourceDao().findEnabled();
|
|
1865
1991
|
const allResources = builtinResources.map((br) => normalizeResourceForList({
|
|
@@ -1884,10 +2010,13 @@ export const handleListResourcesRequest = async (_, extra) => {
|
|
|
1884
2010
|
// Apply custom descriptions from server configuration
|
|
1885
2011
|
const resourcesWithCustomDescriptions = enabledResources.map((resource) => {
|
|
1886
2012
|
const resourceConfig = serverConfig?.resources?.[resource.uri];
|
|
1887
|
-
|
|
2013
|
+
const normalizedResource = normalizeResourceForList({
|
|
1888
2014
|
...resource,
|
|
1889
2015
|
description: resourceConfig?.description || resource.description,
|
|
1890
2016
|
});
|
|
2017
|
+
return appsRouteContext.enabled
|
|
2018
|
+
? normalizedResource
|
|
2019
|
+
: stripMcpAppsMetadata(normalizedResource);
|
|
1891
2020
|
});
|
|
1892
2021
|
allResources.push(...resourcesWithCustomDescriptions);
|
|
1893
2022
|
}
|
|
@@ -1900,6 +2029,7 @@ export const handleListResourceTemplatesRequest = async (_, extra) => {
|
|
|
1900
2029
|
const sessionId = extra.sessionId || '';
|
|
1901
2030
|
const group = getGroup(sessionId);
|
|
1902
2031
|
console.log(`Handling ListResourceTemplatesRequest for group: ${group}`);
|
|
2032
|
+
const appsRouteContext = await getMcpAppsRouteContext(sessionId, group);
|
|
1903
2033
|
const { filteredServerInfos, serverConfigsByName } = await getFilteredServerInfosForGroup(group, {
|
|
1904
2034
|
requireClient: true,
|
|
1905
2035
|
});
|
|
@@ -1908,15 +2038,21 @@ export const handleListResourceTemplatesRequest = async (_, extra) => {
|
|
|
1908
2038
|
return [];
|
|
1909
2039
|
}
|
|
1910
2040
|
const templates = await serverInfo.client.listResourceTemplates({}, serverInfo.options || {});
|
|
1911
|
-
|
|
2041
|
+
const filteredTemplates = await filterResourceTemplatesByGroup(group, serverInfo.name, templates.resourceTemplates || [], serverConfigsByName.get(serverInfo.name));
|
|
2042
|
+
return appsRouteContext.enabled
|
|
2043
|
+
? filteredTemplates
|
|
2044
|
+
: filteredTemplates.map((template) => stripMcpAppsMetadata(template));
|
|
1912
2045
|
}));
|
|
1913
2046
|
return {
|
|
1914
2047
|
resourceTemplates: results.flatMap((result) => result.status === 'fulfilled' ? result.value : []),
|
|
1915
2048
|
};
|
|
1916
2049
|
};
|
|
1917
|
-
export const handleReadResourceRequest = async (request,
|
|
2050
|
+
export const handleReadResourceRequest = async (request, extra) => {
|
|
1918
2051
|
try {
|
|
1919
2052
|
const { uri } = request.params;
|
|
2053
|
+
const sessionId = extra.sessionId || '';
|
|
2054
|
+
const group = getGroup(sessionId);
|
|
2055
|
+
const appsRouteContext = await getMcpAppsRouteContext(sessionId, group);
|
|
1920
2056
|
// Check built-in resources first
|
|
1921
2057
|
const builtinResource = await getBuiltinResourceDao().findByUri(uri);
|
|
1922
2058
|
if (builtinResource && builtinResource.enabled !== false) {
|
|
@@ -1930,18 +2066,39 @@ export const handleReadResourceRequest = async (request, _extra) => {
|
|
|
1930
2066
|
],
|
|
1931
2067
|
};
|
|
1932
2068
|
}
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
serverInfo.
|
|
1937
|
-
|
|
2069
|
+
const { filteredServerInfos, serverConfigsByName } = await getFilteredServerInfosForGroup(group);
|
|
2070
|
+
let server;
|
|
2071
|
+
for (const serverInfo of filteredServerInfos) {
|
|
2072
|
+
if (serverInfo.status !== 'connected') {
|
|
2073
|
+
continue;
|
|
2074
|
+
}
|
|
2075
|
+
const serverConfig = await getServerDao().findById(serverInfo.name);
|
|
2076
|
+
let enabledResources = serverInfo.resources;
|
|
2077
|
+
if (serverConfig?.resources) {
|
|
2078
|
+
enabledResources = enabledResources.filter((resource) => serverConfig.resources?.[resource.uri]?.enabled !== false);
|
|
2079
|
+
}
|
|
2080
|
+
enabledResources = await filterResourcesByGroup(group, serverInfo.name, enabledResources, serverConfigsByName.get(serverInfo.name));
|
|
2081
|
+
if (enabledResources.some((resource) => resource.uri === uri)) {
|
|
2082
|
+
server = serverInfo;
|
|
2083
|
+
break;
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
if (!server && appsRouteContext.enabled && uri.startsWith('ui://')) {
|
|
2087
|
+
server = appsRouteContext.serverInfo;
|
|
2088
|
+
}
|
|
2089
|
+
if (!server?.client) {
|
|
1938
2090
|
throw new Error(`Resource not found: ${uri}`);
|
|
1939
2091
|
}
|
|
1940
|
-
const result = await server.client
|
|
1941
|
-
if (!result) {
|
|
2092
|
+
const result = await server.client.readResource({ uri });
|
|
2093
|
+
if (!result || !Array.isArray(result.contents)) {
|
|
1942
2094
|
throw new Error(`Failed to read resource: ${uri}`);
|
|
1943
2095
|
}
|
|
1944
|
-
return
|
|
2096
|
+
return appsRouteContext.enabled
|
|
2097
|
+
? result
|
|
2098
|
+
: {
|
|
2099
|
+
...result,
|
|
2100
|
+
contents: result.contents.map((content) => stripMcpAppsMetadata(content)),
|
|
2101
|
+
};
|
|
1945
2102
|
}
|
|
1946
2103
|
catch (error) {
|
|
1947
2104
|
console.error('Error handling ReadResourceRequest', summarizeErrorForLogging(error));
|
|
@@ -1968,7 +2125,12 @@ export const createMcpServer = (name, version, options) => {
|
|
|
1968
2125
|
}
|
|
1969
2126
|
// If no group, use default name (global routing)
|
|
1970
2127
|
const server = new Server({ name: serverName, version }, {
|
|
1971
|
-
capabilities: {
|
|
2128
|
+
capabilities: {
|
|
2129
|
+
tools: { listChanged: true },
|
|
2130
|
+
prompts: { listChanged: true },
|
|
2131
|
+
resources: { listChanged: true },
|
|
2132
|
+
...MCP_APPS_CAPABILITIES,
|
|
2133
|
+
},
|
|
1972
2134
|
...(normalizedOptions.instructions !== undefined
|
|
1973
2135
|
? { instructions: normalizedOptions.instructions }
|
|
1974
2136
|
: {}),
|