@adcp/sdk 17.0.0-beta.0 → 17.0.0-beta.1

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.
Files changed (70) hide show
  1. package/dist/lib/adapters/version/3.1/bidding.js +1 -1
  2. package/dist/lib/adapters/version/3.1/bidding.mjs +1 -1
  3. package/dist/lib/core/ResponseValidator.js +1 -1
  4. package/dist/lib/core/ResponseValidator.mjs +1 -1
  5. package/dist/lib/core/SingleAgentClient.d.mts +7 -5
  6. package/dist/lib/core/SingleAgentClient.d.ts +7 -5
  7. package/dist/lib/core/SingleAgentClient.js +57 -32
  8. package/dist/lib/core/SingleAgentClient.mjs +59 -33
  9. package/dist/lib/core/TaskExecutor.js +5 -3
  10. package/dist/lib/core/TaskExecutor.mjs +5 -3
  11. package/dist/lib/errors/index.d.mts +22 -0
  12. package/dist/lib/errors/index.d.ts +22 -0
  13. package/dist/lib/errors/index.js +43 -0
  14. package/dist/lib/errors/index.mjs +42 -0
  15. package/dist/lib/index.d.mts +1 -1
  16. package/dist/lib/index.d.ts +1 -1
  17. package/dist/lib/index.js +2 -0
  18. package/dist/lib/index.mjs +2 -0
  19. package/dist/lib/protocols/mcp-modern.d.mts +2 -0
  20. package/dist/lib/protocols/mcp-modern.d.ts +2 -0
  21. package/dist/lib/protocols/mcp-modern.js +31 -5
  22. package/dist/lib/protocols/mcp-modern.mjs +31 -5
  23. package/dist/lib/protocols/mcp-scope.d.mts +3 -1
  24. package/dist/lib/protocols/mcp-scope.d.ts +3 -1
  25. package/dist/lib/protocols/mcp-scope.js +19 -2
  26. package/dist/lib/protocols/mcp-scope.mjs +18 -2
  27. package/dist/lib/protocols/mcp.js +12 -6
  28. package/dist/lib/protocols/mcp.mjs +13 -6
  29. package/dist/lib/testing/client.d.mts +1 -0
  30. package/dist/lib/testing/client.d.ts +1 -0
  31. package/dist/lib/testing/client.js +6 -5
  32. package/dist/lib/testing/client.mjs +6 -5
  33. package/dist/lib/testing/storyboard/agent-routing.d.mts +5 -2
  34. package/dist/lib/testing/storyboard/agent-routing.d.ts +5 -2
  35. package/dist/lib/testing/storyboard/agent-routing.js +11 -4
  36. package/dist/lib/testing/storyboard/agent-routing.mjs +11 -4
  37. package/dist/lib/testing/storyboard/context.d.mts +13 -3
  38. package/dist/lib/testing/storyboard/context.d.ts +13 -3
  39. package/dist/lib/testing/storyboard/context.js +15 -10
  40. package/dist/lib/testing/storyboard/context.mjs +15 -10
  41. package/dist/lib/testing/storyboard/runner.js +141 -13
  42. package/dist/lib/testing/storyboard/runner.mjs +141 -13
  43. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  44. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  45. package/dist/lib/testing/storyboard/validations.js +4 -1
  46. package/dist/lib/testing/storyboard/validations.mjs +4 -1
  47. package/dist/lib/testing/test-controller.js +3 -0
  48. package/dist/lib/testing/test-controller.mjs +3 -0
  49. package/dist/lib/utils/envelope-status-compat.d.mts +18 -1
  50. package/dist/lib/utils/envelope-status-compat.d.ts +18 -1
  51. package/dist/lib/utils/envelope-status-compat.js +11 -5
  52. package/dist/lib/utils/envelope-status-compat.mjs +11 -5
  53. package/dist/lib/utils/response-unwrapper.js +12 -9
  54. package/dist/lib/utils/response-unwrapper.mjs +12 -9
  55. package/dist/lib/v2/projection/creative-delivery.js +56 -11
  56. package/dist/lib/v2/projection/creative-delivery.mjs +56 -11
  57. package/dist/lib/validation/schema-validator.js +1 -1
  58. package/dist/lib/validation/schema-validator.mjs +1 -1
  59. package/dist/lib/version.d.mts +3 -3
  60. package/dist/lib/version.d.ts +3 -3
  61. package/dist/lib/version.js +3 -3
  62. package/dist/lib/version.mjs +3 -3
  63. package/docs/TYPE-SUMMARY.md +2 -2
  64. package/docs/guides/COLLECTION-FIXTURE-FOUNDATION.md +11 -0
  65. package/docs/guides/DISCOVERY-CACHE-AND-SESSION-REUSE.md +12 -1
  66. package/docs/llms.txt +2 -2
  67. package/docs/migration-14.x-rc-worksheet.md +4 -4
  68. package/docs/migration-16-to-17.md +24 -1
  69. package/docs/migration-reporting-storage-package.md +1 -1
  70. package/package.json +1 -1
