@samanhappy/mcphub 0.12.11 → 0.12.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/README.md +2 -1
- package/dist/clients/openapi.js +3 -1
- package/dist/clients/openapi.js.map +1 -1
- package/dist/controllers/groupController.js +11 -9
- package/dist/controllers/groupController.js.map +1 -1
- package/dist/controllers/mcpbController.js +32 -3
- package/dist/controllers/mcpbController.js.map +1 -1
- package/dist/controllers/serverController.js +83 -45
- package/dist/controllers/serverController.js.map +1 -1
- package/dist/dao/BearerKeyDao.js +2 -1
- package/dist/dao/BearerKeyDao.js.map +1 -1
- package/dist/dao/ServerDaoDbImpl.js +36 -21
- package/dist/dao/ServerDaoDbImpl.js.map +1 -1
- package/dist/db/repositories/VectorEmbeddingRepository.js +9 -3
- package/dist/db/repositories/VectorEmbeddingRepository.js.map +1 -1
- package/dist/middlewares/auth.js +16 -14
- package/dist/middlewares/auth.js.map +1 -1
- package/dist/middlewares/index.js +11 -2
- package/dist/middlewares/index.js.map +1 -1
- package/dist/middlewares/userContext.js +4 -5
- package/dist/middlewares/userContext.js.map +1 -1
- package/dist/routes/index.js +3 -12
- package/dist/routes/index.js.map +1 -1
- package/dist/server.js +11 -10
- package/dist/server.js.map +1 -1
- package/dist/services/activityLoggingService.js +4 -2
- package/dist/services/activityLoggingService.js.map +1 -1
- package/dist/services/groupService.js +10 -5
- package/dist/services/groupService.js.map +1 -1
- package/dist/services/logService.js +6 -5
- package/dist/services/logService.js.map +1 -1
- package/dist/services/mcpOAuthProvider.js +4 -56
- package/dist/services/mcpOAuthProvider.js.map +1 -1
- package/dist/services/mcpService.js +382 -127
- package/dist/services/mcpService.js.map +1 -1
- package/dist/services/oauthClientRegistration.js +5 -1
- package/dist/services/oauthClientRegistration.js.map +1 -1
- package/dist/services/oauthServerService.js +3 -2
- package/dist/services/oauthServerService.js.map +1 -1
- package/dist/services/sseService.js +7 -5
- package/dist/services/sseService.js.map +1 -1
- package/dist/services/templateService.js +8 -1
- package/dist/services/templateService.js.map +1 -1
- package/dist/services/vectorSearchService.js +120 -74
- package/dist/services/vectorSearchService.js.map +1 -1
- package/dist/utils/bearerAuth.js +41 -0
- package/dist/utils/bearerAuth.js.map +1 -0
- package/dist/utils/oauthBearer.js +11 -2
- package/dist/utils/oauthBearer.js.map +1 -1
- package/dist/utils/oauthRedirectUri.js +65 -0
- package/dist/utils/oauthRedirectUri.js.map +1 -0
- package/dist/utils/rateLimit.js +23 -0
- package/dist/utils/rateLimit.js.map +1 -0
- package/dist/utils/safeCompare.js +16 -0
- package/dist/utils/safeCompare.js.map +1 -0
- package/dist/utils/serialization.js +156 -1
- package/dist/utils/serialization.js.map +1 -1
- package/dist/utils/serverConfigPersistence.js +175 -0
- package/dist/utils/serverConfigPersistence.js.map +1 -0
- package/frontend/dist/assets/index-BFEyMCq8.css +1 -0
- package/frontend/dist/assets/index-BhBoIoYG.js +323 -0
- package/frontend/dist/assets/index-BhBoIoYG.js.map +1 -0
- package/frontend/dist/assets/{resourceService-OPtBdW1q.js → resourceService-D25G2-Ta.js} +2 -2
- package/frontend/dist/assets/{resourceService-OPtBdW1q.js.map → resourceService-D25G2-Ta.js.map} +1 -1
- package/frontend/dist/index.html +2 -2
- package/package.json +2 -2
- package/frontend/dist/assets/index-DHhMZeA_.js +0 -319
- package/frontend/dist/assets/index-DHhMZeA_.js.map +0 -1
- package/frontend/dist/assets/index-lGQBQ_t6.css +0 -1
|
@@ -2,7 +2,7 @@ import os from 'os';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
6
6
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
7
7
|
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
8
8
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
@@ -12,7 +12,7 @@ import { createFetchWithProxy, getProxyConfigFromEnv } from './proxy.js';
|
|
|
12
12
|
import { expandEnvVars, replaceEnvVars, getNameSeparator } from '../config/index.js';
|
|
13
13
|
import config from '../config/index.js';
|
|
14
14
|
import { getGroup } from './sseService.js';
|
|
15
|
-
import {
|
|
15
|
+
import { getServerConfigsInGroup, getServerConfigInGroup } from './groupService.js';
|
|
16
16
|
import { removeServerToolEmbeddings, saveToolsAsVectorEmbeddings } from './vectorSearchService.js';
|
|
17
17
|
import { OpenAPIClient } from '../clients/openapi.js';
|
|
18
18
|
import { RequestContextService } from './requestContextService.js';
|
|
@@ -22,6 +22,7 @@ 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 { formatErrorForLogging, sanitizeStringForLogging, summarizeErrorForLogging, } from '../utils/serialization.js';
|
|
25
26
|
const servers = {};
|
|
26
27
|
import { setupClientKeepAlive } from './keepAliveService.js';
|
|
27
28
|
/**
|
|
@@ -309,6 +310,149 @@ const getHeaderValue = (headers, name) => {
|
|
|
309
310
|
}
|
|
310
311
|
return undefined;
|
|
311
312
|
};
|
|
313
|
+
const LOG_SUMMARY_LIMIT = 8;
|
|
314
|
+
const getValueTypeForLogging = (value) => {
|
|
315
|
+
if (Array.isArray(value)) {
|
|
316
|
+
return `array(${value.length})`;
|
|
317
|
+
}
|
|
318
|
+
if (value === null) {
|
|
319
|
+
return 'null';
|
|
320
|
+
}
|
|
321
|
+
if (value && typeof value === 'object') {
|
|
322
|
+
return `object(${Object.keys(value).length} keys)`;
|
|
323
|
+
}
|
|
324
|
+
return typeof value;
|
|
325
|
+
};
|
|
326
|
+
const summarizeObjectShapeForLogging = (value) => {
|
|
327
|
+
const entries = Object.entries(value);
|
|
328
|
+
return {
|
|
329
|
+
keyCount: entries.length,
|
|
330
|
+
keys: entries.slice(0, LOG_SUMMARY_LIMIT).map(([key]) => key),
|
|
331
|
+
valueTypes: Object.fromEntries(entries
|
|
332
|
+
.slice(0, LOG_SUMMARY_LIMIT)
|
|
333
|
+
.map(([key, entryValue]) => [key, getValueTypeForLogging(entryValue)])),
|
|
334
|
+
truncated: entries.length > LOG_SUMMARY_LIMIT || undefined,
|
|
335
|
+
};
|
|
336
|
+
};
|
|
337
|
+
export const summarizeArgumentsForLogging = (value) => {
|
|
338
|
+
if (value === undefined) {
|
|
339
|
+
return { present: false };
|
|
340
|
+
}
|
|
341
|
+
if (Array.isArray(value)) {
|
|
342
|
+
return {
|
|
343
|
+
present: true,
|
|
344
|
+
type: 'array',
|
|
345
|
+
length: value.length,
|
|
346
|
+
itemTypes: Array.from(new Set(value.slice(0, LOG_SUMMARY_LIMIT).map(getValueTypeForLogging))),
|
|
347
|
+
truncated: value.length > LOG_SUMMARY_LIMIT || undefined,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
if (value && typeof value === 'object') {
|
|
351
|
+
return {
|
|
352
|
+
present: true,
|
|
353
|
+
type: 'object',
|
|
354
|
+
...summarizeObjectShapeForLogging(value),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
present: true,
|
|
359
|
+
type: getValueTypeForLogging(value),
|
|
360
|
+
};
|
|
361
|
+
};
|
|
362
|
+
const summarizeTextPayloadForLogging = (text) => ({
|
|
363
|
+
textLength: text.length,
|
|
364
|
+
looksLikeJson: /^[[{]/.test(text.trim()) || undefined,
|
|
365
|
+
wasSanitized: sanitizeStringForLogging(text) !== text || undefined,
|
|
366
|
+
});
|
|
367
|
+
const getHttpErrorStatusCode = (error) => {
|
|
368
|
+
if (!error || typeof error !== 'object') {
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
const err = error;
|
|
372
|
+
const code = err.status ?? err.response?.status ?? err.code;
|
|
373
|
+
if (typeof code === 'number' && Number.isFinite(code)) {
|
|
374
|
+
return code;
|
|
375
|
+
}
|
|
376
|
+
if (typeof code === 'string') {
|
|
377
|
+
const parsedCode = Number.parseInt(code, 10);
|
|
378
|
+
return Number.isFinite(parsedCode) ? parsedCode : undefined;
|
|
379
|
+
}
|
|
380
|
+
return undefined;
|
|
381
|
+
};
|
|
382
|
+
const isRecoverableHttp4xxError = (error) => {
|
|
383
|
+
const statusCode = getHttpErrorStatusCode(error);
|
|
384
|
+
if (statusCode !== undefined) {
|
|
385
|
+
return statusCode === 401 || statusCode === 404;
|
|
386
|
+
}
|
|
387
|
+
const message = typeof error?.message === 'string'
|
|
388
|
+
? error.message
|
|
389
|
+
: '';
|
|
390
|
+
return /Error POSTing to endpoint \(HTTP 40[14]/.test(message);
|
|
391
|
+
};
|
|
392
|
+
const summarizeContentItemForLogging = (item) => {
|
|
393
|
+
if (!item || typeof item !== 'object') {
|
|
394
|
+
return { type: getValueTypeForLogging(item) };
|
|
395
|
+
}
|
|
396
|
+
const record = item;
|
|
397
|
+
return {
|
|
398
|
+
type: typeof record.type === 'string' ? record.type : 'object',
|
|
399
|
+
keys: Object.keys(record).slice(0, LOG_SUMMARY_LIMIT),
|
|
400
|
+
text: typeof record.text === 'string' ? summarizeTextPayloadForLogging(record.text) : undefined,
|
|
401
|
+
truncated: Object.keys(record).length > LOG_SUMMARY_LIMIT || undefined,
|
|
402
|
+
};
|
|
403
|
+
};
|
|
404
|
+
export const summarizeToolResultForLogging = (value) => {
|
|
405
|
+
if (!value || typeof value !== 'object') {
|
|
406
|
+
return { type: getValueTypeForLogging(value) };
|
|
407
|
+
}
|
|
408
|
+
const record = value;
|
|
409
|
+
const summary = {
|
|
410
|
+
type: 'object',
|
|
411
|
+
...summarizeObjectShapeForLogging(record),
|
|
412
|
+
};
|
|
413
|
+
if (typeof record.isError === 'boolean') {
|
|
414
|
+
summary.isError = record.isError;
|
|
415
|
+
}
|
|
416
|
+
if (Array.isArray(record.content)) {
|
|
417
|
+
summary.contentCount = record.content.length;
|
|
418
|
+
summary.content = record.content
|
|
419
|
+
.slice(0, LOG_SUMMARY_LIMIT)
|
|
420
|
+
.map((item) => summarizeContentItemForLogging(item));
|
|
421
|
+
summary.contentTruncated = record.content.length > LOG_SUMMARY_LIMIT || undefined;
|
|
422
|
+
}
|
|
423
|
+
return summary;
|
|
424
|
+
};
|
|
425
|
+
const summarizeToolRequestForLogging = (params) => ({
|
|
426
|
+
name: typeof params?.name === 'string' ? params.name : 'unknown',
|
|
427
|
+
arguments: summarizeArgumentsForLogging(params?.arguments),
|
|
428
|
+
});
|
|
429
|
+
const summarizePromptForLogging = (prompt) => {
|
|
430
|
+
if (!prompt || typeof prompt !== 'object') {
|
|
431
|
+
return { type: getValueTypeForLogging(prompt) };
|
|
432
|
+
}
|
|
433
|
+
const record = prompt;
|
|
434
|
+
const summary = {
|
|
435
|
+
type: 'object',
|
|
436
|
+
...summarizeObjectShapeForLogging(record),
|
|
437
|
+
};
|
|
438
|
+
if (Array.isArray(record.messages)) {
|
|
439
|
+
const messages = record.messages;
|
|
440
|
+
summary.messageCount = messages.length;
|
|
441
|
+
summary.messages = messages.slice(0, LOG_SUMMARY_LIMIT).map((message) => ({
|
|
442
|
+
role: typeof message.role === 'string' ? message.role : undefined,
|
|
443
|
+
contentType: message.content && typeof message.content === 'object'
|
|
444
|
+
? message.content.type
|
|
445
|
+
: getValueTypeForLogging(message.content),
|
|
446
|
+
text: message.content &&
|
|
447
|
+
typeof message.content === 'object' &&
|
|
448
|
+
typeof message.content.text === 'string'
|
|
449
|
+
? summarizeTextPayloadForLogging(String(message.content.text))
|
|
450
|
+
: undefined,
|
|
451
|
+
}));
|
|
452
|
+
summary.messagesTruncated = messages.length > LOG_SUMMARY_LIMIT || undefined;
|
|
453
|
+
}
|
|
454
|
+
return summary;
|
|
455
|
+
};
|
|
312
456
|
export const collectPassthroughHeaders = (requestHeaders, passthroughHeaderNames) => {
|
|
313
457
|
if (!requestHeaders || !Array.isArray(passthroughHeaderNames) || passthroughHeaderNames.length === 0) {
|
|
314
458
|
return {};
|
|
@@ -422,7 +566,7 @@ export const createTransportFromConfig = async (name, conf) => {
|
|
|
422
566
|
const { command: finalCommand, args: finalArgs } = wrapWithProxychains(name, conf.command, replaceEnvVars(conf.args), conf.proxy);
|
|
423
567
|
// Create STDIO transport with potentially wrapped command
|
|
424
568
|
transport = new StdioClientTransport({
|
|
425
|
-
cwd:
|
|
569
|
+
cwd: process.cwd(),
|
|
426
570
|
command: finalCommand,
|
|
427
571
|
args: finalArgs,
|
|
428
572
|
env: env,
|
|
@@ -450,8 +594,7 @@ const callToolWithReconnect = async (serverInfo, toolParams, options, maxRetries
|
|
|
450
594
|
return result;
|
|
451
595
|
}
|
|
452
596
|
catch (error) {
|
|
453
|
-
|
|
454
|
-
const isHttp40xError = error?.message?.startsWith?.('Error POSTing to endpoint (HTTP 40');
|
|
597
|
+
const isHttp40xError = isRecoverableHttp4xxError(error);
|
|
455
598
|
// Only retry for StreamableHTTPClientTransport
|
|
456
599
|
const isStreamableHttp = serverInfo.transport instanceof StreamableHTTPClientTransport;
|
|
457
600
|
const isSSE = serverInfo.transport instanceof SSEClientTransport;
|
|
@@ -499,12 +642,15 @@ const callToolWithReconnect = async (serverInfo, toolParams, options, maxRetries
|
|
|
499
642
|
console.warn(`[EMBED_SYNC_ERROR] Failed to sync tool embeddings after reconnect for server "${serverInfo.name}"`);
|
|
500
643
|
console.error('Error syncing tool embeddings after reconnect', {
|
|
501
644
|
serverName: serverInfo.name,
|
|
502
|
-
error,
|
|
645
|
+
error: summarizeErrorForLogging(error),
|
|
503
646
|
});
|
|
504
647
|
});
|
|
505
648
|
}
|
|
506
649
|
catch (listToolsError) {
|
|
507
|
-
console.warn(
|
|
650
|
+
console.warn('Failed to reload tools after reconnection', {
|
|
651
|
+
serverName: serverInfo.name,
|
|
652
|
+
error: summarizeErrorForLogging(listToolsError),
|
|
653
|
+
});
|
|
508
654
|
// Continue anyway, as the connection might still work for the current tool
|
|
509
655
|
}
|
|
510
656
|
console.log(`Successfully reconnected to server: ${serverInfo.name}`);
|
|
@@ -514,10 +660,10 @@ const callToolWithReconnect = async (serverInfo, toolParams, options, maxRetries
|
|
|
514
660
|
catch (reconnectError) {
|
|
515
661
|
console.error('Failed to reconnect to server', {
|
|
516
662
|
serverName: serverInfo.name,
|
|
517
|
-
error: reconnectError,
|
|
663
|
+
error: summarizeErrorForLogging(reconnectError),
|
|
518
664
|
});
|
|
519
665
|
serverInfo.status = 'disconnected';
|
|
520
|
-
serverInfo.error = `Failed to reconnect: ${reconnectError}`;
|
|
666
|
+
serverInfo.error = `Failed to reconnect: ${formatErrorForLogging(reconnectError)}`;
|
|
521
667
|
// If this was the last attempt, throw the original error
|
|
522
668
|
if (attempt === maxRetries) {
|
|
523
669
|
throw error;
|
|
@@ -624,15 +770,21 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
624
770
|
reportProgress: options?.reportEmbeddingProgress === true && serverName === name,
|
|
625
771
|
}).catch((error) => {
|
|
626
772
|
console.warn(`[EMBED_SYNC_ERROR] Failed to sync OpenAPI embeddings for server "${name}"`);
|
|
627
|
-
console.error('Error syncing OpenAPI tool embeddings', {
|
|
773
|
+
console.error('Error syncing OpenAPI tool embeddings', {
|
|
774
|
+
serverName: name,
|
|
775
|
+
error: summarizeErrorForLogging(error),
|
|
776
|
+
});
|
|
628
777
|
});
|
|
629
778
|
continue;
|
|
630
779
|
}
|
|
631
780
|
catch (error) {
|
|
632
|
-
console.error('Failed to initialize OpenAPI server', {
|
|
781
|
+
console.error('Failed to initialize OpenAPI server', {
|
|
782
|
+
serverName: name,
|
|
783
|
+
error: summarizeErrorForLogging(error),
|
|
784
|
+
});
|
|
633
785
|
// Update the already pushed server info with error status
|
|
634
786
|
serverInfo.status = 'disconnected';
|
|
635
|
-
serverInfo.error = `Failed to initialize OpenAPI server: ${error}`;
|
|
787
|
+
serverInfo.error = `Failed to initialize OpenAPI server: ${formatErrorForLogging(error)}`;
|
|
636
788
|
continue;
|
|
637
789
|
}
|
|
638
790
|
}
|
|
@@ -688,7 +840,7 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
688
840
|
.then(() => {
|
|
689
841
|
console.log(`Successfully connected client for server: ${name}`);
|
|
690
842
|
const capabilities = client.getServerCapabilities();
|
|
691
|
-
console.log(
|
|
843
|
+
console.log('Server capabilities', JSON.stringify(capabilities));
|
|
692
844
|
let dataError = null;
|
|
693
845
|
if (capabilities?.tools) {
|
|
694
846
|
client
|
|
@@ -707,12 +859,15 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
707
859
|
console.warn(`[EMBED_SYNC_ERROR] Failed to sync tool embeddings for connected server "${name}"`);
|
|
708
860
|
console.error('Error syncing tool embeddings for connected server', {
|
|
709
861
|
serverName: name,
|
|
710
|
-
error: embeddingError,
|
|
862
|
+
error: summarizeErrorForLogging(embeddingError),
|
|
711
863
|
});
|
|
712
864
|
});
|
|
713
865
|
})
|
|
714
866
|
.catch((error) => {
|
|
715
|
-
console.error(
|
|
867
|
+
console.error('Failed to list tools for server', {
|
|
868
|
+
serverName: name,
|
|
869
|
+
error: summarizeErrorForLogging(error),
|
|
870
|
+
});
|
|
716
871
|
dataError = error;
|
|
717
872
|
});
|
|
718
873
|
}
|
|
@@ -729,7 +884,10 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
729
884
|
}));
|
|
730
885
|
})
|
|
731
886
|
.catch((error) => {
|
|
732
|
-
console.error(
|
|
887
|
+
console.error('Failed to list prompts for server', {
|
|
888
|
+
serverName: name,
|
|
889
|
+
error: summarizeErrorForLogging(error),
|
|
890
|
+
});
|
|
733
891
|
dataError = error;
|
|
734
892
|
});
|
|
735
893
|
}
|
|
@@ -746,7 +904,10 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
746
904
|
}));
|
|
747
905
|
})
|
|
748
906
|
.catch((error) => {
|
|
749
|
-
console.error(
|
|
907
|
+
console.error('Failed to list resources for server', {
|
|
908
|
+
serverName: name,
|
|
909
|
+
error: summarizeErrorForLogging(error),
|
|
910
|
+
});
|
|
750
911
|
dataError = error;
|
|
751
912
|
});
|
|
752
913
|
}
|
|
@@ -754,11 +915,14 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
754
915
|
serverInfo.status = 'connected';
|
|
755
916
|
serverInfo.error = null;
|
|
756
917
|
// Set up keep-alive ping for SSE connections via shared service
|
|
757
|
-
setupClientKeepAlive(serverInfo, expandedConf).catch((e) => console.warn('Keepalive setup failed', {
|
|
918
|
+
setupClientKeepAlive(serverInfo, expandedConf).catch((e) => console.warn('Keepalive setup failed', {
|
|
919
|
+
serverName: name,
|
|
920
|
+
error: summarizeErrorForLogging(e),
|
|
921
|
+
}));
|
|
758
922
|
}
|
|
759
923
|
else {
|
|
760
924
|
serverInfo.status = 'disconnected';
|
|
761
|
-
serverInfo.error = `Failed to list data: ${dataError}
|
|
925
|
+
serverInfo.error = `Failed to list data: ${formatErrorForLogging(dataError)}`;
|
|
762
926
|
}
|
|
763
927
|
})
|
|
764
928
|
.catch(async (error) => {
|
|
@@ -776,10 +940,13 @@ export const initializeClientsFromSettings = async (isInit, serverName, options)
|
|
|
776
940
|
serverInfo.error = null;
|
|
777
941
|
}
|
|
778
942
|
else {
|
|
779
|
-
console.error(
|
|
943
|
+
console.error('Failed to connect client for server', {
|
|
944
|
+
serverName: name,
|
|
945
|
+
error: summarizeErrorForLogging(error),
|
|
946
|
+
});
|
|
780
947
|
// Other connection errors
|
|
781
948
|
serverInfo.status = 'disconnected';
|
|
782
|
-
serverInfo.error = `Failed to connect: ${error
|
|
949
|
+
serverInfo.error = `Failed to connect: ${formatErrorForLogging(error)}`;
|
|
783
950
|
}
|
|
784
951
|
});
|
|
785
952
|
console.log(`Initialized client for server: ${name}`);
|
|
@@ -1067,7 +1234,7 @@ export const toggleServerStatus = async (name, enabled) => {
|
|
|
1067
1234
|
catch (embeddingError) {
|
|
1068
1235
|
console.warn('Failed to remove embeddings for server', {
|
|
1069
1236
|
serverName: name,
|
|
1070
|
-
error: embeddingError,
|
|
1237
|
+
error: summarizeErrorForLogging(embeddingError),
|
|
1071
1238
|
});
|
|
1072
1239
|
}
|
|
1073
1240
|
}
|
|
@@ -1080,7 +1247,7 @@ export const toggleServerStatus = async (name, enabled) => {
|
|
|
1080
1247
|
catch (reconnectError) {
|
|
1081
1248
|
console.warn('Failed to reconnect server during enable', {
|
|
1082
1249
|
serverName: name,
|
|
1083
|
-
error: reconnectError,
|
|
1250
|
+
error: summarizeErrorForLogging(reconnectError),
|
|
1084
1251
|
});
|
|
1085
1252
|
}
|
|
1086
1253
|
}
|
|
@@ -1100,32 +1267,14 @@ export const handleListToolsRequest = async (_, extra) => {
|
|
|
1100
1267
|
if (isSmartRoutingGroup(group)) {
|
|
1101
1268
|
return getSmartRoutingTools(group);
|
|
1102
1269
|
}
|
|
1103
|
-
|
|
1104
|
-
const filteredServerInfos = [];
|
|
1105
|
-
for (const serverInfo of getDataService().filterData(serverInfos)) {
|
|
1106
|
-
if (serverInfo.enabled === false)
|
|
1107
|
-
continue;
|
|
1108
|
-
if (!group) {
|
|
1109
|
-
filteredServerInfos.push(serverInfo);
|
|
1110
|
-
continue;
|
|
1111
|
-
}
|
|
1112
|
-
const serversInGroup = await getServersInGroup(group);
|
|
1113
|
-
if (!serversInGroup || serversInGroup.length === 0) {
|
|
1114
|
-
if (serverInfo.name === group)
|
|
1115
|
-
filteredServerInfos.push(serverInfo);
|
|
1116
|
-
continue;
|
|
1117
|
-
}
|
|
1118
|
-
if (serversInGroup.includes(serverInfo.name)) {
|
|
1119
|
-
filteredServerInfos.push(serverInfo);
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1270
|
+
const { filteredServerInfos, serverConfigsByName } = await getFilteredServerInfosForGroup(group);
|
|
1122
1271
|
const allTools = [];
|
|
1123
1272
|
for (const serverInfo of filteredServerInfos) {
|
|
1124
1273
|
if (serverInfo.tools && serverInfo.tools.length > 0) {
|
|
1125
1274
|
// Filter tools based on server configuration
|
|
1126
1275
|
let tools = await filterToolsByConfig(serverInfo.name, serverInfo.tools);
|
|
1127
1276
|
// If this is a group request, apply group-level tool filtering
|
|
1128
|
-
tools = await filterToolsByGroup(group, serverInfo.name, tools);
|
|
1277
|
+
tools = await filterToolsByGroup(group, serverInfo.name, tools, serverConfigsByName.get(serverInfo.name));
|
|
1129
1278
|
// Apply custom descriptions from server configuration
|
|
1130
1279
|
const serverConfig = await getServerDao().findById(serverInfo.name);
|
|
1131
1280
|
const toolsWithCustomDescriptions = tools.map((tool) => {
|
|
@@ -1143,7 +1292,7 @@ export const handleListToolsRequest = async (_, extra) => {
|
|
|
1143
1292
|
};
|
|
1144
1293
|
};
|
|
1145
1294
|
export const handleCallToolRequest = async (request, extra) => {
|
|
1146
|
-
console.log(
|
|
1295
|
+
console.log('Handling CallToolRequest for tool', summarizeToolRequestForLogging(request.params));
|
|
1147
1296
|
const startTime = Date.now();
|
|
1148
1297
|
const activityLogger = getActivityLoggingService();
|
|
1149
1298
|
// Get request context for activity logging
|
|
@@ -1197,7 +1346,11 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1197
1346
|
const openApiClient = targetServerInfo.openApiClient;
|
|
1198
1347
|
// Use toolArgs if it has properties, otherwise fallback to request.params.arguments
|
|
1199
1348
|
const finalArgs = toolArgs && typeof toolArgs === 'object' ? toolArgs : {};
|
|
1200
|
-
console.log(
|
|
1349
|
+
console.log('Invoking OpenAPI tool', {
|
|
1350
|
+
toolName,
|
|
1351
|
+
serverName: targetServerInfo.name,
|
|
1352
|
+
arguments: summarizeArgumentsForLogging(finalArgs),
|
|
1353
|
+
});
|
|
1201
1354
|
// Remove server prefix from tool name if present
|
|
1202
1355
|
const separator = getNameSeparator();
|
|
1203
1356
|
const prefix = `${targetServerInfo.name}${separator}`;
|
|
@@ -1229,7 +1382,11 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1229
1382
|
}
|
|
1230
1383
|
}
|
|
1231
1384
|
const result = await openApiClient.callTool(cleanToolName, finalArgs, passthroughHeaders);
|
|
1232
|
-
console.log(
|
|
1385
|
+
console.log('OpenAPI tool invocation result', {
|
|
1386
|
+
serverName: targetServerInfo.name,
|
|
1387
|
+
toolName: cleanToolName,
|
|
1388
|
+
result: summarizeToolResultForLogging(result),
|
|
1389
|
+
});
|
|
1233
1390
|
// Log successful activity
|
|
1234
1391
|
const duration = Date.now() - startTime;
|
|
1235
1392
|
await activityLogger.logToolCall({
|
|
@@ -1237,8 +1394,8 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1237
1394
|
tool: cleanToolName,
|
|
1238
1395
|
duration,
|
|
1239
1396
|
status: 'success',
|
|
1240
|
-
input: finalArgs,
|
|
1241
|
-
output: result,
|
|
1397
|
+
input: summarizeArgumentsForLogging(finalArgs),
|
|
1398
|
+
output: summarizeToolResultForLogging(result),
|
|
1242
1399
|
group,
|
|
1243
1400
|
keyId,
|
|
1244
1401
|
keyName,
|
|
@@ -1259,7 +1416,11 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1259
1416
|
}
|
|
1260
1417
|
// Use toolArgs if it has properties, otherwise fallback to request.params.arguments
|
|
1261
1418
|
const finalArgs = toolArgs && typeof toolArgs === 'object' ? toolArgs : {};
|
|
1262
|
-
console.log(
|
|
1419
|
+
console.log('Invoking tool', {
|
|
1420
|
+
toolName,
|
|
1421
|
+
serverName: targetServerInfo.name,
|
|
1422
|
+
arguments: summarizeArgumentsForLogging(finalArgs),
|
|
1423
|
+
});
|
|
1263
1424
|
const separator = getNameSeparator();
|
|
1264
1425
|
const prefix = `${targetServerInfo.name}${separator}`;
|
|
1265
1426
|
const cleanToolName = toolName.startsWith(prefix)
|
|
@@ -1269,7 +1430,11 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1269
1430
|
name: cleanToolName,
|
|
1270
1431
|
arguments: finalArgs,
|
|
1271
1432
|
}, targetServerInfo.options || {});
|
|
1272
|
-
console.log(
|
|
1433
|
+
console.log('Tool invocation result', {
|
|
1434
|
+
serverName: targetServerInfo.name,
|
|
1435
|
+
toolName: cleanToolName,
|
|
1436
|
+
result: summarizeToolResultForLogging(result),
|
|
1437
|
+
});
|
|
1273
1438
|
// Log successful activity
|
|
1274
1439
|
const duration = Date.now() - startTime;
|
|
1275
1440
|
await activityLogger.logToolCall({
|
|
@@ -1277,14 +1442,12 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1277
1442
|
tool: cleanToolName,
|
|
1278
1443
|
duration,
|
|
1279
1444
|
status: result.isError ? 'error' : 'success',
|
|
1280
|
-
input: finalArgs,
|
|
1281
|
-
output: result,
|
|
1445
|
+
input: summarizeArgumentsForLogging(finalArgs),
|
|
1446
|
+
output: summarizeToolResultForLogging(result),
|
|
1282
1447
|
group,
|
|
1283
1448
|
keyId,
|
|
1284
1449
|
keyName,
|
|
1285
|
-
errorMessage: result.isError
|
|
1286
|
-
? String(result.content?.[0]?.text || 'Unknown error')
|
|
1287
|
-
: undefined,
|
|
1450
|
+
errorMessage: result.isError ? 'Tool returned error response' : undefined,
|
|
1288
1451
|
});
|
|
1289
1452
|
return result;
|
|
1290
1453
|
}
|
|
@@ -1303,7 +1466,11 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1303
1466
|
const cleanToolName = request.params.name.startsWith(prefix)
|
|
1304
1467
|
? request.params.name.substring(prefix.length)
|
|
1305
1468
|
: request.params.name;
|
|
1306
|
-
console.log(
|
|
1469
|
+
console.log('Invoking OpenAPI tool', {
|
|
1470
|
+
toolName: cleanToolName,
|
|
1471
|
+
serverName: serverInfo.name,
|
|
1472
|
+
arguments: summarizeArgumentsForLogging(request.params.arguments),
|
|
1473
|
+
});
|
|
1307
1474
|
// Extract passthrough headers from extra or request context
|
|
1308
1475
|
let passthroughHeaders;
|
|
1309
1476
|
let requestHeaders = null;
|
|
@@ -1329,7 +1496,11 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1329
1496
|
}
|
|
1330
1497
|
}
|
|
1331
1498
|
const result = await openApiClient.callTool(cleanToolName, request.params.arguments || {}, passthroughHeaders);
|
|
1332
|
-
console.log(
|
|
1499
|
+
console.log('OpenAPI tool invocation result', {
|
|
1500
|
+
serverName: serverInfo.name,
|
|
1501
|
+
toolName: cleanToolName,
|
|
1502
|
+
result: summarizeToolResultForLogging(result),
|
|
1503
|
+
});
|
|
1333
1504
|
// Log successful activity
|
|
1334
1505
|
const duration = Date.now() - startTime;
|
|
1335
1506
|
await activityLogger.logToolCall({
|
|
@@ -1337,8 +1508,8 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1337
1508
|
tool: cleanToolName,
|
|
1338
1509
|
duration,
|
|
1339
1510
|
status: 'success',
|
|
1340
|
-
input: request.params.arguments,
|
|
1341
|
-
output: result,
|
|
1511
|
+
input: summarizeArgumentsForLogging(request.params.arguments),
|
|
1512
|
+
output: summarizeToolResultForLogging(result),
|
|
1342
1513
|
group,
|
|
1343
1514
|
keyId,
|
|
1344
1515
|
keyName,
|
|
@@ -1363,7 +1534,11 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1363
1534
|
? request.params.name.substring(prefix.length)
|
|
1364
1535
|
: request.params.name;
|
|
1365
1536
|
const result = await callToolWithReconnect(serverInfo, { ...request.params, name: cleanToolName }, serverInfo.options || {});
|
|
1366
|
-
console.log(
|
|
1537
|
+
console.log('Tool call result', {
|
|
1538
|
+
serverName: serverInfo.name,
|
|
1539
|
+
toolName: cleanToolName,
|
|
1540
|
+
result: summarizeToolResultForLogging(result),
|
|
1541
|
+
});
|
|
1367
1542
|
// Log successful activity
|
|
1368
1543
|
const duration = Date.now() - startTime;
|
|
1369
1544
|
await activityLogger.logToolCall({
|
|
@@ -1371,19 +1546,17 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1371
1546
|
tool: cleanToolName,
|
|
1372
1547
|
duration,
|
|
1373
1548
|
status: result.isError ? 'error' : 'success',
|
|
1374
|
-
input: request.params.arguments,
|
|
1375
|
-
output: result,
|
|
1549
|
+
input: summarizeArgumentsForLogging(request.params.arguments),
|
|
1550
|
+
output: summarizeToolResultForLogging(result),
|
|
1376
1551
|
group,
|
|
1377
1552
|
keyId,
|
|
1378
1553
|
keyName,
|
|
1379
|
-
errorMessage: result.isError
|
|
1380
|
-
? String(result.content?.[0]?.text || 'Unknown error')
|
|
1381
|
-
: undefined,
|
|
1554
|
+
errorMessage: result.isError ? 'Tool returned error response' : undefined,
|
|
1382
1555
|
});
|
|
1383
1556
|
return result;
|
|
1384
1557
|
}
|
|
1385
1558
|
catch (error) {
|
|
1386
|
-
console.error(
|
|
1559
|
+
console.error('Error handling CallToolRequest', summarizeErrorForLogging(error));
|
|
1387
1560
|
// Log error activity
|
|
1388
1561
|
const duration = Date.now() - startTime;
|
|
1389
1562
|
const toolName = request.params?.name || 'unknown';
|
|
@@ -1393,17 +1566,18 @@ export const handleCallToolRequest = async (request, extra) => {
|
|
|
1393
1566
|
tool: toolName,
|
|
1394
1567
|
duration,
|
|
1395
1568
|
status: 'error',
|
|
1396
|
-
input: request.params?.arguments,
|
|
1569
|
+
input: summarizeArgumentsForLogging(request.params?.arguments),
|
|
1397
1570
|
group,
|
|
1398
1571
|
keyId,
|
|
1399
1572
|
keyName,
|
|
1400
|
-
errorMessage:
|
|
1573
|
+
errorMessage: formatErrorForLogging(error),
|
|
1401
1574
|
});
|
|
1575
|
+
const safeErrorText = formatErrorForLogging(error);
|
|
1402
1576
|
return {
|
|
1403
1577
|
content: [
|
|
1404
1578
|
{
|
|
1405
1579
|
type: 'text',
|
|
1406
|
-
text: `Error: ${
|
|
1580
|
+
text: `Error: ${safeErrorText}`,
|
|
1407
1581
|
},
|
|
1408
1582
|
],
|
|
1409
1583
|
isError: true,
|
|
@@ -1454,21 +1628,25 @@ export const handleGetPromptRequest = async (request, extra) => {
|
|
|
1454
1628
|
arguments: promptArgs,
|
|
1455
1629
|
};
|
|
1456
1630
|
// Log the final promptParams
|
|
1457
|
-
console.log(
|
|
1631
|
+
console.log('Calling getPrompt with params', {
|
|
1632
|
+
name: cleanPromptName || '',
|
|
1633
|
+
arguments: summarizeArgumentsForLogging(promptArgs),
|
|
1634
|
+
});
|
|
1458
1635
|
const prompt = await server.client?.getPrompt(promptParams);
|
|
1459
|
-
console.log(
|
|
1636
|
+
console.log('Received prompt', summarizePromptForLogging(prompt));
|
|
1460
1637
|
if (!prompt) {
|
|
1461
1638
|
throw new Error(`Prompt not found: ${cleanPromptName}`);
|
|
1462
1639
|
}
|
|
1463
1640
|
return prompt;
|
|
1464
1641
|
}
|
|
1465
1642
|
catch (error) {
|
|
1466
|
-
console.error(
|
|
1643
|
+
console.error('Error handling GetPromptRequest', summarizeErrorForLogging(error));
|
|
1644
|
+
const safeErrorText = formatErrorForLogging(error);
|
|
1467
1645
|
return {
|
|
1468
1646
|
content: [
|
|
1469
1647
|
{
|
|
1470
1648
|
type: 'text',
|
|
1471
|
-
text: `Error: ${
|
|
1649
|
+
text: `Error: ${safeErrorText}`,
|
|
1472
1650
|
},
|
|
1473
1651
|
],
|
|
1474
1652
|
isError: true,
|
|
@@ -1487,25 +1665,7 @@ export const handleListPromptsRequest = async (_, extra) => {
|
|
|
1487
1665
|
description: bp.description,
|
|
1488
1666
|
arguments: bp.arguments,
|
|
1489
1667
|
}));
|
|
1490
|
-
|
|
1491
|
-
const filteredServerInfos = [];
|
|
1492
|
-
for (const serverInfo of getDataService().filterData(serverInfos)) {
|
|
1493
|
-
if (serverInfo.enabled === false)
|
|
1494
|
-
continue;
|
|
1495
|
-
if (!group) {
|
|
1496
|
-
filteredServerInfos.push(serverInfo);
|
|
1497
|
-
continue;
|
|
1498
|
-
}
|
|
1499
|
-
const serversInGroup = await getServersInGroup(group);
|
|
1500
|
-
if (!serversInGroup || serversInGroup.length === 0) {
|
|
1501
|
-
if (serverInfo.name === group)
|
|
1502
|
-
filteredServerInfos.push(serverInfo);
|
|
1503
|
-
continue;
|
|
1504
|
-
}
|
|
1505
|
-
if (serversInGroup.includes(serverInfo.name)) {
|
|
1506
|
-
filteredServerInfos.push(serverInfo);
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1668
|
+
const { filteredServerInfos, serverConfigsByName } = await getFilteredServerInfosForGroup(group);
|
|
1509
1669
|
for (const serverInfo of filteredServerInfos) {
|
|
1510
1670
|
if (serverInfo.prompts && serverInfo.prompts.length > 0) {
|
|
1511
1671
|
// Filter prompts based on server configuration
|
|
@@ -1518,16 +1678,7 @@ export const handleListPromptsRequest = async (_, extra) => {
|
|
|
1518
1678
|
return promptConfig?.enabled !== false;
|
|
1519
1679
|
});
|
|
1520
1680
|
}
|
|
1521
|
-
|
|
1522
|
-
if (group) {
|
|
1523
|
-
const serverConfigInGroup = await getServerConfigInGroup(group, serverInfo.name);
|
|
1524
|
-
if (serverConfigInGroup &&
|
|
1525
|
-
serverConfigInGroup.tools !== 'all' &&
|
|
1526
|
-
Array.isArray(serverConfigInGroup.tools)) {
|
|
1527
|
-
// Note: Group config uses 'tools' field but we're filtering prompts here
|
|
1528
|
-
// This might be a design decision to control access at the server level
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1681
|
+
enabledPrompts = await filterPromptsByGroup(group, serverInfo.name, enabledPrompts, serverConfigsByName.get(serverInfo.name));
|
|
1531
1682
|
// Apply custom descriptions from server configuration
|
|
1532
1683
|
const promptsWithCustomDescriptions = enabledPrompts.map((prompt) => {
|
|
1533
1684
|
const promptConfig = serverConfig?.prompts?.[prompt.name];
|
|
@@ -1555,25 +1706,7 @@ export const handleListResourcesRequest = async (_, extra) => {
|
|
|
1555
1706
|
description: br.description,
|
|
1556
1707
|
mimeType: br.mimeType,
|
|
1557
1708
|
}));
|
|
1558
|
-
|
|
1559
|
-
const filteredServerInfos = [];
|
|
1560
|
-
for (const serverInfo of getDataService().filterData(serverInfos)) {
|
|
1561
|
-
if (serverInfo.enabled === false)
|
|
1562
|
-
continue;
|
|
1563
|
-
if (!group) {
|
|
1564
|
-
filteredServerInfos.push(serverInfo);
|
|
1565
|
-
continue;
|
|
1566
|
-
}
|
|
1567
|
-
const serversInGroup = await getServersInGroup(group);
|
|
1568
|
-
if (!serversInGroup || serversInGroup.length === 0) {
|
|
1569
|
-
if (serverInfo.name === group)
|
|
1570
|
-
filteredServerInfos.push(serverInfo);
|
|
1571
|
-
continue;
|
|
1572
|
-
}
|
|
1573
|
-
if (serversInGroup.includes(serverInfo.name)) {
|
|
1574
|
-
filteredServerInfos.push(serverInfo);
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1709
|
+
const { filteredServerInfos, serverConfigsByName } = await getFilteredServerInfosForGroup(group);
|
|
1577
1710
|
for (const serverInfo of filteredServerInfos) {
|
|
1578
1711
|
if (serverInfo.resources && serverInfo.resources.length > 0) {
|
|
1579
1712
|
// Filter resources based on server configuration
|
|
@@ -1585,6 +1718,7 @@ export const handleListResourcesRequest = async (_, extra) => {
|
|
|
1585
1718
|
return resourceConfig?.enabled !== false;
|
|
1586
1719
|
});
|
|
1587
1720
|
}
|
|
1721
|
+
enabledResources = await filterResourcesByGroup(group, serverInfo.name, enabledResources, serverConfigsByName.get(serverInfo.name));
|
|
1588
1722
|
// Apply custom descriptions from server configuration
|
|
1589
1723
|
const resourcesWithCustomDescriptions = enabledResources.map((resource) => {
|
|
1590
1724
|
const resourceConfig = serverConfig?.resources?.[resource.uri];
|
|
@@ -1600,6 +1734,24 @@ export const handleListResourcesRequest = async (_, extra) => {
|
|
|
1600
1734
|
resources: allResources,
|
|
1601
1735
|
};
|
|
1602
1736
|
};
|
|
1737
|
+
export const handleListResourceTemplatesRequest = async (_, extra) => {
|
|
1738
|
+
const sessionId = extra.sessionId || '';
|
|
1739
|
+
const group = getGroup(sessionId);
|
|
1740
|
+
console.log(`Handling ListResourceTemplatesRequest for group: ${group}`);
|
|
1741
|
+
const { filteredServerInfos, serverConfigsByName } = await getFilteredServerInfosForGroup(group, {
|
|
1742
|
+
requireClient: true,
|
|
1743
|
+
});
|
|
1744
|
+
const results = await Promise.allSettled(filteredServerInfos.map(async (serverInfo) => {
|
|
1745
|
+
if (!serverInfo.client?.listResourceTemplates) {
|
|
1746
|
+
return [];
|
|
1747
|
+
}
|
|
1748
|
+
const templates = await serverInfo.client.listResourceTemplates({}, serverInfo.options || {});
|
|
1749
|
+
return filterResourceTemplatesByGroup(group, serverInfo.name, templates.resourceTemplates || [], serverConfigsByName.get(serverInfo.name));
|
|
1750
|
+
}));
|
|
1751
|
+
return {
|
|
1752
|
+
resourceTemplates: results.flatMap((result) => result.status === 'fulfilled' ? result.value : []),
|
|
1753
|
+
};
|
|
1754
|
+
};
|
|
1603
1755
|
export const handleReadResourceRequest = async (request, _extra) => {
|
|
1604
1756
|
try {
|
|
1605
1757
|
const { uri } = request.params;
|
|
@@ -1630,13 +1782,14 @@ export const handleReadResourceRequest = async (request, _extra) => {
|
|
|
1630
1782
|
return result;
|
|
1631
1783
|
}
|
|
1632
1784
|
catch (error) {
|
|
1633
|
-
console.error(
|
|
1785
|
+
console.error('Error handling ReadResourceRequest', summarizeErrorForLogging(error));
|
|
1786
|
+
const safeErrorText = formatErrorForLogging(error);
|
|
1634
1787
|
return {
|
|
1635
1788
|
contents: [
|
|
1636
1789
|
{
|
|
1637
1790
|
uri: request.params?.uri || '',
|
|
1638
1791
|
mimeType: 'text/plain',
|
|
1639
|
-
text: `Error: ${
|
|
1792
|
+
text: `Error: ${safeErrorText}`,
|
|
1640
1793
|
},
|
|
1641
1794
|
],
|
|
1642
1795
|
};
|
|
@@ -1658,19 +1811,121 @@ export const createMcpServer = (name, version, group) => {
|
|
|
1658
1811
|
server.setRequestHandler(GetPromptRequestSchema, handleGetPromptRequest);
|
|
1659
1812
|
server.setRequestHandler(ListPromptsRequestSchema, handleListPromptsRequest);
|
|
1660
1813
|
server.setRequestHandler(ListResourcesRequestSchema, handleListResourcesRequest);
|
|
1814
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, handleListResourceTemplatesRequest);
|
|
1661
1815
|
server.setRequestHandler(ReadResourceRequestSchema, handleReadResourceRequest);
|
|
1662
1816
|
return server;
|
|
1663
1817
|
};
|
|
1818
|
+
const getFilteredServerInfosForGroup = async (group, options) => {
|
|
1819
|
+
const serverConfigs = group ? await getServerConfigsInGroup(group) : [];
|
|
1820
|
+
const serverNamesInGroup = new Set(serverConfigs.map((serverConfig) => serverConfig.name));
|
|
1821
|
+
const serverConfigsByName = new Map(serverConfigs.map((serverConfig) => [serverConfig.name, serverConfig]));
|
|
1822
|
+
const filteredServerInfos = [];
|
|
1823
|
+
for (const serverInfo of getDataService().filterData(serverInfos)) {
|
|
1824
|
+
if (serverInfo.enabled === false)
|
|
1825
|
+
continue;
|
|
1826
|
+
if (options?.requireClient && !serverInfo.client)
|
|
1827
|
+
continue;
|
|
1828
|
+
if (!group) {
|
|
1829
|
+
filteredServerInfos.push(serverInfo);
|
|
1830
|
+
continue;
|
|
1831
|
+
}
|
|
1832
|
+
if (serverNamesInGroup.size === 0) {
|
|
1833
|
+
if (serverInfo.name === group) {
|
|
1834
|
+
filteredServerInfos.push(serverInfo);
|
|
1835
|
+
}
|
|
1836
|
+
continue;
|
|
1837
|
+
}
|
|
1838
|
+
if (serverNamesInGroup.has(serverInfo.name)) {
|
|
1839
|
+
filteredServerInfos.push(serverInfo);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
return { filteredServerInfos, serverConfigsByName };
|
|
1843
|
+
};
|
|
1844
|
+
const getGroupServerConfig = async (group, serverName, serverConfig) => {
|
|
1845
|
+
if (!group) {
|
|
1846
|
+
return undefined;
|
|
1847
|
+
}
|
|
1848
|
+
return serverConfig ?? getServerConfigInGroup(group, serverName);
|
|
1849
|
+
};
|
|
1664
1850
|
// Filter tools based on group configuration
|
|
1665
|
-
async function filterToolsByGroup(group, serverName, tools) {
|
|
1851
|
+
async function filterToolsByGroup(group, serverName, tools, serverConfig) {
|
|
1666
1852
|
if (group) {
|
|
1667
|
-
const
|
|
1668
|
-
if (
|
|
1853
|
+
const resolvedServerConfig = await getGroupServerConfig(group, serverName, serverConfig);
|
|
1854
|
+
if (resolvedServerConfig &&
|
|
1855
|
+
resolvedServerConfig.tools !== 'all' &&
|
|
1856
|
+
Array.isArray(resolvedServerConfig.tools)) {
|
|
1669
1857
|
// Filter tools based on group configuration
|
|
1670
|
-
const allowedToolNames =
|
|
1858
|
+
const allowedToolNames = resolvedServerConfig.tools.map((toolName) => `${serverName}${getNameSeparator()}${toolName}`);
|
|
1671
1859
|
tools = tools.filter((tool) => allowedToolNames.includes(tool.name));
|
|
1672
1860
|
}
|
|
1673
1861
|
}
|
|
1674
1862
|
return tools;
|
|
1675
1863
|
}
|
|
1864
|
+
const normalizePromptNameForGroup = (serverName, promptName) => {
|
|
1865
|
+
const prefix = `${serverName}${getNameSeparator()}`;
|
|
1866
|
+
return promptName.startsWith(prefix) ? promptName.substring(prefix.length) : promptName;
|
|
1867
|
+
};
|
|
1868
|
+
export async function filterPromptsByGroup(group, serverName, prompts, serverConfig) {
|
|
1869
|
+
if (group) {
|
|
1870
|
+
const resolvedServerConfig = await getGroupServerConfig(group, serverName, serverConfig);
|
|
1871
|
+
if (resolvedServerConfig &&
|
|
1872
|
+
resolvedServerConfig.prompts !== 'all' &&
|
|
1873
|
+
Array.isArray(resolvedServerConfig.prompts)) {
|
|
1874
|
+
const allowedPromptNames = new Set(resolvedServerConfig.prompts);
|
|
1875
|
+
return prompts.filter((prompt) => allowedPromptNames.has(normalizePromptNameForGroup(serverName, prompt.name)));
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
return prompts;
|
|
1879
|
+
}
|
|
1880
|
+
export async function filterResourcesByGroup(group, serverName, resources, serverConfig) {
|
|
1881
|
+
if (group) {
|
|
1882
|
+
const resolvedServerConfig = await getGroupServerConfig(group, serverName, serverConfig);
|
|
1883
|
+
if (resolvedServerConfig &&
|
|
1884
|
+
resolvedServerConfig.resources !== 'all' &&
|
|
1885
|
+
Array.isArray(resolvedServerConfig.resources)) {
|
|
1886
|
+
const allowedResources = new Set(resolvedServerConfig.resources);
|
|
1887
|
+
return resources.filter((resource) => allowedResources.has(resource.uri));
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
return resources;
|
|
1891
|
+
}
|
|
1892
|
+
const resourceTemplateMatchesSelection = (uriTemplate, allowedResources) => {
|
|
1893
|
+
if (allowedResources.has(uriTemplate)) {
|
|
1894
|
+
return true;
|
|
1895
|
+
}
|
|
1896
|
+
const dynamicSegmentIndex = uriTemplate.search(/[{*]/);
|
|
1897
|
+
if (dynamicSegmentIndex === -1) {
|
|
1898
|
+
return false;
|
|
1899
|
+
}
|
|
1900
|
+
const staticPrefix = uriTemplate.slice(0, dynamicSegmentIndex);
|
|
1901
|
+
if (!staticPrefix) {
|
|
1902
|
+
return false;
|
|
1903
|
+
}
|
|
1904
|
+
for (const resourceUri of allowedResources) {
|
|
1905
|
+
if (resourceUri.startsWith(staticPrefix)) {
|
|
1906
|
+
return true;
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
return false;
|
|
1910
|
+
};
|
|
1911
|
+
export async function filterResourceTemplatesByGroup(group, serverName, resourceTemplates, serverConfig) {
|
|
1912
|
+
if (group) {
|
|
1913
|
+
const resolvedServerConfig = await getGroupServerConfig(group, serverName, serverConfig);
|
|
1914
|
+
if (resolvedServerConfig &&
|
|
1915
|
+
resolvedServerConfig.resources !== 'all' &&
|
|
1916
|
+
Array.isArray(resolvedServerConfig.resources)) {
|
|
1917
|
+
if (resolvedServerConfig.resources.length === 0) {
|
|
1918
|
+
return [];
|
|
1919
|
+
}
|
|
1920
|
+
const allowedResources = new Set(resolvedServerConfig.resources);
|
|
1921
|
+
return resourceTemplates.filter((resourceTemplate) => {
|
|
1922
|
+
if (typeof resourceTemplate.uriTemplate !== 'string') {
|
|
1923
|
+
return false;
|
|
1924
|
+
}
|
|
1925
|
+
return resourceTemplateMatchesSelection(resourceTemplate.uriTemplate, allowedResources);
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
return resourceTemplates;
|
|
1930
|
+
}
|
|
1676
1931
|
//# sourceMappingURL=mcpService.js.map
|