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