@@ -28,6 +28,7 @@ __export(errors_exports, {
28
28
  AccountSetupRequiredError: () => AccountSetupRequiredError,
29
29
  ActionNotAllowedError: () => ActionNotAllowedError,
30
30
  AgentNotFoundError: () => AgentNotFoundError,
31
+ AgentRateLimitedError: () => AgentRateLimitedError,
31
32
  AuthenticationCredentialsRejectedError: () => AuthenticationCredentialsRejectedError,
32
33
  AuthenticationRequiredError: () => AuthenticationRequiredError,
33
34
  BuyerSetupError: () => BuyerSetupError,
@@ -474,6 +475,47 @@ class ResponseTooLargeError extends ADCPError {
474
475
  contentLengthHeader;
475
476
  code = "RESPONSE_TOO_LARGE";
476
477
  }
478
+ class AgentRateLimitedError extends ADCPError {
479
+ constructor(agentUrl, status, retryAfter, cause) {
480
+ const safeAgentUrl = sanitizeAgentUrlForError(agentUrl);
481
+ const retryAfterMs = parseRetryAfterMs(retryAfter);
482
+ const validRetryAfter = retryAfterMs === void 0 ? void 0 : retryAfter?.trim();
483
+ const retryHint = retryAfterMs === void 0 ? "No usable Retry-After header; back off before retrying." : `Retry-After: ${validRetryAfter} (${Math.ceil(retryAfterMs / 1e3)}s).`;
484
+ super(
485
+ `Agent rate limited MCP endpoint discovery: HTTP ${status} from ${safeAgentUrl}. ${retryHint} Discovery stopped at this probe to avoid spending more of the agent's request budget; this does not indicate a wrong agent_uri.`
486
+ );
487
+ this.status = status;
488
+ this.agentUrl = safeAgentUrl;
489
+ if (retryAfterMs !== void 0) {
490
+ this.retryAfter = validRetryAfter;
491
+ this.retryAfterMs = retryAfterMs;
492
+ }
493
+ this.details = {
494
+ agentUrl: safeAgentUrl,
495
+ status,
496
+ ...retryAfterMs !== void 0 && { retryAfter: validRetryAfter, retryAfterMs }
497
+ };
498
+ if (cause !== void 0) {
499
+ Object.defineProperty(this, "cause", { value: cause, enumerable: false, configurable: true });
500
+ }
501
+ }
502
+ status;
503
+ code = "RATE_LIMITED";
504
+ /** The probed URL, without credentials, query or fragment. */
505
+ agentUrl;
506
+ /** `Retry-After` as the agent sent it. Set only when it is valid delta-seconds or an HTTP-date. */
507
+ retryAfter;
508
+ /** Delay from `Retry-After`, in milliseconds. */
509
+ retryAfterMs;
510
+ }
511
+ function parseRetryAfterMs(value) {
512
+ const trimmed = value?.trim();
513
+ if (!trimmed) return void 0;
514
+ if (/^\d{1,10}$/.test(trimmed)) return Number(trimmed) * 1e3;
515
+ if (!/^[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} GMT$/.test(trimmed)) return void 0;
516
+ const date = Date.parse(trimmed);
517
+ return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
518
+ }
477
519
  class ActionNotAllowedError extends ADCPError {
478
520
  code = "ACTION_NOT_ALLOWED";
479
521
  attemptedAction;
@@ -677,6 +719,7 @@ class PreparedFixturesDeniedError extends ADCPError {
677
719
  AccountSetupRequiredError,
678
720
  ActionNotAllowedError,
679
721
  AgentNotFoundError,
722
+ AgentRateLimitedError,
680
723
  AuthenticationCredentialsRejectedError,
681
724
  AuthenticationRequiredError,
682
725
  BuyerSetupError,
@@ -413,6 +413,47 @@ class ResponseTooLargeError extends ADCPError {
413
413
  contentLengthHeader;
414
414
  code = "RESPONSE_TOO_LARGE";
415
415
  }
416
+ class AgentRateLimitedError extends ADCPError {
417
+ constructor(agentUrl, status, retryAfter, cause) {
418
+ const safeAgentUrl = sanitizeAgentUrlForError(agentUrl);
419
+ const retryAfterMs = parseRetryAfterMs(retryAfter);
420
+ const validRetryAfter = retryAfterMs === void 0 ? void 0 : retryAfter?.trim();
421
+ const retryHint = retryAfterMs === void 0 ? "No usable Retry-After header; back off before retrying." : `Retry-After: ${validRetryAfter} (${Math.ceil(retryAfterMs / 1e3)}s).`;
422
+ super(
423
+ `Agent rate limited MCP endpoint discovery: HTTP ${status} from ${safeAgentUrl}. ${retryHint} Discovery stopped at this probe to avoid spending more of the agent's request budget; this does not indicate a wrong agent_uri.`
424
+ );
425
+ this.status = status;
426
+ this.agentUrl = safeAgentUrl;
427
+ if (retryAfterMs !== void 0) {
428
+ this.retryAfter = validRetryAfter;
429
+ this.retryAfterMs = retryAfterMs;
430
+ }
431
+ this.details = {
432
+ agentUrl: safeAgentUrl,
433
+ status,
434
+ ...retryAfterMs !== void 0 && { retryAfter: validRetryAfter, retryAfterMs }
435
+ };
436
+ if (cause !== void 0) {
437
+ Object.defineProperty(this, "cause", { value: cause, enumerable: false, configurable: true });
438
+ }
439
+ }
440
+ status;
441
+ code = "RATE_LIMITED";
442
+ /** The probed URL, without credentials, query or fragment. */
443
+ agentUrl;
444
+ /** `Retry-After` as the agent sent it. Set only when it is valid delta-seconds or an HTTP-date. */
445
+ retryAfter;
446
+ /** Delay from `Retry-After`, in milliseconds. */
447
+ retryAfterMs;
448
+ }
449
+ function parseRetryAfterMs(value) {
450
+ const trimmed = value?.trim();
451
+ if (!trimmed) return void 0;
452
+ if (/^\d{1,10}$/.test(trimmed)) return Number(trimmed) * 1e3;
453
+ if (!/^[A-Z][a-z]{2}, \d{2} [A-Z][a-z]{2} \d{4} \d{2}:\d{2}:\d{2} GMT$/.test(trimmed)) return void 0;
454
+ const date = Date.parse(trimmed);
455
+ return Number.isNaN(date) ? void 0 : Math.max(0, date - Date.now());
456
+ }
416
457
  class ActionNotAllowedError extends ADCPError {
417
458
  code = "ACTION_NOT_ALLOWED";
418
459
  attemptedAction;
@@ -615,6 +656,7 @@ export {
615
656
  AccountSetupRequiredError,
616
657
  ActionNotAllowedError,
617
658
  AgentNotFoundError,
659
+ AgentRateLimitedError,
618
660
  AuthenticationCredentialsRejectedError,
619
661
  AuthenticationRequiredError,
620
662
  BuyerSetupError,
@@ -57,7 +57,7 @@ export * from './handlers/types.mjs';
57
57
  export type { Storage, AtomicTakeStorage, DeferredTaskStorage, BatchStorage, PatternStorage, AgentCapabilities, ConversationState, DeferredTaskState, StorageConfig, StorageFactory, StorageMiddleware, } from './storage/interfaces.mjs';
58
58
  export { MemoryStorage, createMemoryStorage, createMemoryStorageConfig } from './storage/MemoryStorage.mjs';
59
59
  export { ADCPError, TaskTimeoutError, MaxClarificationError, DeferredTaskError, TaskAbortedError, AgentNotFoundError, UnsupportedTaskError, ProtocolError, ValidationError as ADCPValidationError, // Rename to avoid conflict
60
- MissingInputHandlerError, InvalidContextError, ConfigurationError, AuthenticationCredentialsRejectedError, AuthenticationRequiredError, FeatureUnsupportedError, ProtocolFeatureUnsupportedError, UnsupportedBuyingModeError, AccountRequiredError, AccountPendingApprovalError, AccountAmbiguousError, BuyerSetupError, AccountNotFoundError, AccountSetupRequiredError, AccountPaymentRequiredError, AccountNotProvisionedError, SDK_ERROR_TO_PROTOCOL_ERROR_CODE, VersionUnsupportedError, IdempotencyConflictError, IdempotencyExpiredError, ResponseTooLargeError, ActionNotAllowedError, PreparedFixturesDeniedError, adcpErrorToTypedError, getClientPreflightAdcpError, isADCPError, isErrorOfType, extractErrorInfo, is401Error, mapSdkErrorCodeToProtocolErrorCode, } from './errors/index.mjs';
60
+ MissingInputHandlerError, InvalidContextError, ConfigurationError, AuthenticationCredentialsRejectedError, AuthenticationRequiredError, FeatureUnsupportedError, ProtocolFeatureUnsupportedError, UnsupportedBuyingModeError, AccountRequiredError, AccountPendingApprovalError, AccountAmbiguousError, BuyerSetupError, AccountNotFoundError, AccountSetupRequiredError, AccountPaymentRequiredError, AccountNotProvisionedError, SDK_ERROR_TO_PROTOCOL_ERROR_CODE, VersionUnsupportedError, IdempotencyConflictError, IdempotencyExpiredError, ResponseTooLargeError, AgentRateLimitedError, ActionNotAllowedError, PreparedFixturesDeniedError, adcpErrorToTypedError, getClientPreflightAdcpError, isADCPError, isErrorOfType, extractErrorInfo, is401Error, mapSdkErrorCodeToProtocolErrorCode, } from './errors/index.mjs';
61
61
  export type { OAuthMetadataInfo, ClientPreflightAdcpErrorInfo, ClientPreflightAdcpErrorRecovery, FeatureUnsupportedErrorOptions, ProtocolFeatureUnsupportedErrorOptions, ActionNotAllowedErrorDetails, ActionNotAllowedReasonValue, ActionNotAllowedAttemptedAction, ActionNotAllowedAvailableAction, ActionNotAllowedRecovery, } from './errors/index.mjs';
62
62
  export type { ActionNotAllowedDetails, ActionNotAllowedReason, AvailableActionsResult, AvailableActionsSource, DecomposedUpdateMediaBuy, DecomposedUpdateMediaBuyMutation, LegacyCoarseAction, MediaBuyActionContext, MediaBuyActionId, MediaBuyActionMode, MediaBuyAvailableAction, MediaBuyMutationDirection, MediaBuyMutationScope, MediaBuyUpdateFieldAction, MediaBuyValidAction, ModeMismatchRecovery, PreflightAllowed, PreflightDenial, PreflightDenied, BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPolicyResolvedProperty, ProductPropertyPolicyIdentifier, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, PreflightResult, ResolvedAction, SLAWindow, SlaWindow, StructuredOnlyMediaBuyAction, ResolvedTargetingInput, TargetingInputFor, ValidateProductsAgainstPropertyPolicyOptions, UpdateFieldEntry, UpdateMediaBuyRequestLike, } from './media-buy/index.mjs';
63
63
  export { ACTIONS_BY_FIELD, LEGACY_COARSE_ACTIONS, STRUCTURED_ONLY_MEDIA_BUY_ACTIONS, UPDATE_FIELDS_BY_ACTION, applyTargetingInput, hasTargetingClears, resolveTargetingInput, canAddPackages, canCancel, canDecreaseBudget, canExtendFlight, canIncreaseBudget, canPause, canReallocateBudget, canRemoveCreative, canRemovePackages, canReplaceCreative, canResume, canShortenFlight, canUpdateCreativeAssignments, canUpdateFlightDates, canUpdateFrequencyCaps, canUpdatePacing, canUpdateTargeting, decomposeUpdateMediaBuy, findAvailableAction, getActionForMutation, getAvailableActions, getRollupParent, ProductPropertyPolicyError, normalizeDomainForPropertyPolicy, preflightUpdateMediaBuy, recoveryForModeMismatch, validateProductsAgainstPropertyPolicy, } from './media-buy/index.mjs';
@@ -57,7 +57,7 @@ export * from './handlers/types';
57
57
  export type { Storage, AtomicTakeStorage, DeferredTaskStorage, BatchStorage, PatternStorage, AgentCapabilities, ConversationState, DeferredTaskState, StorageConfig, StorageFactory, StorageMiddleware, } from './storage/interfaces';
58
58
  export { MemoryStorage, createMemoryStorage, createMemoryStorageConfig } from './storage/MemoryStorage';
59
59
  export { ADCPError, TaskTimeoutError, MaxClarificationError, DeferredTaskError, TaskAbortedError, AgentNotFoundError, UnsupportedTaskError, ProtocolError, ValidationError as ADCPValidationError, // Rename to avoid conflict
60
- MissingInputHandlerError, InvalidContextError, ConfigurationError, AuthenticationCredentialsRejectedError, AuthenticationRequiredError, FeatureUnsupportedError, ProtocolFeatureUnsupportedError, UnsupportedBuyingModeError, AccountRequiredError, AccountPendingApprovalError, AccountAmbiguousError, BuyerSetupError, AccountNotFoundError, AccountSetupRequiredError, AccountPaymentRequiredError, AccountNotProvisionedError, SDK_ERROR_TO_PROTOCOL_ERROR_CODE, VersionUnsupportedError, IdempotencyConflictError, IdempotencyExpiredError, ResponseTooLargeError, ActionNotAllowedError, PreparedFixturesDeniedError, adcpErrorToTypedError, getClientPreflightAdcpError, isADCPError, isErrorOfType, extractErrorInfo, is401Error, mapSdkErrorCodeToProtocolErrorCode, } from './errors';
60
+ MissingInputHandlerError, InvalidContextError, ConfigurationError, AuthenticationCredentialsRejectedError, AuthenticationRequiredError, FeatureUnsupportedError, ProtocolFeatureUnsupportedError, UnsupportedBuyingModeError, AccountRequiredError, AccountPendingApprovalError, AccountAmbiguousError, BuyerSetupError, AccountNotFoundError, AccountSetupRequiredError, AccountPaymentRequiredError, AccountNotProvisionedError, SDK_ERROR_TO_PROTOCOL_ERROR_CODE, VersionUnsupportedError, IdempotencyConflictError, IdempotencyExpiredError, ResponseTooLargeError, AgentRateLimitedError, ActionNotAllowedError, PreparedFixturesDeniedError, adcpErrorToTypedError, getClientPreflightAdcpError, isADCPError, isErrorOfType, extractErrorInfo, is401Error, mapSdkErrorCodeToProtocolErrorCode, } from './errors';
61
61
  export type { OAuthMetadataInfo, ClientPreflightAdcpErrorInfo, ClientPreflightAdcpErrorRecovery, FeatureUnsupportedErrorOptions, ProtocolFeatureUnsupportedErrorOptions, ActionNotAllowedErrorDetails, ActionNotAllowedReasonValue, ActionNotAllowedAttemptedAction, ActionNotAllowedAvailableAction, ActionNotAllowedRecovery, } from './errors';
62
62
  export type { ActionNotAllowedDetails, ActionNotAllowedReason, AvailableActionsResult, AvailableActionsSource, DecomposedUpdateMediaBuy, DecomposedUpdateMediaBuyMutation, LegacyCoarseAction, MediaBuyActionContext, MediaBuyActionId, MediaBuyActionMode, MediaBuyAvailableAction, MediaBuyMutationDirection, MediaBuyMutationScope, MediaBuyUpdateFieldAction, MediaBuyValidAction, ModeMismatchRecovery, PreflightAllowed, PreflightDenial, PreflightDenied, BuyerPropertyPolicy, NormalizedPolicyDomain, ProductPolicyProductLike, ProductPolicyResolvedProperty, ProductPropertyPolicyIdentifier, ProductPropertyPolicyDiagnostic, ProductPropertyPolicyDiagnosticCode, ProductPropertyPolicyDiagnosticSeverity, ProductPropertyPolicyMode, ProductPropertyPolicySelectorBehavior, ProductPropertyPolicyValidationResult, PreflightResult, ResolvedAction, SLAWindow, SlaWindow, StructuredOnlyMediaBuyAction, ResolvedTargetingInput, TargetingInputFor, ValidateProductsAgainstPropertyPolicyOptions, UpdateFieldEntry, UpdateMediaBuyRequestLike, } from './media-buy';
63
63
  export { ACTIONS_BY_FIELD, LEGACY_COARSE_ACTIONS, STRUCTURED_ONLY_MEDIA_BUY_ACTIONS, UPDATE_FIELDS_BY_ACTION, applyTargetingInput, hasTargetingClears, resolveTargetingInput, canAddPackages, canCancel, canDecreaseBudget, canExtendFlight, canIncreaseBudget, canPause, canReallocateBudget, canRemoveCreative, canRemovePackages, canReplaceCreative, canResume, canShortenFlight, canUpdateCreativeAssignments, canUpdateFlightDates, canUpdateFrequencyCaps, canUpdatePacing, canUpdateTargeting, decomposeUpdateMediaBuy, findAvailableAction, getActionForMutation, getAvailableActions, getRollupParent, ProductPropertyPolicyError, normalizeDomainForPropertyPolicy, preflightUpdateMediaBuy, recoveryForModeMismatch, validateProductsAgainstPropertyPolicy, } from './media-buy';
package/dist/lib/index.js CHANGED
@@ -49,6 +49,7 @@ __export(index_exports, {
49
49
  AgentClient: () => import_AgentClient.AgentClient,
50
50
  AgentNotFoundError: () => import_errors.AgentNotFoundError,
51
51
  AgentOAuthClientCredentialsSchema: () => import_oauth4.AgentOAuthClientCredentialsSchema,
52
+ AgentRateLimitedError: () => import_errors.AgentRateLimitedError,
52
53
  Asset: () => import_asset_builders.Asset,
53
54
  AsyncHandler: () => import_AsyncHandler.AsyncHandler,
54
55
  AuthenticationCredentialsRejectedError: () => import_errors.AuthenticationCredentialsRejectedError,
@@ -896,6 +897,7 @@ function createAdCPClientFromEnv() {
896
897
  AgentClient,
897
898
  AgentNotFoundError,
898
899
  AgentOAuthClientCredentialsSchema,
900
+ AgentRateLimitedError,
899
901
  Asset,
900
902
  AsyncHandler,
901
903
  AuthenticationCredentialsRejectedError,
@@ -234,6 +234,7 @@ import {
234
234
  IdempotencyConflictError,
235
235
  IdempotencyExpiredError,
236
236
  ResponseTooLargeError,
237
+ AgentRateLimitedError,
237
238
  ActionNotAllowedError,
238
239
  PreparedFixturesDeniedError,
239
240
  adcpErrorToTypedError,
@@ -858,6 +859,7 @@ export {
858
859
  AgentClient,
859
860
  AgentNotFoundError,
860
861
  AgentOAuthClientCredentialsSchema,
862
+ AgentRateLimitedError,
861
863
  Asset,
862
864
  AsyncHandler,
863
865
  AuthenticationCredentialsRejectedError,
@@ -41,6 +41,8 @@ export interface ModernMCPConnectionOptions {
41
41
  /** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */
42
42
  handleLegacy?: boolean;
43
43
  }
44
+ /** `Retry-After` recorded on an MCP connect error by {@link withRetryAfter}, if any. */
45
+ export declare function retryAfterOf(error: unknown): string | undefined;
44
46
  /**
45
47
  * Try a tool call using the MCP 2026-07-28 protocol era.
46
48
  *
@@ -41,6 +41,8 @@ export interface ModernMCPConnectionOptions {
41
41
  /** Use the v2 SDK's negotiated legacy client instead of handing off to v1. */
42
42
  handleLegacy?: boolean;
43
43
  }
44
+ /** `Retry-After` recorded on an MCP connect error by {@link withRetryAfter}, if any. */
45
+ export declare function retryAfterOf(error: unknown): string | undefined;
44
46
  /**
45
47
  * Try a tool call using the MCP 2026-07-28 protocol era.
46
48
  *
@@ -20,6 +20,7 @@ var mcp_modern_exports = {};
20
20
  __export(mcp_modern_exports, {
21
21
  closeModernMCPConnections: () => closeModernMCPConnections,
22
22
  probeModernMCPConnection: () => probeModernMCPConnection,
23
+ retryAfterOf: () => retryAfterOf,
23
24
  tryCallModernMCPTool: () => tryCallModernMCPTool,
24
25
  tryListModernMCPTools: () => tryListModernMCPTools
25
26
  });
@@ -248,9 +249,15 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
248
249
  getCapability: options.signingContext.getCapability,
249
250
  adcpVersion: options.signingContext.adcpVersion
250
251
  }) : diagnosticFetch;
252
+ const transportFetch = (0, import_rawResponseCapture.wrapFetchWithCapture)(withPerRequestTraceHeaders(signedFetch));
253
+ let throttleRetryAfter;
251
254
  const transport = new import_client.StreamableHTTPClientTransport(new URL(options.agentUrl), {
252
255
  requestInit: { headers: (0, import_mcp_call_context.splitConnectionHeaders)(authHeaders).identity, redirect: "manual" },
253
- fetch: (0, import_rawResponseCapture.wrapFetchWithCapture)(withPerRequestTraceHeaders(signedFetch)),
256
+ fetch: async (input, init) => {
257
+ const response = await transportFetch(input, init);
258
+ throttleRetryAfter = response.status === 429 || response.status === 503 ? response.headers.get("retry-after") ?? void 0 : void 0;
259
+ return response;
260
+ },
254
261
  ...options.authProvider && {
255
262
  authProvider: options.authProvider
256
263
  }
@@ -293,8 +300,22 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
293
300
  if (isNegotiationAuthFailure(error) && !skipProbe && presentedStaticCredential(authHeaders, options.authProvider)) {
294
301
  return createNegotiatedClient(cacheKey, options, authHeaders, useCachedDiscovery, true);
295
302
  }
296
- throw error;
303
+ throw withRetryAfter(error, throttleRetryAfter);
304
+ }
305
+ }
306
+ function withRetryAfter(error, retryAfter) {
307
+ if (retryAfter === void 0 || !error || typeof error !== "object") return error;
308
+ const status = httpStatusOf(error);
309
+ if (status !== 429 && status !== 503) return error;
310
+ try {
311
+ Object.defineProperty(error, "retryAfter", { value: retryAfter, enumerable: false, configurable: true });
312
+ } catch {
297
313
  }
314
+ return error;
315
+ }
316
+ function retryAfterOf(error) {
317
+ const value = error && typeof error === "object" ? error.retryAfter : void 0;
318
+ return typeof value === "string" ? value : void 0;
298
319
  }
299
320
  async function getOrCreateModernConnection(cacheKey, options, authHeaders) {
300
321
  for (let attempt = 0; ; attempt++) {
@@ -314,12 +335,12 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
314
335
  const promise = createNegotiatedClient(cacheKey, options, authHeaders).then(async (client) => {
315
336
  if ((client.getProtocolEra() === "modern" || options.handleLegacy === true) && generation === connectionGeneration) {
316
337
  modernConnections.set(cacheKey, client);
317
- (0, import_mcp_scope.registerMCPConnectionScopeCleanup)("modern", cacheKey, async () => {
338
+ (0, import_mcp_scope.registerMCPConnectionScopeCleanup)("modern", cacheKey, async (terminateSession) => {
318
339
  if (modernConnections.get(cacheKey) !== client) return;
319
340
  modernConnections.delete(cacheKey);
320
341
  legacyConnectionExpiresAt.delete(cacheKey);
321
342
  modernDiscoveries.delete(cacheKey);
322
- await closeModernClient(client);
343
+ await closeModernClient(client, terminateSession);
323
344
  });
324
345
  if (client.getProtocolEra() === "legacy") {
325
346
  legacyConnectionExpiresAt.set(cacheKey, Date.now() + LEGACY_CLASSIFICATION_TTL_MS);
@@ -341,7 +362,10 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
341
362
  return promise;
342
363
  }
343
364
  async function retireFailedConnection(cacheKey, client, error) {
344
- if ((0, import_abort.isAbortOrTimeoutError)(error)) return;
365
+ if ((0, import_abort.isAbortOrTimeoutError)(error)) {
366
+ (0, import_mcp_scope.markMCPConnectionScopeInterrupted)();
367
+ return;
368
+ }
345
369
  if (modernConnections.get(cacheKey) === client) {
346
370
  modernConnections.delete(cacheKey);
347
371
  legacyConnectionExpiresAt.delete(cacheKey);
@@ -510,6 +534,7 @@ async function probeModernMCPConnection(agentUrl, authToken, customHeaders, opti
510
534
  options.allowPrivateIp
511
535
  );
512
536
  const scoped = (0, import_mcp_connection_policy.shouldReuseMCPConnection)(options.fetchFn !== void 0);
537
+ if (isKnownLegacy(cacheKey)) return { connected: false };
513
538
  let client;
514
539
  return (0, import_mcp_call_context.runWithMCPCallContext)(
515
540
  callContextFor({ customHeaders, requestTimeoutMs: options.requestTimeoutMs }),
@@ -650,6 +675,7 @@ async function closeModernMCPConnections() {
650
675
  0 && (module.exports = {
651
676
  closeModernMCPConnections,
652
677
  probeModernMCPConnection,
678
+ retryAfterOf,
653
679
  tryCallModernMCPTool,
654
680
  tryListModernMCPTools
655
681
  });
@@ -16,6 +16,7 @@ import { is401Error } from "../errors/index.mjs";
16
16
  import { withSpan, injectTraceHeaders } from "../observability/tracing.mjs";
17
17
  import {
18
18
  currentMCPConnectionScopeKey,
19
+ markMCPConnectionScopeInterrupted,
19
20
  isMCPConnectionScopeCacheKeyActive,
20
21
  registerMCPConnectionScopeCleanup,
21
22
  registerMCPConnectionScopePending
@@ -255,9 +256,15 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
255
256
  getCapability: options.signingContext.getCapability,
256
257
  adcpVersion: options.signingContext.adcpVersion
257
258
  }) : diagnosticFetch;
259
+ const transportFetch = wrapFetchWithCapture(withPerRequestTraceHeaders(signedFetch));
260
+ let throttleRetryAfter;
258
261
  const transport = new StreamableHTTPClientTransport(new URL(options.agentUrl), {
259
262
  requestInit: { headers: splitConnectionHeaders(authHeaders).identity, redirect: "manual" },
260
- fetch: wrapFetchWithCapture(withPerRequestTraceHeaders(signedFetch)),
263
+ fetch: async (input, init) => {
264
+ const response = await transportFetch(input, init);
265
+ throttleRetryAfter = response.status === 429 || response.status === 503 ? response.headers.get("retry-after") ?? void 0 : void 0;
266
+ return response;
267
+ },
261
268
  ...options.authProvider && {
262
269
  authProvider: options.authProvider
263
270
  }
@@ -300,8 +307,22 @@ async function createNegotiatedClient(cacheKey, options, authHeaders, useCachedD
300
307
  if (isNegotiationAuthFailure(error) && !skipProbe && presentedStaticCredential(authHeaders, options.authProvider)) {
301
308
  return createNegotiatedClient(cacheKey, options, authHeaders, useCachedDiscovery, true);
302
309
  }
303
- throw error;
310
+ throw withRetryAfter(error, throttleRetryAfter);
311
+ }
312
+ }
313
+ function withRetryAfter(error, retryAfter) {
314
+ if (retryAfter === void 0 || !error || typeof error !== "object") return error;
315
+ const status = httpStatusOf(error);
316
+ if (status !== 429 && status !== 503) return error;
317
+ try {
318
+ Object.defineProperty(error, "retryAfter", { value: retryAfter, enumerable: false, configurable: true });
319
+ } catch {
304
320
  }
321
+ return error;
322
+ }
323
+ function retryAfterOf(error) {
324
+ const value = error && typeof error === "object" ? error.retryAfter : void 0;
325
+ return typeof value === "string" ? value : void 0;
305
326
  }
306
327
  async function getOrCreateModernConnection(cacheKey, options, authHeaders) {
307
328
  for (let attempt = 0; ; attempt++) {
@@ -321,12 +342,12 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
321
342
  const promise = createNegotiatedClient(cacheKey, options, authHeaders).then(async (client) => {
322
343
  if ((client.getProtocolEra() === "modern" || options.handleLegacy === true) && generation === connectionGeneration) {
323
344
  modernConnections.set(cacheKey, client);
324
- registerMCPConnectionScopeCleanup("modern", cacheKey, async () => {
345
+ registerMCPConnectionScopeCleanup("modern", cacheKey, async (terminateSession) => {
325
346
  if (modernConnections.get(cacheKey) !== client) return;
326
347
  modernConnections.delete(cacheKey);
327
348
  legacyConnectionExpiresAt.delete(cacheKey);
328
349
  modernDiscoveries.delete(cacheKey);
329
- await closeModernClient(client);
350
+ await closeModernClient(client, terminateSession);
330
351
  });
331
352
  if (client.getProtocolEra() === "legacy") {
332
353
  legacyConnectionExpiresAt.set(cacheKey, Date.now() + LEGACY_CLASSIFICATION_TTL_MS);
@@ -348,7 +369,10 @@ function createSharedModernConnection(cacheKey, options, authHeaders) {
348
369
  return promise;
349
370
  }
350
371
  async function retireFailedConnection(cacheKey, client, error) {
351
- if (isAbortOrTimeoutError(error)) return;
372
+ if (isAbortOrTimeoutError(error)) {
373
+ markMCPConnectionScopeInterrupted();
374
+ return;
375
+ }
352
376
  if (modernConnections.get(cacheKey) === client) {
353
377
  modernConnections.delete(cacheKey);
354
378
  legacyConnectionExpiresAt.delete(cacheKey);
@@ -517,6 +541,7 @@ async function probeModernMCPConnection(agentUrl, authToken, customHeaders, opti
517
541
  options.allowPrivateIp
518
542
  );
519
543
  const scoped = shouldReuseMCPConnection(options.fetchFn !== void 0);
544
+ if (isKnownLegacy(cacheKey)) return { connected: false };
520
545
  let client;
521
546
  return runWithMCPCallContext(
522
547
  callContextFor({ customHeaders, requestTimeoutMs: options.requestTimeoutMs }),
@@ -656,6 +681,7 @@ async function closeModernMCPConnections() {
656
681
  export {
657
682
  closeModernMCPConnections,
658
683
  probeModernMCPConnection,
684
+ retryAfterOf,
659
685
  tryCallModernMCPTool,
660
686
  tryListModernMCPTools
661
687
  };
@@ -1,6 +1,8 @@
1
- type ScopeCleanup = () => Promise<void>;
1
+ type ScopeCleanup = (terminateSession: boolean) => Promise<void>;
2
2
  /** Cache-key suffix for the current caller-owned MCP workflow. */
3
3
  export declare function currentMCPConnectionScopeKey(): string | undefined;
4
+ /** Preserve seller work even when a higher layer handles a request timeout. */
5
+ export declare function markMCPConnectionScopeInterrupted(): void;
4
6
  /** Whether an LRU entry belongs to a workflow that has not finished yet. */
5
7
  export declare function isMCPConnectionScopeCacheKeyActive(cacheKey: string): boolean;
6
8
  /** Register one idempotent cache-entry cleanup with the current workflow. */
@@ -1,6 +1,8 @@
1
- type ScopeCleanup = () => Promise<void>;
1
+ type ScopeCleanup = (terminateSession: boolean) => Promise<void>;
2
2
  /** Cache-key suffix for the current caller-owned MCP workflow. */
3
3
  export declare function currentMCPConnectionScopeKey(): string | undefined;
4
+ /** Preserve seller work even when a higher layer handles a request timeout. */
5
+ export declare function markMCPConnectionScopeInterrupted(): void;
4
6
  /** Whether an LRU entry belongs to a workflow that has not finished yet. */
5
7
  export declare function isMCPConnectionScopeCacheKeyActive(cacheKey: string): boolean;
6
8
  /** Register one idempotent cache-entry cleanup with the current workflow. */
@@ -21,18 +21,24 @@ __export(mcp_scope_exports, {
21
21
  closeCurrentMCPConnectionScope: () => closeCurrentMCPConnectionScope,
22
22
  currentMCPConnectionScopeKey: () => currentMCPConnectionScopeKey,
23
23
  isMCPConnectionScopeCacheKeyActive: () => isMCPConnectionScopeCacheKeyActive,
24
+ markMCPConnectionScopeInterrupted: () => markMCPConnectionScopeInterrupted,
24
25
  registerMCPConnectionScopeCleanup: () => registerMCPConnectionScopeCleanup,
25
26
  registerMCPConnectionScopePending: () => registerMCPConnectionScopePending,
26
27
  withMCPConnectionScope: () => withMCPConnectionScope
27
28
  });
28
29
  module.exports = __toCommonJS(mcp_scope_exports);
29
30
  var import_node_async_hooks = require("node:async_hooks");
31
+ var import_abort = require('./abort.js');
30
32
  const scopeStorage = new import_node_async_hooks.AsyncLocalStorage();
31
33
  const activeScopeKeys = /* @__PURE__ */ new Set();
32
34
  let nextScopeId = 0;
33
35
  function currentMCPConnectionScopeKey() {
34
36
  return scopeStorage.getStore()?.cacheKey;
35
37
  }
38
+ function markMCPConnectionScopeInterrupted() {
39
+ const scope = scopeStorage.getStore();
40
+ if (scope?.preserveOnInterruption) scope.interrupted = true;
41
+ }
36
42
  function isMCPConnectionScopeCacheKeyActive(cacheKey) {
37
43
  const marker = cacheKey.lastIndexOf("::scope:");
38
44
  return marker >= 0 && activeScopeKeys.has(cacheKey.slice(marker + 2));
@@ -55,17 +61,27 @@ async function closeCurrentMCPConnectionScope() {
55
61
  }
56
62
  const cleanups = [...scope.cleanups.values()];
57
63
  scope.cleanups.clear();
58
- await Promise.allSettled(cleanups.map((cleanup) => cleanup()));
64
+ await Promise.allSettled(cleanups.map((cleanup) => cleanup(!scope.signal?.aborted && !scope.interrupted)));
59
65
  return true;
60
66
  }
61
67
  async function withMCPConnectionScope(fn, options = {}) {
62
68
  if (scopeStorage.getStore() && options.isolate !== true) return fn();
63
69
  const id = ++nextScopeId;
64
- const scope = { id, cacheKey: `scope:${id}`, pending: /* @__PURE__ */ new Set(), cleanups: /* @__PURE__ */ new Map() };
70
+ const scope = {
71
+ id,
72
+ cacheKey: `scope:${id}`,
73
+ pending: /* @__PURE__ */ new Set(),
74
+ cleanups: /* @__PURE__ */ new Map(),
75
+ signal: options.signal,
76
+ preserveOnInterruption: options.preserveOnInterruption
77
+ };
65
78
  activeScopeKeys.add(scope.cacheKey);
66
79
  return scopeStorage.run(scope, async () => {
67
80
  try {
68
81
  return await fn();
82
+ } catch (error) {
83
+ if ((0, import_abort.isAbortOrTimeoutError)(error)) markMCPConnectionScopeInterrupted();
84
+ throw error;
69
85
  } finally {
70
86
  try {
71
87
  await closeCurrentMCPConnectionScope();
@@ -80,6 +96,7 @@ async function withMCPConnectionScope(fn, options = {}) {
80
96
  closeCurrentMCPConnectionScope,
81
97
  currentMCPConnectionScopeKey,
82
98
  isMCPConnectionScopeCacheKeyActive,
99
+ markMCPConnectionScopeInterrupted,
83
100
  registerMCPConnectionScopeCleanup,
84
101
  registerMCPConnectionScopePending,
85
102
  withMCPConnectionScope
@@ -4,12 +4,17 @@ import { createRequire as __adcpCreateRequire } from "node:module";
4
4
  const __dirname = __adcpDirname(__adcpFileURLToPath(import.meta.url));
5
5
  const require2 = __adcpCreateRequire(import.meta.url);
6
6
  import { AsyncLocalStorage } from "node:async_hooks";
7
+ import { isAbortOrTimeoutError } from "./abort.mjs";
7
8
  const scopeStorage = new AsyncLocalStorage();
8
9
  const activeScopeKeys = /* @__PURE__ */ new Set();
9
10
  let nextScopeId = 0;
10
11
  function currentMCPConnectionScopeKey() {
11
12
  return scopeStorage.getStore()?.cacheKey;
12
13
  }
14
+ function markMCPConnectionScopeInterrupted() {
15
+ const scope = scopeStorage.getStore();
16
+ if (scope?.preserveOnInterruption) scope.interrupted = true;
17
+ }
13
18
  function isMCPConnectionScopeCacheKeyActive(cacheKey) {
14
19
  const marker = cacheKey.lastIndexOf("::scope:");
15
20
  return marker >= 0 && activeScopeKeys.has(cacheKey.slice(marker + 2));
@@ -32,17 +37,27 @@ async function closeCurrentMCPConnectionScope() {
32
37
  }
33
38
  const cleanups = [...scope.cleanups.values()];
34
39
  scope.cleanups.clear();
35
- await Promise.allSettled(cleanups.map((cleanup) => cleanup()));
40
+ await Promise.allSettled(cleanups.map((cleanup) => cleanup(!scope.signal?.aborted && !scope.interrupted)));
36
41
  return true;
37
42
  }
38
43
  async function withMCPConnectionScope(fn, options = {}) {
39
44
  if (scopeStorage.getStore() && options.isolate !== true) return fn();
40
45
  const id = ++nextScopeId;
41
- const scope = { id, cacheKey: `scope:${id}`, pending: /* @__PURE__ */ new Set(), cleanups: /* @__PURE__ */ new Map() };
46
+ const scope = {
47
+ id,
48
+ cacheKey: `scope:${id}`,
49
+ pending: /* @__PURE__ */ new Set(),
50
+ cleanups: /* @__PURE__ */ new Map(),
51
+ signal: options.signal,
52
+ preserveOnInterruption: options.preserveOnInterruption
53
+ };
42
54
  activeScopeKeys.add(scope.cacheKey);
43
55
  return scopeStorage.run(scope, async () => {
44
56
  try {
45
57
  return await fn();
58
+ } catch (error) {
59
+ if (isAbortOrTimeoutError(error)) markMCPConnectionScopeInterrupted();
60
+ throw error;
46
61
  } finally {
47
62
  try {
48
63
  await closeCurrentMCPConnectionScope();
@@ -56,6 +71,7 @@ export {
56
71
  closeCurrentMCPConnectionScope,
57
72
  currentMCPConnectionScopeKey,
58
73
  isMCPConnectionScopeCacheKeyActive,
74
+ markMCPConnectionScopeInterrupted,
59
75
  registerMCPConnectionScopeCleanup,
60
76
  registerMCPConnectionScopePending,
61
77
  withMCPConnectionScope
@@ -207,10 +207,10 @@ async function getOrCreateConnection(cacheKey, baseUrl, authHeaders, debugLogs,
207
207
  throw new Error(`MCP ${label} completed after connection teardown`);
208
208
  }
209
209
  connectionCache.set(cacheKey, client);
210
- (0, import_mcp_scope.registerMCPConnectionScopeCleanup)("legacy", cacheKey, async () => {
210
+ (0, import_mcp_scope.registerMCPConnectionScopeCleanup)("legacy", cacheKey, async (terminateSession) => {
211
211
  if (connectionCache.get(cacheKey) !== client) return;
212
212
  connectionCache.delete(cacheKey);
213
- await closeMCPClient(client);
213
+ await closeMCPClient(client, terminateSession);
214
214
  });
215
215
  evictLeastRecentlyUsed();
216
216
  return client;
@@ -280,10 +280,10 @@ async function getOrCreateOAuthConnection(cacheKey, options) {
280
280
  throw new Error("OAuth MCP connection completed after connection teardown");
281
281
  }
282
282
  oauthConnectionCache.set(cacheKey, client);
283
- (0, import_mcp_scope.registerMCPConnectionScopeCleanup)("oauth", cacheKey, async () => {
283
+ (0, import_mcp_scope.registerMCPConnectionScopeCleanup)("oauth", cacheKey, async (terminateSession) => {
284
284
  if (oauthConnectionCache.get(cacheKey) !== client) return;
285
285
  oauthConnectionCache.delete(cacheKey);
286
- await closeMCPClient(client);
286
+ await closeMCPClient(client, terminateSession);
287
287
  });
288
288
  evictLeastRecentlyUsedOAuth();
289
289
  return client;
@@ -337,7 +337,10 @@ async function withCachedOAuthConnectionImpl(options, label, fn) {
337
337
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
338
338
  error
339
339
  });
340
- if ((0, import_abort.isAbortOrTimeoutError)(error)) throw error;
340
+ if ((0, import_abort.isAbortOrTimeoutError)(error)) {
341
+ (0, import_mcp_scope.markMCPConnectionScopeInterrupted)();
342
+ throw error;
343
+ }
341
344
  if ((0, import_errors.is401Error)(error)) {
342
345
  options.debugLogs.push({
343
346
  type: "warning",
@@ -405,7 +408,10 @@ async function withCachedConnectionImpl(agentUrl, authToken, authHeaders, debugL
405
408
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
406
409
  error
407
410
  });
408
- if ((0, import_abort.isAbortOrTimeoutError)(error)) throw error;
411
+ if ((0, import_abort.isAbortOrTimeoutError)(error)) {
412
+ (0, import_mcp_scope.markMCPConnectionScopeInterrupted)();
413
+ throw error;
414
+ }
409
415
  if ((0, import_errors.is401Error)(error)) {
410
416
  debugLogs.push({
411
417
  type: "warning",
@@ -35,6 +35,7 @@ import {
35
35
  import { closeModernMCPConnections, tryCallModernMCPTool } from "./mcp-modern.mjs";
36
36
  import {
37
37
  currentMCPConnectionScopeKey,
38
+ markMCPConnectionScopeInterrupted,
38
39
  isMCPConnectionScopeCacheKeyActive,
39
40
  registerMCPConnectionScopeCleanup,
40
41
  registerMCPConnectionScopePending
@@ -208,10 +209,10 @@ async function getOrCreateConnection(cacheKey, baseUrl, authHeaders, debugLogs,
208
209
  throw new Error(`MCP ${label} completed after connection teardown`);
209
210
  }
210
211
  connectionCache.set(cacheKey, client);
211
- registerMCPConnectionScopeCleanup("legacy", cacheKey, async () => {
212
+ registerMCPConnectionScopeCleanup("legacy", cacheKey, async (terminateSession) => {
212
213
  if (connectionCache.get(cacheKey) !== client) return;
213
214
  connectionCache.delete(cacheKey);
214
- await closeMCPClient(client);
215
+ await closeMCPClient(client, terminateSession);
215
216
  });
216
217
  evictLeastRecentlyUsed();
217
218
  return client;
@@ -281,10 +282,10 @@ async function getOrCreateOAuthConnection(cacheKey, options) {
281
282
  throw new Error("OAuth MCP connection completed after connection teardown");
282
283
  }
283
284
  oauthConnectionCache.set(cacheKey, client);
284
- registerMCPConnectionScopeCleanup("oauth", cacheKey, async () => {
285
+ registerMCPConnectionScopeCleanup("oauth", cacheKey, async (terminateSession) => {
285
286
  if (oauthConnectionCache.get(cacheKey) !== client) return;
286
287
  oauthConnectionCache.delete(cacheKey);
287
- await closeMCPClient(client);
288
+ await closeMCPClient(client, terminateSession);
288
289
  });
289
290
  evictLeastRecentlyUsedOAuth();
290
291
  return client;
@@ -338,7 +339,10 @@ async function withCachedOAuthConnectionImpl(options, label, fn) {
338
339
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
339
340
  error
340
341
  });
341
- if (isAbortOrTimeoutError(error)) throw error;
342
+ if (isAbortOrTimeoutError(error)) {
343
+ markMCPConnectionScopeInterrupted();
344
+ throw error;
345
+ }
342
346
  if (is401Error(error)) {
343
347
  options.debugLogs.push({
344
348
  type: "warning",
@@ -406,7 +410,10 @@ async function withCachedConnectionImpl(agentUrl, authToken, authHeaders, debugL
406
410
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
407
411
  error
408
412
  });
409
- if (isAbortOrTimeoutError(error)) throw error;
413
+ if (isAbortOrTimeoutError(error)) {
414
+ markMCPConnectionScopeInterrupted();
415
+ throw error;
416
+ }
410
417
  if (is401Error(error)) {
411
418
  debugLogs.push({
412
419
  type: "warning",
@@ -89,6 +89,7 @@ schemaAdcpVersion?: string): Promise<{
89
89
  profile: AgentProfile;
90
90
  step: TestStepResult;
91
91
  caughtError?: unknown;
92
+ evidence?: TestStepResult;
92
93
  }>;
93
94
  /**
94
95
  * Discover what channels, pricing models, formats the agent supports
@@ -89,6 +89,7 @@ schemaAdcpVersion?: string): Promise<{
89
89
  profile: AgentProfile;
90
90
  step: TestStepResult;
91
91
  caughtError?: unknown;
92
+ evidence?: TestStepResult;
92
93
  }>;
93
94
  /**
94
95
  * Discover what channels, pricing models, formats the agent supports