@mozilla-ai/mcpd 0.0.3 → 0.1.0

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/index.js CHANGED
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const lruCache = require("lru-cache");
4
4
  const zod = require("zod");
5
+ const PIPELINE_FLOW_REQUEST = "request";
6
+ const PIPELINE_FLOW_RESPONSE = "response";
5
7
  class McpdError extends Error {
6
8
  constructor(message, cause) {
7
9
  super(message);
@@ -88,6 +90,19 @@ class TimeoutError extends McpdError {
88
90
  Error.captureStackTrace(this, this.constructor);
89
91
  }
90
92
  }
93
+ class PipelineError extends McpdError {
94
+ serverName;
95
+ operation;
96
+ pipelineFlow;
97
+ constructor(message, serverName, operation, pipelineFlow, cause) {
98
+ super(message, cause);
99
+ this.name = "PipelineError";
100
+ this.serverName = serverName;
101
+ this.operation = operation;
102
+ this.pipelineFlow = pipelineFlow;
103
+ Error.captureStackTrace(this, this.constructor);
104
+ }
105
+ }
91
106
  var HealthStatus = /* @__PURE__ */ ((HealthStatus2) => {
92
107
  HealthStatus2["OK"] = "ok";
93
108
  HealthStatus2["TIMEOUT"] = "timeout";
@@ -943,6 +958,14 @@ class FunctionBuilder {
943
958
  getCacheSize() {
944
959
  return this.#functionCache.size;
945
960
  }
961
+ /**
962
+ * Get all cached functions.
963
+ *
964
+ * @returns Array of all cached agent functions, or empty array if cache is empty
965
+ */
966
+ getCachedFunctions() {
967
+ return Array.from(this.#functionCache.values());
968
+ }
946
969
  }
947
970
  const API_BASE = "/api/v1";
948
971
  const SERVERS_BASE = `${API_BASE}/servers`;
@@ -973,13 +996,81 @@ const API_PATHS = {
973
996
  HEALTH_ALL: HEALTH_SERVERS_BASE,
974
997
  HEALTH_SERVER: (serverName) => `${HEALTH_SERVERS_BASE}/${encodeURIComponent(serverName)}`
975
998
  };
999
+ const LogLevels = {
1000
+ OFF: "off"
1001
+ };
1002
+ const ranks = {
1003
+ trace: 5,
1004
+ debug: 10,
1005
+ info: 20,
1006
+ warn: 30,
1007
+ error: 40,
1008
+ off: 1e3
1009
+ };
1010
+ function resolve(raw) {
1011
+ const candidate = raw?.toLowerCase();
1012
+ return candidate && candidate in ranks ? candidate : LogLevels.OFF;
1013
+ }
1014
+ function getLevel() {
1015
+ return resolve(
1016
+ typeof process !== "undefined" ? process.env.MCPD_LOG_LEVEL : void 0
1017
+ );
1018
+ }
1019
+ function defaultLogger() {
1020
+ return {
1021
+ trace: (...args) => {
1022
+ const lvl = getLevel();
1023
+ if (lvl !== LogLevels.OFF && ranks[lvl] <= ranks.trace)
1024
+ console.trace(...args);
1025
+ },
1026
+ debug: (...args) => {
1027
+ const lvl = getLevel();
1028
+ if (lvl !== LogLevels.OFF && ranks[lvl] <= ranks.debug)
1029
+ console.debug(...args);
1030
+ },
1031
+ info: (...args) => {
1032
+ const lvl = getLevel();
1033
+ if (lvl !== LogLevels.OFF && ranks[lvl] <= ranks.info)
1034
+ console.info(...args);
1035
+ },
1036
+ warn: (...args) => {
1037
+ const lvl = getLevel();
1038
+ if (lvl !== LogLevels.OFF && ranks[lvl] <= ranks.warn)
1039
+ console.warn(...args);
1040
+ },
1041
+ error: (...args) => {
1042
+ const lvl = getLevel();
1043
+ if (lvl !== LogLevels.OFF && ranks[lvl] <= ranks.error)
1044
+ console.error(...args);
1045
+ }
1046
+ };
1047
+ }
1048
+ function createLogger(impl) {
1049
+ const base = defaultLogger();
1050
+ return {
1051
+ trace: impl?.trace ?? base.trace,
1052
+ debug: impl?.debug ?? base.debug,
1053
+ info: impl?.info ?? base.info,
1054
+ warn: impl?.warn ?? base.warn,
1055
+ error: impl?.error ?? base.error
1056
+ };
1057
+ }
1058
+ const REQUEST_TIMEOUT_SECONDS = 30;
1059
+ const SERVER_HEALTH_CACHE_TTL_SECONDS = 10;
976
1060
  const SERVER_HEALTH_CACHE_MAXSIZE = 100;
1061
+ const TOOL_SEPARATOR = "__";
1062
+ const MCPD_ERROR_TYPE_HEADER = "Mcpd-Error-Type";
1063
+ const PIPELINE_ERROR_FLOWS = {
1064
+ "request-pipeline-failure": PIPELINE_FLOW_REQUEST,
1065
+ "response-pipeline-failure": PIPELINE_FLOW_RESPONSE
1066
+ };
977
1067
  class McpdClient {
978
1068
  #endpoint;
979
1069
  #apiKey;
980
1070
  #timeout;
981
1071
  #serverHealthCache;
982
1072
  #functionBuilder;
1073
+ #logger;
983
1074
  #cacheableExceptions = /* @__PURE__ */ new Set([
984
1075
  ServerNotFoundError,
985
1076
  ServerUnhealthyError,
@@ -995,14 +1086,18 @@ class McpdClient {
995
1086
  * @param options - Configuration options for the client
996
1087
  */
997
1088
  constructor(options) {
1089
+ const toMs = (s) => s * 1e3;
998
1090
  this.#endpoint = options.apiEndpoint.replace(/\/$/, "");
999
1091
  this.#apiKey = options.apiKey;
1000
- this.#timeout = options.timeout ?? 3e4;
1001
- const healthCacheTtlMs = (options.healthCacheTtl ?? 10) * 1e3;
1092
+ this.#timeout = options.timeout ?? toMs(REQUEST_TIMEOUT_SECONDS);
1093
+ const healthCacheTtlMs = toMs(
1094
+ options.healthCacheTtl ?? SERVER_HEALTH_CACHE_TTL_SECONDS
1095
+ );
1002
1096
  this.#serverHealthCache = createCache({
1003
1097
  max: SERVER_HEALTH_CACHE_MAXSIZE,
1004
1098
  ttl: healthCacheTtlMs
1005
1099
  });
1100
+ this.#logger = createLogger(options.logger);
1006
1101
  this.servers = new ServersNamespace({
1007
1102
  performCall: this.#performCall.bind(this),
1008
1103
  getTools: this.#getToolsByServer.bind(this),
@@ -1019,8 +1114,15 @@ class McpdClient {
1019
1114
  *
1020
1115
  * @param path - The API path (e.g., '/servers', '/servers/{server_name}/tools')
1021
1116
  * @param options - Request options
1117
+ *
1022
1118
  * @returns The JSON response from the daemon
1119
+ *
1120
+ * @throws {AuthenticationError} If API key was present and authentication fails
1121
+ * @throws {ConnectionError} If unable to connect to the mcpd daemon
1122
+ * @throws {TimeoutError} If the request times out
1023
1123
  * @throws {McpdError} If the request fails
1124
+ *
1125
+ * @internal
1024
1126
  */
1025
1127
  async #request(path, options = {}) {
1026
1128
  const url = `${this.#endpoint}${path}`;
@@ -1048,6 +1150,21 @@ class McpdClient {
1048
1150
  } catch {
1049
1151
  errorModel = null;
1050
1152
  }
1153
+ if (response.status === 500) {
1154
+ const errorType = response.headers.get(MCPD_ERROR_TYPE_HEADER)?.toLowerCase();
1155
+ const flow = errorType ? PIPELINE_ERROR_FLOWS[errorType] : void 0;
1156
+ if (flow) {
1157
+ const message = errorModel?.detail || body || "Pipeline failure";
1158
+ throw new PipelineError(
1159
+ message,
1160
+ void 0,
1161
+ // serverName - enriched by caller if available.
1162
+ void 0,
1163
+ // operation - enriched by caller if available.
1164
+ flow
1165
+ );
1166
+ }
1167
+ }
1051
1168
  if (errorModel && errorModel.detail) {
1052
1169
  const errorDetails = errorModel.errors?.map((e) => `${e.location}: ${e.message}`).join("; ");
1053
1170
  const fullMessage = errorDetails ? `${errorModel.detail} - ${errorDetails}` : errorModel.detail;
@@ -1100,6 +1217,10 @@ class McpdClient {
1100
1217
  * Get a list of all configured MCP servers.
1101
1218
  *
1102
1219
  * @returns Array of server names
1220
+ *
1221
+ * @throws {AuthenticationError} If API key was present and authentication fails
1222
+ * @throws {ConnectionError} If unable to connect to the mcpd daemon
1223
+ * @throws {TimeoutError} If the request times out
1103
1224
  * @throws {McpdError} If the request fails
1104
1225
  *
1105
1226
  * @example
@@ -1112,16 +1233,23 @@ class McpdClient {
1112
1233
  return await this.#request(API_PATHS.SERVERS);
1113
1234
  }
1114
1235
  /**
1115
- * Internal method to get tool schemas for a server.
1236
+ * Get tool schemas for a server.
1237
+ *
1238
+ * @privateRemarks
1116
1239
  * Used by dependency injection for ServersNamespace and internally for getAgentTools.
1117
1240
  *
1118
1241
  * @param serverName - Server name to get tools for
1242
+ *
1119
1243
  * @returns Tool schemas for the specified server
1244
+ *
1120
1245
  * @throws {ServerNotFoundError} If the specified server doesn't exist
1121
1246
  * @throws {ServerUnhealthyError} If the server is not healthy
1247
+ *
1248
+ * @throws {AuthenticationError} If API key was present and authentication fails
1122
1249
  * @throws {ConnectionError} If unable to connect to the mcpd daemon
1123
1250
  * @throws {TimeoutError} If the request times out
1124
1251
  * @throws {McpdError} If the request fails
1252
+ *
1125
1253
  * @internal
1126
1254
  */
1127
1255
  async #getToolsByServer(serverName) {
@@ -1137,17 +1265,24 @@ class McpdClient {
1137
1265
  return response.tools;
1138
1266
  }
1139
1267
  /**
1140
- * Internal method to get prompt schemas for a server.
1268
+ * Get prompt schemas for a server.
1269
+ *
1270
+ * @privateRemarks
1141
1271
  * Used internally for getPromptSchemas.
1142
1272
  *
1143
1273
  * @param serverName - Server name to get prompts for
1144
- * @param cursor - Optional cursor for pagination
1274
+ * @param cursor - Cursor for pagination
1275
+ *
1145
1276
  * @returns Prompt schemas for the specified server
1277
+ *
1146
1278
  * @throws {ServerNotFoundError} If the specified server doesn't exist
1147
1279
  * @throws {ServerUnhealthyError} If the server is not healthy
1280
+ *
1281
+ * @throws {AuthenticationError} If API key was present and authentication fails
1148
1282
  * @throws {ConnectionError} If unable to connect to the mcpd daemon
1149
1283
  * @throws {TimeoutError} If the request times out
1150
1284
  * @throws {McpdError} If the request fails
1285
+ *
1151
1286
  * @internal
1152
1287
  */
1153
1288
  async #getPromptsByServer(serverName, cursor) {
@@ -1164,16 +1299,24 @@ class McpdClient {
1164
1299
  }
1165
1300
  }
1166
1301
  /**
1167
- * Internal method to generate a prompt on a server.
1302
+ * Generate a prompt on a server.
1168
1303
  *
1169
- * This method is used internally by:
1304
+ * @privateRemarks
1305
+ * Used internally by:
1170
1306
  * - PromptsNamespace (via dependency injection)
1171
1307
  * - Server.generatePrompt() (via dependency injection)
1172
1308
  *
1173
1309
  * @param serverName - The name of the server
1174
1310
  * @param promptName - The exact name of the prompt
1175
1311
  * @param args - The prompt arguments
1312
+ *
1176
1313
  * @returns The generated prompt response
1314
+ *
1315
+ * @throws {AuthenticationError} If API key was present and authentication fails
1316
+ * @throws {ConnectionError} If unable to connect to the mcpd daemon
1317
+ * @throws {TimeoutError} If the request times out
1318
+ * @throws {McpdError} If the request fails
1319
+ *
1177
1320
  * @internal
1178
1321
  */
1179
1322
  async #generatePromptInternal(serverName, promptName, args) {
@@ -1189,17 +1332,24 @@ class McpdClient {
1189
1332
  return response;
1190
1333
  }
1191
1334
  /**
1192
- * Internal method to get resource schemas for a server.
1335
+ * Get resource schemas for a server.
1336
+ *
1337
+ * @privateRemarks
1193
1338
  * Used internally for getResources and by dependency injection for ServersNamespace.
1194
1339
  *
1195
1340
  * @param serverName - Server name to get resources for
1196
- * @param cursor - Optional cursor for pagination
1341
+ * @param cursor - Cursor for pagination
1342
+ *
1197
1343
  * @returns Resource schemas for the specified server
1344
+ *
1198
1345
  * @throws {ServerNotFoundError} If the specified server doesn't exist
1199
1346
  * @throws {ServerUnhealthyError} If the server is not healthy
1347
+ *
1348
+ * @throws {AuthenticationError} If API key was present and authentication fails
1200
1349
  * @throws {ConnectionError} If unable to connect to the mcpd daemon
1201
1350
  * @throws {TimeoutError} If the request times out
1202
1351
  * @throws {McpdError} If the request fails
1352
+ *
1203
1353
  * @internal
1204
1354
  */
1205
1355
  async #getResourcesByServer(serverName, cursor) {
@@ -1216,17 +1366,24 @@ class McpdClient {
1216
1366
  }
1217
1367
  }
1218
1368
  /**
1219
- * Internal method to get resource template schemas for a server.
1369
+ * Get resource template schemas for a server.
1370
+ *
1371
+ * @privateRemarks
1220
1372
  * Used internally for getResourceTemplates and by dependency injection for ServersNamespace.
1221
1373
  *
1222
1374
  * @param serverName - Server name to get resource templates for
1223
- * @param cursor - Optional cursor for pagination
1375
+ * @param cursor - Cursor for pagination
1376
+ *
1224
1377
  * @returns Resource template schemas for the specified server
1378
+ *
1225
1379
  * @throws {ServerNotFoundError} If the specified server doesn't exist
1226
1380
  * @throws {ServerUnhealthyError} If the server is not healthy
1381
+ *
1382
+ * @throws {AuthenticationError} If API key was present and authentication fails
1227
1383
  * @throws {ConnectionError} If unable to connect to the mcpd daemon
1228
1384
  * @throws {TimeoutError} If the request times out
1229
1385
  * @throws {McpdError} If the request fails
1386
+ *
1230
1387
  * @internal
1231
1388
  */
1232
1389
  async #getResourceTemplatesByServer(serverName, cursor) {
@@ -1243,17 +1400,24 @@ class McpdClient {
1243
1400
  }
1244
1401
  }
1245
1402
  /**
1246
- * Internal method to read resource content from a server.
1403
+ * Read resource content from a server.
1404
+ *
1405
+ * @privateRemarks
1247
1406
  * Used by dependency injection for ServersNamespace.
1248
1407
  *
1249
1408
  * @param serverName - Server name to read resource from
1250
1409
  * @param uri - The resource URI
1410
+ *
1251
1411
  * @returns Array of resource contents (text or blob)
1412
+ *
1252
1413
  * @throws {ServerNotFoundError} If the specified server doesn't exist
1253
1414
  * @throws {ServerUnhealthyError} If the server is not healthy
1415
+ *
1416
+ * @throws {AuthenticationError} If API key was present and authentication fails
1254
1417
  * @throws {ConnectionError} If unable to connect to the mcpd daemon
1255
1418
  * @throws {TimeoutError} If the request times out
1256
1419
  * @throws {McpdError} If the request fails
1420
+ *
1257
1421
  * @internal
1258
1422
  */
1259
1423
  async #readResourceByServer(serverName, uri) {
@@ -1305,8 +1469,14 @@ class McpdClient {
1305
1469
  * Check if a specific server is healthy.
1306
1470
  *
1307
1471
  * @param serverName - The name of the server to check
1472
+ *
1308
1473
  * @returns True if the server is healthy, false otherwise
1309
1474
  *
1475
+ * @throws {AuthenticationError} If API key was present and authentication fails
1476
+ * @throws {ConnectionError} If unable to connect to the mcpd daemon
1477
+ * @throws {TimeoutError} If the request times out
1478
+ * @throws {McpdError} If the request fails
1479
+ *
1310
1480
  * @example
1311
1481
  * ```typescript
1312
1482
  * if (await client.isServerHealthy('time')) {
@@ -1329,8 +1499,14 @@ class McpdClient {
1329
1499
  * Ensure a server is healthy before performing an operation.
1330
1500
  *
1331
1501
  * @param serverName - The name of the server to check
1502
+ *
1332
1503
  * @throws {ServerNotFoundError} If the server doesn't exist
1333
1504
  * @throws {ServerUnhealthyError} If the server is not healthy
1505
+ *
1506
+ * @throws {AuthenticationError} If API key was present and authentication fails
1507
+ * @throws {ConnectionError} If unable to connect to the mcpd daemon
1508
+ * @throws {TimeoutError} If the request times out
1509
+ * @throws {McpdError} If the request fails
1334
1510
  */
1335
1511
  async #ensureServerHealthy(serverName) {
1336
1512
  const health = await this.getServerHealth(serverName);
@@ -1349,35 +1525,60 @@ class McpdClient {
1349
1525
  }
1350
1526
  }
1351
1527
  /**
1352
- * Get list of healthy servers from optional server names.
1528
+ * Get list of healthy servers.
1353
1529
  *
1354
- * This helper fetches server names (if not provided) and filters to only healthy servers.
1355
- * Used by getToolSchemas(), getPrompts(), and agentTools() to avoid timeouts on failed servers.
1530
+ * @remarks
1531
+ * If logging is enabled, warnings are logged for servers that do not exist or are unhealthy.
1356
1532
  *
1357
- * @param servers - Optional array of server names. If not provided, fetches all servers.
1358
- * @returns Array of healthy server names
1359
- * @internal
1533
+ * @param servers - List of server names to use for health checking.
1534
+ * If not provided, or empty, checks health for all servers.
1535
+ *
1536
+ * @returns List of server names with 'ok' health status.
1537
+ *
1538
+ * @throws {AuthenticationError} If API key was present and authentication fails
1539
+ * @throws {ConnectionError} If unable to connect to the mcpd daemon
1540
+ * @throws {TimeoutError} If the request times out
1541
+ * @throws {McpdError} If the request fails
1360
1542
  */
1361
1543
  async #getHealthyServers(servers) {
1362
- const serverNames = servers && servers.length > 0 ? servers : await this.listServers();
1544
+ const serverNames = servers?.length ? servers : await this.listServers();
1363
1545
  const healthMap = await this.getServerHealth();
1364
1546
  return serverNames.filter((name) => {
1365
1547
  const health = healthMap[name];
1366
- return health && HealthStatusHelpers.isHealthy(health.status);
1548
+ if (!health) {
1549
+ this.#logger.warn(`Skipping non-existent server '${name}'`);
1550
+ return false;
1551
+ }
1552
+ if (!HealthStatusHelpers.isHealthy(health.status)) {
1553
+ this.#logger.warn(
1554
+ `Skipping unhealthy server '${name}' with status '${health.status}'`
1555
+ );
1556
+ return false;
1557
+ }
1558
+ return true;
1367
1559
  });
1368
1560
  }
1369
1561
  /**
1370
- * Internal method to perform a tool call on a server.
1562
+ * Perform a tool call on a server.
1371
1563
  *
1372
- * This method is used internally by:
1564
+ * @privateRemarks
1565
+ * Used internally by:
1373
1566
  * - ToolsNamespace (via dependency injection)
1374
1567
  * - FunctionBuilder (via dependency injection)
1375
1568
  *
1376
1569
  * @param serverName - The name of the server
1377
1570
  * @param toolName - The exact name of the tool
1378
1571
  * @param args - The tool arguments
1572
+ *
1379
1573
  * @returns The tool's response
1574
+ *
1380
1575
  * @throws {ToolExecutionError} If the tool execution fails
1576
+ *
1577
+ * @throws {AuthenticationError} If API key was present and authentication fails
1578
+ * @throws {ConnectionError} If unable to connect to the mcpd daemon
1579
+ * @throws {TimeoutError} If the request times out
1580
+ * @throws {McpdError} If the request fails
1581
+ *
1381
1582
  * @internal
1382
1583
  */
1383
1584
  async #performCall(serverName, toolName, args) {
@@ -1396,6 +1597,15 @@ class McpdClient {
1396
1597
  }
1397
1598
  return response;
1398
1599
  } catch (error) {
1600
+ if (error instanceof PipelineError) {
1601
+ throw new PipelineError(
1602
+ error.message,
1603
+ serverName,
1604
+ `${serverName}.${toolName}`,
1605
+ error.pipelineFlow,
1606
+ error.cause
1607
+ );
1608
+ }
1399
1609
  if (error instanceof McpdError) {
1400
1610
  throw error;
1401
1611
  }
@@ -1423,29 +1633,33 @@ class McpdClient {
1423
1633
  this.#serverHealthCache.clear();
1424
1634
  }
1425
1635
  /**
1426
- * Generate callable functions for use with AI agent frameworks (internal).
1636
+ * Fetch and cache callable functions from all healthy servers.
1427
1637
  *
1428
- * This method queries servers and creates self-contained, callable functions
1638
+ * This method queries all healthy servers and creates self-contained, callable functions
1429
1639
  * that can be passed to AI agent frameworks. Each function includes its schema
1430
1640
  * as metadata and handles the MCP communication internally.
1431
1641
  *
1432
- * This method automatically filters out unhealthy servers by checking their health
1433
- * status before fetching tools. Unhealthy servers are silently skipped to ensure
1434
- * the method returns quickly without waiting for timeouts on failed servers.
1642
+ * Unhealthy servers are automatically filtered out and skipped (with optional warnings
1643
+ * when logging is enabled) to ensure the method returns quickly without waiting for timeouts.
1435
1644
  *
1436
1645
  * Tool fetches from multiple servers are executed concurrently for optimal performance.
1646
+ * Functions are cached indefinitely until explicitly cleared.
1437
1647
  *
1438
- * @param servers - Optional list of server names to include. If not specified, includes all servers.
1439
- * @returns Array of callable functions with metadata. Only includes tools from healthy servers.
1648
+ * @returns Array of callable functions with metadata from all healthy servers.
1440
1649
  *
1650
+ * @throws {AuthenticationError} If API key was present and authentication fails
1441
1651
  * @throws {ConnectionError} If unable to connect to the mcpd daemon
1442
- * @throws {TimeoutError} If requests to the daemon time out
1443
- * @throws {AuthenticationError} If API key authentication fails
1444
- * @throws {McpdError} If unable to retrieve health status, server list, or generate functions
1652
+ * @throws {TimeoutError} If the request times out
1653
+ * @throws {McpdError} If the request fails
1654
+ *
1445
1655
  * @internal
1446
1656
  */
1447
- async agentTools(servers) {
1448
- const healthyServers = await this.#getHealthyServers(servers);
1657
+ async #agentTools() {
1658
+ const cachedFunctions = this.#functionBuilder.getCachedFunctions();
1659
+ if (cachedFunctions.length > 0) {
1660
+ return cachedFunctions;
1661
+ }
1662
+ const healthyServers = await this.#getHealthyServers();
1449
1663
  const results = await Promise.allSettled(
1450
1664
  healthyServers.map(async (serverName) => ({
1451
1665
  serverName,
@@ -1464,17 +1678,43 @@ class McpdClient {
1464
1678
  return agentTools;
1465
1679
  }
1466
1680
  async getAgentTools(options = {}) {
1467
- const { servers, format = "array" } = options;
1468
- const tools = await this.agentTools(servers);
1469
- switch (format) {
1470
- case "object":
1471
- return Object.fromEntries(tools.map((tool) => [tool.name, tool]));
1472
- case "map":
1473
- return new Map(tools.map((tool) => [tool.name, tool]));
1474
- case "array":
1475
- default:
1476
- return tools;
1477
- }
1681
+ const { servers, tools, format = "array", refreshCache = false } = options;
1682
+ if (refreshCache) this.#functionBuilder.clearCache();
1683
+ const allTools = await this.#agentTools();
1684
+ const filteredTools = allTools.filter((tool) => !servers || servers.includes(tool._serverName)).filter((tool) => !tools || this.#matchesToolFilter(tool, tools));
1685
+ const formatters = {
1686
+ array: (t) => t,
1687
+ object: (t) => Object.fromEntries(t.map((tool) => [tool.name, tool])),
1688
+ map: (t) => new Map(t.map((tool) => [tool.name, tool]))
1689
+ };
1690
+ return formatters[format](filteredTools);
1691
+ }
1692
+ /**
1693
+ * Check if a tool matches the tool filter.
1694
+ *
1695
+ * Supports two formats:
1696
+ * - Raw tool name: "get_current_time" (matches across all servers)
1697
+ * - Server-prefixed: "time__get_current_time" (matches specific server + tool)
1698
+ *
1699
+ * @remarks
1700
+ * When a filter contains "__", it's first checked as server-prefixed (exact match).
1701
+ * If that fails, it's checked as a raw tool name. This handles tools whose names
1702
+ * contain "__" (e.g., "my__special__tool").
1703
+ *
1704
+ * @param tool The tool to match.
1705
+ * @param tools List of tool names to match against.
1706
+ *
1707
+ * @returns True if a match is found in tools, based on the predicate.
1708
+ *
1709
+ * @internal
1710
+ */
1711
+ #matchesToolFilter(tool, tools) {
1712
+ return tools.some((filterItem) => {
1713
+ if (filterItem.indexOf(TOOL_SEPARATOR) === -1) {
1714
+ return filterItem === tool._toolName;
1715
+ }
1716
+ return filterItem === tool.name || filterItem === tool._toolName;
1717
+ });
1478
1718
  }
1479
1719
  }
1480
1720
  exports.AuthenticationError = AuthenticationError;
@@ -1483,6 +1723,9 @@ exports.HealthStatus = HealthStatus;
1483
1723
  exports.HealthStatusHelpers = HealthStatusHelpers;
1484
1724
  exports.McpdClient = McpdClient;
1485
1725
  exports.McpdError = McpdError;
1726
+ exports.PIPELINE_FLOW_REQUEST = PIPELINE_FLOW_REQUEST;
1727
+ exports.PIPELINE_FLOW_RESPONSE = PIPELINE_FLOW_RESPONSE;
1728
+ exports.PipelineError = PipelineError;
1486
1729
  exports.ServerNotFoundError = ServerNotFoundError;
1487
1730
  exports.ServerUnhealthyError = ServerUnhealthyError;
1488
1731
  exports.TimeoutError = TimeoutError;