@frontmcp/testing 1.8.0 → 1.8.2

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/fixtures/index.js CHANGED
@@ -489,6 +489,7 @@ function sleep(ms) {
489
489
 
490
490
  // libs/testing/src/transport/streamable-http.transport.ts
491
491
  var DEFAULT_TIMEOUT = 3e4;
492
+ var NOTIFICATION_STREAM_REOPEN_DELAY_MS = 250;
492
493
  var StreamableHttpTransport = class {
493
494
  config;
494
495
  state = "disconnected";
@@ -500,6 +501,10 @@ var StreamableHttpTransport = class {
500
501
  interceptors;
501
502
  publicMode;
502
503
  elicitationHandler;
504
+ notificationHandler;
505
+ notificationStream;
506
+ notificationProtocolVersion = "";
507
+ notificationStreamReopenTimer;
503
508
  constructor(config) {
504
509
  this.config = {
505
510
  baseUrl: config.baseUrl.replace(/\/$/, ""),
@@ -516,6 +521,7 @@ var StreamableHttpTransport = class {
516
521
  this.interceptors = config.interceptors;
517
522
  this.publicMode = config.publicMode ?? false;
518
523
  this.elicitationHandler = config.elicitationHandler;
524
+ this.notificationHandler = config.notificationHandler;
519
525
  }
520
526
  async connect() {
521
527
  this.state = "connecting";
@@ -735,7 +741,12 @@ var StreamableHttpTransport = class {
735
741
  };
736
742
  }
737
743
  }
744
+ async openNotificationStream(protocolVersion) {
745
+ this.notificationProtocolVersion = protocolVersion;
746
+ await this.connectNotificationStream();
747
+ }
738
748
  async close() {
749
+ this.closeNotificationStream();
739
750
  this.state = "disconnected";
740
751
  this.sessionId = void 0;
741
752
  this.log("StreamableHTTP transport closed");
@@ -774,6 +785,7 @@ var StreamableHttpTransport = class {
774
785
  return { ...this.lastRequestHeaders };
775
786
  }
776
787
  async simulateDisconnect() {
788
+ this.closeNotificationStream();
777
789
  this.state = "disconnected";
778
790
  this.sessionId = void 0;
779
791
  }
@@ -792,6 +804,72 @@ var StreamableHttpTransport = class {
792
804
  // ═══════════════════════════════════════════════════════════════════
793
805
  // PRIVATE HELPERS
794
806
  // ═══════════════════════════════════════════════════════════════════
807
+ closeNotificationStream() {
808
+ clearTimeout(this.notificationStreamReopenTimer);
809
+ this.notificationStream?.abort();
810
+ this.notificationStream = void 0;
811
+ }
812
+ /** Opens the stream without holding up the caller past the request timeout; close() aborts it at any point. */
813
+ async connectNotificationStream() {
814
+ if (!this.sessionId || this.notificationStream) return;
815
+ const controller = new AbortController();
816
+ this.notificationStream = controller;
817
+ const { "Content-Type": _contentType, ...headers } = this.buildHeaders();
818
+ const established = fetch(this.mcpUrl(), {
819
+ method: "GET",
820
+ headers: { ...headers, Accept: "text/event-stream", "MCP-Protocol-Version": this.notificationProtocolVersion },
821
+ signal: controller.signal
822
+ }).then(
823
+ async (response) => {
824
+ const isEventStream = response.headers.get("content-type")?.includes("text/event-stream") ?? false;
825
+ if (!response.ok || !response.body || !isEventStream) {
826
+ await response.body?.cancel();
827
+ this.log(`Server offers no notification stream (HTTP ${response.status})`);
828
+ this.releaseNotificationStream(controller);
829
+ return;
830
+ }
831
+ void this.readNotificationStream(controller, response.body.getReader());
832
+ },
833
+ (error) => {
834
+ this.log("Failed to open the notification stream:", error);
835
+ this.releaseNotificationStream(controller);
836
+ }
837
+ );
838
+ let establishTimer;
839
+ const establishDeadline = new Promise((resolve) => {
840
+ establishTimer = setTimeout(resolve, this.config.timeout);
841
+ });
842
+ await Promise.race([established, establishDeadline]);
843
+ clearTimeout(establishTimer);
844
+ }
845
+ releaseNotificationStream(controller) {
846
+ if (this.notificationStream === controller) this.notificationStream = void 0;
847
+ }
848
+ async readNotificationStream(controller, reader) {
849
+ const decoder = new TextDecoder();
850
+ let buffer = "";
851
+ try {
852
+ for (let chunk = await reader.read(); !chunk.done; chunk = await reader.read()) {
853
+ const { completeEvents, remainder } = splitSSEEvents(buffer + decoder.decode(chunk.value, { stream: true }));
854
+ buffer = remainder;
855
+ for (const eventText of completeEvents) {
856
+ for (const event of this.parseSSEEvents(eventText, void 0).events) {
857
+ await this.handleSSEEvent(event);
858
+ }
859
+ }
860
+ }
861
+ } catch (error) {
862
+ this.log("Notification stream ended:", error);
863
+ } finally {
864
+ reader.releaseLock();
865
+ }
866
+ if (controller.signal.aborted || this.notificationStream !== controller) return;
867
+ this.releaseNotificationStream(controller);
868
+ this.notificationStreamReopenTimer = setTimeout(
869
+ () => void this.connectNotificationStream(),
870
+ NOTIFICATION_STREAM_REOPEN_DELAY_MS
871
+ );
872
+ }
795
873
  /**
796
874
  * Handle SSE response with elicitation support.
797
875
  *
@@ -929,6 +1007,13 @@ var StreamableHttpTransport = class {
929
1007
  response: { jsonrpc: "2.0", id: null, result: void 0 }
930
1008
  };
931
1009
  }
1010
+ if ("method" in parsed && parsed.id === void 0) {
1011
+ this.notificationHandler?.(parsed);
1012
+ return {
1013
+ isFinal: false,
1014
+ response: { jsonrpc: "2.0", id: null, result: void 0 }
1015
+ };
1016
+ }
932
1017
  if ("result" in parsed || "error" in parsed) {
933
1018
  return { isFinal: true, response: parsed };
934
1019
  }
@@ -1099,6 +1184,13 @@ var StreamableHttpTransport = class {
1099
1184
  };
1100
1185
  }
1101
1186
  };
1187
+ function splitSSEEvents(buffer) {
1188
+ const endsWithCarriageReturn = buffer.endsWith("\r");
1189
+ const normalized = (endsWithCarriageReturn ? buffer.slice(0, -1) : buffer).replace(/\r\n?/g, "\n");
1190
+ const completeEvents = normalized.split("\n\n");
1191
+ const remainder = completeEvents.pop() ?? "";
1192
+ return { completeEvents, remainder: endsWithCarriageReturn ? `${remainder}\r` : remainder };
1193
+ }
1102
1194
 
1103
1195
  // libs/testing/src/platform/platform-client-info.ts
1104
1196
  var MCP_APPS_EXTENSION_KEY = "io.modelcontextprotocol/ui";
@@ -1235,7 +1327,8 @@ var McpTestClientBuilder = class {
1235
1327
  return this;
1236
1328
  }
1237
1329
  /**
1238
- * Set the MCP protocol version to request
1330
+ * Set the MCP protocol version to request (default '2025-06-18').
1331
+ * '2026-07-28' has no initialize handshake, so `build()` throws for it.
1239
1332
  */
1240
1333
  withProtocolVersion(version) {
1241
1334
  this.config.protocolVersion = version;
@@ -1331,6 +1424,7 @@ var McpTestClientBuilder = class {
1331
1424
  // libs/testing/src/client/mcp-test-client.ts
1332
1425
  var DEFAULT_TIMEOUT2 = 3e4;
1333
1426
  var DEFAULT_PROTOCOL_VERSION = "2025-06-18";
1427
+ var UNSUPPORTED_PROTOCOL_VERSIONS = ["2026-07-28"];
1334
1428
  var DEFAULT_CLIENT_INFO = {
1335
1429
  name: "@frontmcp/testing",
1336
1430
  version: "0.4.0"
@@ -1367,6 +1461,8 @@ var McpTestClient = class {
1367
1461
  _traces = [];
1368
1462
  _notifications = [];
1369
1463
  _progressUpdates = [];
1464
+ collectingProgress = false;
1465
+ progressTokenCounter = 0;
1370
1466
  // Interceptor chain
1371
1467
  _interceptors;
1372
1468
  // Elicitation handler for server→client elicit requests
@@ -1375,6 +1471,11 @@ var McpTestClient = class {
1375
1471
  // CONSTRUCTOR & FACTORY
1376
1472
  // ═══════════════════════════════════════════════════════════════════
1377
1473
  constructor(config) {
1474
+ if (config.protocolVersion && UNSUPPORTED_PROTOCOL_VERSIONS.includes(config.protocolVersion)) {
1475
+ throw new Error(
1476
+ `McpTestClient does not support protocol version ${config.protocolVersion}: it has no initialize handshake. Use ${DEFAULT_PROTOCOL_VERSION} or earlier.`
1477
+ );
1478
+ }
1378
1479
  this.config = {
1379
1480
  baseUrl: config.baseUrl,
1380
1481
  entryPath: config.entryPath,
@@ -1460,6 +1561,7 @@ var McpTestClient = class {
1460
1561
  jsonrpc: "2.0",
1461
1562
  method: "notifications/initialized"
1462
1563
  });
1564
+ await this.transport.openNotificationStream?.(this.initResult.protocolVersion);
1463
1565
  this.log("info", `Connected to ${this.initResult.serverInfo?.name ?? "MCP Server"}`);
1464
1566
  return this.initResult;
1465
1567
  }
@@ -1570,8 +1672,8 @@ var McpTestClient = class {
1570
1672
  /**
1571
1673
  * Call a tool by name with arguments
1572
1674
  */
1573
- call: async (name, args) => {
1574
- const response = await this.callTool(name, args);
1675
+ call: async (name, args, options = {}) => {
1676
+ const response = await this.callTool(name, args, this.progressTokenFor(options));
1575
1677
  return this.wrapToolResult(response);
1576
1678
  }
1577
1679
  };
@@ -1713,6 +1815,7 @@ var McpTestClient = class {
1713
1815
  * Collect progress notifications specifically
1714
1816
  */
1715
1817
  collectProgress: () => {
1818
+ this.collectingProgress = true;
1716
1819
  return new ProgressCollector(this._progressUpdates);
1717
1820
  },
1718
1821
  /**
@@ -2018,12 +2121,29 @@ var McpTestClient = class {
2018
2121
  async listTools() {
2019
2122
  return this.request("tools/list", {});
2020
2123
  }
2021
- async callTool(name, args) {
2124
+ async callTool(name, args, progressToken) {
2022
2125
  return this.request("tools/call", {
2023
2126
  name,
2024
- arguments: args ?? {}
2127
+ arguments: args ?? {},
2128
+ ...progressToken !== void 0 && { _meta: { progressToken } }
2025
2129
  });
2026
2130
  }
2131
+ progressTokenFor(options) {
2132
+ if (options.progressToken !== void 0) return options.progressToken;
2133
+ return this.collectingProgress ? `progress-${++this.progressTokenCounter}` : void 0;
2134
+ }
2135
+ recordNotification = (notification) => {
2136
+ const timestamp = /* @__PURE__ */ new Date();
2137
+ this._notifications.push({ method: notification.method, params: notification.params, timestamp });
2138
+ if (notification.method !== "notifications/progress") return;
2139
+ const { progress, total, progressToken } = notification.params ?? {};
2140
+ this._progressUpdates.push({
2141
+ progress: Number(progress),
2142
+ total: typeof total === "number" ? total : void 0,
2143
+ progressToken: typeof progressToken === "string" || typeof progressToken === "number" ? progressToken : void 0,
2144
+ timestamp
2145
+ });
2146
+ };
2027
2147
  async listResources() {
2028
2148
  return this.request("resources/list", {});
2029
2149
  }
@@ -2070,7 +2190,8 @@ var McpTestClient = class {
2070
2190
  debug: this.config.debug,
2071
2191
  interceptors: this._interceptors,
2072
2192
  clientInfo: this.config.clientInfo,
2073
- elicitationHandler: this._elicitationHandler
2193
+ elicitationHandler: this._elicitationHandler,
2194
+ notificationHandler: this.recordNotification
2074
2195
  });
2075
2196
  case "sse":
2076
2197
  throw new Error("SSE transport not yet implemented");
package/index.d.ts CHANGED
@@ -40,7 +40,7 @@
40
40
  */
41
41
  export { McpTestClient } from './client/mcp-test-client';
42
42
  export { McpTestClientBuilder } from './client/mcp-test-client.builder';
43
- export type { McpTestClientConfig, McpResponse, McpErrorInfo, TestTransportType, TestAuthConfig, ToolResultWrapper, ResourceContentWrapper, PromptResultWrapper, LogEntry, LogLevel, RequestTrace, NotificationEntry, ProgressUpdate, SessionInfo, AuthState, } from './client/mcp-test-client.types';
43
+ export type { McpTestClientConfig, McpResponse, McpErrorInfo, TestTransportType, TestAuthConfig, ToolResultWrapper, ResourceContentWrapper, PromptResultWrapper, LogEntry, LogLevel, RequestTrace, NotificationEntry, ProgressUpdate, ToolCallOptions, SessionInfo, AuthState, } from './client/mcp-test-client.types';
44
44
  export type { McpTransport, TransportConfig, TransportState } from './transport/transport.interface';
45
45
  export { StreamableHttpTransport } from './transport/streamable-http.transport';
46
46
  export { TestTokenFactory } from './auth/token-factory';
package/index.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/index.js CHANGED
@@ -462,6 +462,7 @@ var interceptors = {
462
462
 
463
463
  // libs/testing/src/transport/streamable-http.transport.ts
464
464
  var DEFAULT_TIMEOUT = 3e4;
465
+ var NOTIFICATION_STREAM_REOPEN_DELAY_MS = 250;
465
466
  var StreamableHttpTransport = class {
466
467
  config;
467
468
  state = "disconnected";
@@ -473,6 +474,10 @@ var StreamableHttpTransport = class {
473
474
  interceptors;
474
475
  publicMode;
475
476
  elicitationHandler;
477
+ notificationHandler;
478
+ notificationStream;
479
+ notificationProtocolVersion = "";
480
+ notificationStreamReopenTimer;
476
481
  constructor(config) {
477
482
  this.config = {
478
483
  baseUrl: config.baseUrl.replace(/\/$/, ""),
@@ -489,6 +494,7 @@ var StreamableHttpTransport = class {
489
494
  this.interceptors = config.interceptors;
490
495
  this.publicMode = config.publicMode ?? false;
491
496
  this.elicitationHandler = config.elicitationHandler;
497
+ this.notificationHandler = config.notificationHandler;
492
498
  }
493
499
  async connect() {
494
500
  this.state = "connecting";
@@ -708,7 +714,12 @@ var StreamableHttpTransport = class {
708
714
  };
709
715
  }
710
716
  }
717
+ async openNotificationStream(protocolVersion) {
718
+ this.notificationProtocolVersion = protocolVersion;
719
+ await this.connectNotificationStream();
720
+ }
711
721
  async close() {
722
+ this.closeNotificationStream();
712
723
  this.state = "disconnected";
713
724
  this.sessionId = void 0;
714
725
  this.log("StreamableHTTP transport closed");
@@ -747,6 +758,7 @@ var StreamableHttpTransport = class {
747
758
  return { ...this.lastRequestHeaders };
748
759
  }
749
760
  async simulateDisconnect() {
761
+ this.closeNotificationStream();
750
762
  this.state = "disconnected";
751
763
  this.sessionId = void 0;
752
764
  }
@@ -765,6 +777,72 @@ var StreamableHttpTransport = class {
765
777
  // ═══════════════════════════════════════════════════════════════════
766
778
  // PRIVATE HELPERS
767
779
  // ═══════════════════════════════════════════════════════════════════
780
+ closeNotificationStream() {
781
+ clearTimeout(this.notificationStreamReopenTimer);
782
+ this.notificationStream?.abort();
783
+ this.notificationStream = void 0;
784
+ }
785
+ /** Opens the stream without holding up the caller past the request timeout; close() aborts it at any point. */
786
+ async connectNotificationStream() {
787
+ if (!this.sessionId || this.notificationStream) return;
788
+ const controller = new AbortController();
789
+ this.notificationStream = controller;
790
+ const { "Content-Type": _contentType, ...headers } = this.buildHeaders();
791
+ const established = fetch(this.mcpUrl(), {
792
+ method: "GET",
793
+ headers: { ...headers, Accept: "text/event-stream", "MCP-Protocol-Version": this.notificationProtocolVersion },
794
+ signal: controller.signal
795
+ }).then(
796
+ async (response) => {
797
+ const isEventStream = response.headers.get("content-type")?.includes("text/event-stream") ?? false;
798
+ if (!response.ok || !response.body || !isEventStream) {
799
+ await response.body?.cancel();
800
+ this.log(`Server offers no notification stream (HTTP ${response.status})`);
801
+ this.releaseNotificationStream(controller);
802
+ return;
803
+ }
804
+ void this.readNotificationStream(controller, response.body.getReader());
805
+ },
806
+ (error) => {
807
+ this.log("Failed to open the notification stream:", error);
808
+ this.releaseNotificationStream(controller);
809
+ }
810
+ );
811
+ let establishTimer;
812
+ const establishDeadline = new Promise((resolve) => {
813
+ establishTimer = setTimeout(resolve, this.config.timeout);
814
+ });
815
+ await Promise.race([established, establishDeadline]);
816
+ clearTimeout(establishTimer);
817
+ }
818
+ releaseNotificationStream(controller) {
819
+ if (this.notificationStream === controller) this.notificationStream = void 0;
820
+ }
821
+ async readNotificationStream(controller, reader) {
822
+ const decoder = new TextDecoder();
823
+ let buffer = "";
824
+ try {
825
+ for (let chunk = await reader.read(); !chunk.done; chunk = await reader.read()) {
826
+ const { completeEvents, remainder } = splitSSEEvents(buffer + decoder.decode(chunk.value, { stream: true }));
827
+ buffer = remainder;
828
+ for (const eventText of completeEvents) {
829
+ for (const event of this.parseSSEEvents(eventText, void 0).events) {
830
+ await this.handleSSEEvent(event);
831
+ }
832
+ }
833
+ }
834
+ } catch (error) {
835
+ this.log("Notification stream ended:", error);
836
+ } finally {
837
+ reader.releaseLock();
838
+ }
839
+ if (controller.signal.aborted || this.notificationStream !== controller) return;
840
+ this.releaseNotificationStream(controller);
841
+ this.notificationStreamReopenTimer = setTimeout(
842
+ () => void this.connectNotificationStream(),
843
+ NOTIFICATION_STREAM_REOPEN_DELAY_MS
844
+ );
845
+ }
768
846
  /**
769
847
  * Handle SSE response with elicitation support.
770
848
  *
@@ -902,6 +980,13 @@ var StreamableHttpTransport = class {
902
980
  response: { jsonrpc: "2.0", id: null, result: void 0 }
903
981
  };
904
982
  }
983
+ if ("method" in parsed && parsed.id === void 0) {
984
+ this.notificationHandler?.(parsed);
985
+ return {
986
+ isFinal: false,
987
+ response: { jsonrpc: "2.0", id: null, result: void 0 }
988
+ };
989
+ }
905
990
  if ("result" in parsed || "error" in parsed) {
906
991
  return { isFinal: true, response: parsed };
907
992
  }
@@ -1072,6 +1157,13 @@ var StreamableHttpTransport = class {
1072
1157
  };
1073
1158
  }
1074
1159
  };
1160
+ function splitSSEEvents(buffer) {
1161
+ const endsWithCarriageReturn = buffer.endsWith("\r");
1162
+ const normalized = (endsWithCarriageReturn ? buffer.slice(0, -1) : buffer).replace(/\r\n?/g, "\n");
1163
+ const completeEvents = normalized.split("\n\n");
1164
+ const remainder = completeEvents.pop() ?? "";
1165
+ return { completeEvents, remainder: endsWithCarriageReturn ? `${remainder}\r` : remainder };
1166
+ }
1075
1167
 
1076
1168
  // libs/testing/src/platform/platform-client-info.ts
1077
1169
  var MCP_APPS_EXTENSION_KEY = "io.modelcontextprotocol/ui";
@@ -1227,7 +1319,8 @@ var McpTestClientBuilder = class {
1227
1319
  return this;
1228
1320
  }
1229
1321
  /**
1230
- * Set the MCP protocol version to request
1322
+ * Set the MCP protocol version to request (default '2025-06-18').
1323
+ * '2026-07-28' has no initialize handshake, so `build()` throws for it.
1231
1324
  */
1232
1325
  withProtocolVersion(version) {
1233
1326
  this.config.protocolVersion = version;
@@ -1323,6 +1416,7 @@ var McpTestClientBuilder = class {
1323
1416
  // libs/testing/src/client/mcp-test-client.ts
1324
1417
  var DEFAULT_TIMEOUT2 = 3e4;
1325
1418
  var DEFAULT_PROTOCOL_VERSION = "2025-06-18";
1419
+ var UNSUPPORTED_PROTOCOL_VERSIONS = ["2026-07-28"];
1326
1420
  var DEFAULT_CLIENT_INFO = {
1327
1421
  name: "@frontmcp/testing",
1328
1422
  version: "0.4.0"
@@ -1359,6 +1453,8 @@ var McpTestClient = class {
1359
1453
  _traces = [];
1360
1454
  _notifications = [];
1361
1455
  _progressUpdates = [];
1456
+ collectingProgress = false;
1457
+ progressTokenCounter = 0;
1362
1458
  // Interceptor chain
1363
1459
  _interceptors;
1364
1460
  // Elicitation handler for server→client elicit requests
@@ -1367,6 +1463,11 @@ var McpTestClient = class {
1367
1463
  // CONSTRUCTOR & FACTORY
1368
1464
  // ═══════════════════════════════════════════════════════════════════
1369
1465
  constructor(config) {
1466
+ if (config.protocolVersion && UNSUPPORTED_PROTOCOL_VERSIONS.includes(config.protocolVersion)) {
1467
+ throw new Error(
1468
+ `McpTestClient does not support protocol version ${config.protocolVersion}: it has no initialize handshake. Use ${DEFAULT_PROTOCOL_VERSION} or earlier.`
1469
+ );
1470
+ }
1370
1471
  this.config = {
1371
1472
  baseUrl: config.baseUrl,
1372
1473
  entryPath: config.entryPath,
@@ -1452,6 +1553,7 @@ var McpTestClient = class {
1452
1553
  jsonrpc: "2.0",
1453
1554
  method: "notifications/initialized"
1454
1555
  });
1556
+ await this.transport.openNotificationStream?.(this.initResult.protocolVersion);
1455
1557
  this.log("info", `Connected to ${this.initResult.serverInfo?.name ?? "MCP Server"}`);
1456
1558
  return this.initResult;
1457
1559
  }
@@ -1562,8 +1664,8 @@ var McpTestClient = class {
1562
1664
  /**
1563
1665
  * Call a tool by name with arguments
1564
1666
  */
1565
- call: async (name, args) => {
1566
- const response = await this.callTool(name, args);
1667
+ call: async (name, args, options = {}) => {
1668
+ const response = await this.callTool(name, args, this.progressTokenFor(options));
1567
1669
  return this.wrapToolResult(response);
1568
1670
  }
1569
1671
  };
@@ -1705,6 +1807,7 @@ var McpTestClient = class {
1705
1807
  * Collect progress notifications specifically
1706
1808
  */
1707
1809
  collectProgress: () => {
1810
+ this.collectingProgress = true;
1708
1811
  return new ProgressCollector(this._progressUpdates);
1709
1812
  },
1710
1813
  /**
@@ -2010,12 +2113,29 @@ var McpTestClient = class {
2010
2113
  async listTools() {
2011
2114
  return this.request("tools/list", {});
2012
2115
  }
2013
- async callTool(name, args) {
2116
+ async callTool(name, args, progressToken) {
2014
2117
  return this.request("tools/call", {
2015
2118
  name,
2016
- arguments: args ?? {}
2119
+ arguments: args ?? {},
2120
+ ...progressToken !== void 0 && { _meta: { progressToken } }
2017
2121
  });
2018
2122
  }
2123
+ progressTokenFor(options) {
2124
+ if (options.progressToken !== void 0) return options.progressToken;
2125
+ return this.collectingProgress ? `progress-${++this.progressTokenCounter}` : void 0;
2126
+ }
2127
+ recordNotification = (notification) => {
2128
+ const timestamp = /* @__PURE__ */ new Date();
2129
+ this._notifications.push({ method: notification.method, params: notification.params, timestamp });
2130
+ if (notification.method !== "notifications/progress") return;
2131
+ const { progress, total, progressToken } = notification.params ?? {};
2132
+ this._progressUpdates.push({
2133
+ progress: Number(progress),
2134
+ total: typeof total === "number" ? total : void 0,
2135
+ progressToken: typeof progressToken === "string" || typeof progressToken === "number" ? progressToken : void 0,
2136
+ timestamp
2137
+ });
2138
+ };
2019
2139
  async listResources() {
2020
2140
  return this.request("resources/list", {});
2021
2141
  }
@@ -2062,7 +2182,8 @@ var McpTestClient = class {
2062
2182
  debug: this.config.debug,
2063
2183
  interceptors: this._interceptors,
2064
2184
  clientInfo: this.config.clientInfo,
2065
- elicitationHandler: this._elicitationHandler
2185
+ elicitationHandler: this._elicitationHandler,
2186
+ notificationHandler: this.recordNotification
2066
2187
  });
2067
2188
  case "sse":
2068
2189
  throw new Error("SSE transport not yet implemented");
@@ -5598,18 +5719,17 @@ var toBeError = function(received, expectedCode) {
5598
5719
  message: () => `Expected a result wrapper object with isError property`
5599
5720
  };
5600
5721
  }
5601
- let pass = result.isError;
5602
- if (pass && expectedCode !== void 0) {
5603
- pass = result.error?.code === expectedCode;
5604
- }
5722
+ const receivedCode = typeof expectedCode === "string" ? result.raw?._meta?.["code"] : result.error?.code;
5723
+ const codeMatches = expectedCode === void 0 || receivedCode === expectedCode;
5724
+ const pass = result.isError && codeMatches;
5605
5725
  return {
5606
5726
  pass,
5607
5727
  message: () => {
5608
5728
  if (!result.isError) {
5609
5729
  return "Expected result to be an error, but it was successful";
5610
5730
  }
5611
- if (expectedCode !== void 0 && result.error?.code !== expectedCode) {
5612
- return `Expected error code ${expectedCode}, but got ${result.error?.code}`;
5731
+ if (!codeMatches) {
5732
+ return `Expected error code ${expectedCode}, but got ${String(receivedCode)}`;
5613
5733
  }
5614
5734
  return "Expected result not to be an error";
5615
5735
  }
package/matchers/index.js CHANGED
@@ -389,18 +389,17 @@ var toBeError = function(received, expectedCode) {
389
389
  message: () => `Expected a result wrapper object with isError property`
390
390
  };
391
391
  }
392
- let pass = result.isError;
393
- if (pass && expectedCode !== void 0) {
394
- pass = result.error?.code === expectedCode;
395
- }
392
+ const receivedCode = typeof expectedCode === "string" ? result.raw?._meta?.["code"] : result.error?.code;
393
+ const codeMatches = expectedCode === void 0 || receivedCode === expectedCode;
394
+ const pass = result.isError && codeMatches;
396
395
  return {
397
396
  pass,
398
397
  message: () => {
399
398
  if (!result.isError) {
400
399
  return "Expected result to be an error, but it was successful";
401
400
  }
402
- if (expectedCode !== void 0 && result.error?.code !== expectedCode) {
403
- return `Expected error code ${expectedCode}, but got ${result.error?.code}`;
401
+ if (!codeMatches) {
402
+ return `Expected error code ${expectedCode}, but got ${String(receivedCode)}`;
404
403
  }
405
404
  return "Expected result not to be an error";
406
405
  }
@@ -32,16 +32,17 @@ export interface McpMatchers<R = unknown> {
32
32
  toBeSuccessful(): R;
33
33
  /**
34
34
  * Check if result is an error, optionally with a specific error code
35
- * @param expectedCode - Optional specific MCP error code to match
35
+ * @param expectedCode - A JSON-RPC error code (number), or a tool error code (string) matched against `_meta.code`
36
36
  *
37
37
  * @example
38
38
  * ```typescript
39
39
  * const result = await mcp.tools.call('unknown-tool', {});
40
40
  * expect(result).toBeError();
41
41
  * expect(result).toBeError(-32601); // Method not found
42
+ * expect(await mcp.tools.call('add', { a: 5 })).toBeError('INVALID_INPUT');
42
43
  * ```
43
44
  */
44
- toBeError(expectedCode?: number): R;
45
+ toBeError(expectedCode?: number | string): R;
45
46
  /**
46
47
  * Check if tool result has text content, optionally containing specific text
47
48
  * @param expectedText - Optional text that should be contained in the result
@@ -1 +1 @@
1
- {"version":3,"file":"matcher-types.d.ts","sourceRoot":"","sources":["../../src/matchers/matcher-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IAKtC;;;;;;;;;OASG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;IAEnC;;;;;;;;OAQG;IACH,cAAc,IAAI,CAAC,CAAC;IAEpB;;;;;;;;;;OAUG;IACH,SAAS,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC;IAEpC;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC;IAE5C;;;;;;;;OAQG;IACH,kBAAkB,IAAI,CAAC,CAAC;IAExB;;;;;;;;OAQG;IACH,qBAAqB,IAAI,CAAC,CAAC;IAM3B;;;;;;;;;OASG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC;IAElC;;;;;;;;;OASG;IACH,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC;IAElD;;;;;;;;;OASG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;IAMpC;;;;;;;;;OASG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC;IAEjC;;;;;;;;;OASG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC;IAMjC;;;;;;;;OAQG;IACH,gBAAgB,IAAI,CAAC,CAAC;IAEtB;;;;;;;;OAQG;IACH,YAAY,IAAI,CAAC,CAAC;IAElB;;;;;;;;OAQG;IACH,WAAW,IAAI,CAAC,CAAC;IAEjB;;;;;;;;;OASG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC;IAMjC;;;;;;;;;OASG;IACH,kBAAkB,IAAI,CAAC,CAAC;IAExB;;;;;;;;;OASG;IACH,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC;IAErC;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;IAE/C;;;;;;;OAOG;IACH,WAAW,IAAI,CAAC,CAAC;IAEjB;;;;;;;OAOG;IACH,oBAAoB,IAAI,CAAC,CAAC;IAE1B;;;;;;;;OAQG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,CAAC,CAAC;IAErC;;;;;;;;;OASG;IACH,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;IAE3C;;;;;;;OAOG;IACH,yBAAyB,IAAI,CAAC,CAAC;CAChC;AAQD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,IAAI,CAAC;QAEb,UAAU,QAAQ,CAAC,CAAC,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAC;SAAG;QAG/C,UAAU,MAAO,SAAQ,WAAW,CAAC,IAAI,CAAC;SAAG;QAG7C,UAAU,yBAA0B,SAAQ,WAAW,CAAC,IAAI,CAAC;SAAG;KACjE;CACF;AAID,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"matcher-types.d.ts","sourceRoot":"","sources":["../../src/matchers/matcher-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH;;GAEG;AACH,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IAKtC;;;;;;;;;OASG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;IAEnC;;;;;;;;OAQG;IACH,cAAc,IAAI,CAAC,CAAC;IAEpB;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;IAE7C;;;;;;;;;;OAUG;IACH,iBAAiB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC;IAE5C;;;;;;;;OAQG;IACH,kBAAkB,IAAI,CAAC,CAAC;IAExB;;;;;;;;OAQG;IACH,qBAAqB,IAAI,CAAC,CAAC;IAM3B;;;;;;;;;OASG;IACH,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC;IAElC;;;;;;;;;OASG;IACH,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,CAAC,CAAC;IAElD;;;;;;;;;OASG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,CAAC,CAAC;IAMpC;;;;;;;;;OASG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC;IAEjC;;;;;;;;;OASG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,CAAC;IAMjC;;;;;;;;OAQG;IACH,gBAAgB,IAAI,CAAC,CAAC;IAEtB;;;;;;;;OAQG;IACH,YAAY,IAAI,CAAC,CAAC;IAElB;;;;;;;;OAQG;IACH,WAAW,IAAI,CAAC,CAAC;IAEjB;;;;;;;;;OASG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,CAAC;IAMjC;;;;;;;;;OASG;IACH,kBAAkB,IAAI,CAAC,CAAC;IAExB;;;;;;;;;OASG;IACH,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC;IAErC;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC;IAE/C;;;;;;;OAOG;IACH,WAAW,IAAI,CAAC,CAAC;IAEjB;;;;;;;OAOG;IACH,oBAAoB,IAAI,CAAC,CAAC;IAE1B;;;;;;;;OAQG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,CAAC,CAAC;IAErC;;;;;;;;;OASG;IACH,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,CAAC;IAE3C;;;;;;;OAOG;IACH,yBAAyB,IAAI,CAAC,CAAC;CAChC;AAQD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,IAAI,CAAC;QAEb,UAAU,QAAQ,CAAC,CAAC,CAAE,SAAQ,WAAW,CAAC,CAAC,CAAC;SAAG;QAG/C,UAAU,MAAO,SAAQ,WAAW,CAAC,IAAI,CAAC;SAAG;QAG7C,UAAU,yBAA0B,SAAQ,WAAW,CAAC,IAAI,CAAC;SAAG;KACjE;CACF;AAID,OAAO,EAAE,CAAC"}
@@ -38,7 +38,7 @@ export declare const mcpMatchers: {
38
38
  toHavePlatformHtml: MatcherFunction<[platform: import("..").TestPlatformType]>;
39
39
  toContainTool: MatcherFunction<[toolName: string]>;
40
40
  toBeSuccessful: MatcherFunction<[]>;
41
- toBeError: MatcherFunction<[expectedCode?: number | undefined]>;
41
+ toBeError: MatcherFunction<[expectedCode?: string | number | undefined]>;
42
42
  toHaveTextContent: MatcherFunction<[expectedText?: string | undefined]>;
43
43
  toHaveImageContent: MatcherFunction<[]>;
44
44
  toHaveResourceContent: MatcherFunction<[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-matchers.d.ts","sourceRoot":"","sources":["../../src/matchers/mcp-matchers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AA+a9C;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BvB,CAAC"}
1
+ {"version":3,"file":"mcp-matchers.d.ts","sourceRoot":"","sources":["../../src/matchers/mcp-matchers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AA6a9C;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BvB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frontmcp/testing",
3
- "version": "1.8.0",
3
+ "version": "1.8.2",
4
4
  "description": "E2E testing framework for FrontMCP servers - MCP client, auth mocks, Playwright integration",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://docs.agentfront.dev",
@@ -87,9 +87,9 @@
87
87
  "./esm": null
88
88
  },
89
89
  "peerDependencies": {
90
- "@frontmcp/lazy-zod": "1.8.0",
91
- "@frontmcp/sdk": "1.8.0",
92
- "@frontmcp/ui": "1.8.0",
90
+ "@frontmcp/lazy-zod": "1.8.2",
91
+ "@frontmcp/sdk": "1.8.2",
92
+ "@frontmcp/ui": "1.8.2",
93
93
  "@jest/globals": "^29.0.0 || ^30.0.0",
94
94
  "@playwright/test": "^1.40.0",
95
95
  "jest": "^29.0.0 || ^30.0.0"
@@ -112,8 +112,8 @@
112
112
  "node": ">=24.0.0"
113
113
  },
114
114
  "dependencies": {
115
- "@frontmcp/protocol": "1.8.0",
116
- "@frontmcp/utils": "1.8.0",
115
+ "@frontmcp/protocol": "1.8.2",
116
+ "@frontmcp/utils": "1.8.2",
117
117
  "jose": "^6.0.11",
118
118
  "tslib": "^2.3.0"
119
119
  },