@mcp-z/client 2.2.4 → 2.3.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.
Files changed (107) hide show
  1. package/README.md +12 -1
  2. package/dist/cjs/auth/capability-discovery.d.cts +3 -1
  3. package/dist/cjs/auth/capability-discovery.d.ts +3 -1
  4. package/dist/cjs/auth/capability-discovery.js +46 -32
  5. package/dist/cjs/auth/capability-discovery.js.map +1 -1
  6. package/dist/cjs/auth/discovery-fetch.d.cts +2 -0
  7. package/dist/cjs/auth/discovery-fetch.d.ts +2 -0
  8. package/dist/cjs/auth/discovery-fetch.js +85 -31
  9. package/dist/cjs/auth/discovery-fetch.js.map +1 -1
  10. package/dist/cjs/auth/interactive-oauth-flow.d.cts +1 -1
  11. package/dist/cjs/auth/interactive-oauth-flow.d.ts +1 -1
  12. package/dist/cjs/auth/interactive-oauth-flow.js +13 -6
  13. package/dist/cjs/auth/interactive-oauth-flow.js.map +1 -1
  14. package/dist/cjs/auth/oauth-callback-listener.d.cts +1 -1
  15. package/dist/cjs/auth/oauth-callback-listener.d.ts +1 -1
  16. package/dist/cjs/auth/oauth-callback-listener.js +38 -2
  17. package/dist/cjs/auth/oauth-callback-listener.js.map +1 -1
  18. package/dist/cjs/auth/rfc9728-discovery.d.cts +7 -2
  19. package/dist/cjs/auth/rfc9728-discovery.d.ts +7 -2
  20. package/dist/cjs/auth/rfc9728-discovery.js +120 -88
  21. package/dist/cjs/auth/rfc9728-discovery.js.map +1 -1
  22. package/dist/cjs/auth/types.d.cts +4 -0
  23. package/dist/cjs/auth/types.d.ts +4 -0
  24. package/dist/cjs/auth/types.js.map +1 -1
  25. package/dist/cjs/connection/connect-client.d.cts +9 -1
  26. package/dist/cjs/connection/connect-client.d.ts +9 -1
  27. package/dist/cjs/connection/connect-client.js +282 -75
  28. package/dist/cjs/connection/connect-client.js.map +1 -1
  29. package/dist/cjs/connection/existing-process-transport.d.cts +18 -18
  30. package/dist/cjs/connection/existing-process-transport.d.ts +18 -18
  31. package/dist/cjs/connection/existing-process-transport.js +187 -82
  32. package/dist/cjs/connection/existing-process-transport.js.map +1 -1
  33. package/dist/cjs/connection/wait-for-http-ready.d.cts +1 -1
  34. package/dist/cjs/connection/wait-for-http-ready.d.ts +1 -1
  35. package/dist/cjs/connection/wait-for-http-ready.js +30 -5
  36. package/dist/cjs/connection/wait-for-http-ready.js.map +1 -1
  37. package/dist/cjs/dcr/dcr-authenticator.d.cts +1 -1
  38. package/dist/cjs/dcr/dcr-authenticator.d.ts +1 -1
  39. package/dist/cjs/dcr/dcr-authenticator.js +29 -18
  40. package/dist/cjs/dcr/dcr-authenticator.js.map +1 -1
  41. package/dist/cjs/dcr/dynamic-client-registrar.js +2 -1
  42. package/dist/cjs/dcr/dynamic-client-registrar.js.map +1 -1
  43. package/dist/cjs/index.d.cts +1 -1
  44. package/dist/cjs/index.d.ts +1 -1
  45. package/dist/cjs/index.js.map +1 -1
  46. package/dist/cjs/spawn/owned-process-tree.d.cts +12 -0
  47. package/dist/cjs/spawn/owned-process-tree.d.ts +12 -0
  48. package/dist/cjs/spawn/owned-process-tree.js +93 -0
  49. package/dist/cjs/spawn/owned-process-tree.js.map +1 -0
  50. package/dist/cjs/spawn/spawn-server.d.cts +8 -32
  51. package/dist/cjs/spawn/spawn-server.d.ts +8 -32
  52. package/dist/cjs/spawn/spawn-server.js +398 -212
  53. package/dist/cjs/spawn/spawn-server.js.map +1 -1
  54. package/dist/cjs/spawn/spawn-servers.d.cts +18 -8
  55. package/dist/cjs/spawn/spawn-servers.d.ts +18 -8
  56. package/dist/cjs/spawn/spawn-servers.js +342 -113
  57. package/dist/cjs/spawn/spawn-servers.js.map +1 -1
  58. package/dist/cjs/types.d.cts +1 -1
  59. package/dist/cjs/types.d.ts +1 -1
  60. package/dist/cjs/types.js.map +1 -1
  61. package/dist/esm/auth/capability-discovery.d.ts +3 -1
  62. package/dist/esm/auth/capability-discovery.js +21 -11
  63. package/dist/esm/auth/capability-discovery.js.map +1 -1
  64. package/dist/esm/auth/discovery-fetch.d.ts +2 -0
  65. package/dist/esm/auth/discovery-fetch.js +64 -23
  66. package/dist/esm/auth/discovery-fetch.js.map +1 -1
  67. package/dist/esm/auth/interactive-oauth-flow.d.ts +1 -1
  68. package/dist/esm/auth/interactive-oauth-flow.js +13 -6
  69. package/dist/esm/auth/interactive-oauth-flow.js.map +1 -1
  70. package/dist/esm/auth/oauth-callback-listener.d.ts +1 -1
  71. package/dist/esm/auth/oauth-callback-listener.js +32 -2
  72. package/dist/esm/auth/oauth-callback-listener.js.map +1 -1
  73. package/dist/esm/auth/rfc9728-discovery.d.ts +7 -2
  74. package/dist/esm/auth/rfc9728-discovery.js +40 -16
  75. package/dist/esm/auth/rfc9728-discovery.js.map +1 -1
  76. package/dist/esm/auth/types.d.ts +4 -0
  77. package/dist/esm/auth/types.js.map +1 -1
  78. package/dist/esm/connection/connect-client.d.ts +9 -1
  79. package/dist/esm/connection/connect-client.js +97 -35
  80. package/dist/esm/connection/connect-client.js.map +1 -1
  81. package/dist/esm/connection/existing-process-transport.d.ts +18 -18
  82. package/dist/esm/connection/existing-process-transport.js +132 -70
  83. package/dist/esm/connection/existing-process-transport.js.map +1 -1
  84. package/dist/esm/connection/wait-for-http-ready.d.ts +1 -1
  85. package/dist/esm/connection/wait-for-http-ready.js +19 -4
  86. package/dist/esm/connection/wait-for-http-ready.js.map +1 -1
  87. package/dist/esm/dcr/dcr-authenticator.d.ts +1 -1
  88. package/dist/esm/dcr/dcr-authenticator.js +26 -15
  89. package/dist/esm/dcr/dcr-authenticator.js.map +1 -1
  90. package/dist/esm/dcr/dynamic-client-registrar.js +2 -1
  91. package/dist/esm/dcr/dynamic-client-registrar.js.map +1 -1
  92. package/dist/esm/index.d.ts +1 -1
  93. package/dist/esm/index.js.map +1 -1
  94. package/dist/esm/spawn/owned-process-tree.d.ts +12 -0
  95. package/dist/esm/spawn/owned-process-tree.js +39 -0
  96. package/dist/esm/spawn/owned-process-tree.js.map +1 -0
  97. package/dist/esm/spawn/spawn-server.d.ts +8 -32
  98. package/dist/esm/spawn/spawn-server.js +224 -130
  99. package/dist/esm/spawn/spawn-server.js.map +1 -1
  100. package/dist/esm/spawn/spawn-servers.d.ts +18 -8
  101. package/dist/esm/spawn/spawn-servers.js +180 -55
  102. package/dist/esm/spawn/spawn-servers.js.map +1 -1
  103. package/dist/esm/types.d.ts +1 -1
  104. package/dist/esm/types.js.map +1 -1
  105. package/package.json +8 -5
  106. package/schemas/servers.d.ts +24 -0
  107. package/schemas/servers.schema.json +31 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/auth/types.ts"],"sourcesContent":["/**\n * Shared types for OAuth and DCR authentication\n */\n\n/**\n * OAuth callback result from authorization server\n */\nexport interface CallbackResult {\n /** Authorization code from OAuth server */\n code: string;\n /** State parameter for CSRF protection */\n state?: string;\n /** Issuer identifier of the authorization server that minted the response (RFC 9207) */\n iss?: string;\n}\n\n/**\n * PKCE (Proof Key for Code Exchange) parameters (RFC 7636)\n * Used to secure OAuth 2.0 authorization code flow for public clients\n */\nexport interface PkceParams {\n /** Code verifier - cryptographically random string (43-128 characters) */\n codeVerifier: string;\n /** Code challenge - derived from code verifier using challenge method */\n codeChallenge: string;\n /** Code challenge method - S256 (SHA-256) or plain */\n codeChallengeMethod: 'S256' | 'plain';\n}\n\n/**\n * OAuth token set with access and refresh tokens\n */\nexport interface TokenSet {\n /** Access token for API requests */\n accessToken: string;\n /** Refresh token for obtaining new access tokens */\n refreshToken: string;\n /** Timestamp when access token expires (milliseconds since epoch) */\n expiresAt: number;\n /** Scopes granted for this token set */\n scopes?: string[];\n /** Client ID used for DCR registration (stored for future use) */\n clientId?: string;\n /** Client secret used for DCR registration (stored for future use) */\n clientSecret?: string;\n /** Issuer identifier of the authorization server these credentials belong to (SEP-2352) */\n issuer?: string;\n}\n\n/**\n * OAuth 2.0 Protected Resource Metadata (RFC 9728)\n * Response from .well-known/oauth-protected-resource endpoint\n */\nexport interface ProtectedResourceMetadata {\n /** The protected resource identifier */\n resource: string;\n /** List of authorization server URLs that can issue tokens for this resource */\n authorization_servers: string[];\n /** Optional list of scopes supported by this resource */\n scopes_supported?: string[];\n /** Optional list of bearer token methods supported (header, query, body) */\n bearer_methods_supported?: string[];\n}\n\n/**\n * OAuth 2.0 Authorization Server Metadata (RFC 8414)\n * Response from .well-known/oauth-authorization-server endpoint\n */\nexport interface AuthorizationServerMetadata {\n /** The authorization server's issuer identifier */\n issuer?: string;\n /** URL of the authorization endpoint */\n authorization_endpoint?: string;\n /** URL of the token endpoint */\n token_endpoint?: string;\n /** URL of the client registration endpoint (DCR - RFC 7591) */\n registration_endpoint?: string;\n /** URL of the token introspection endpoint */\n introspection_endpoint?: string;\n /** List of OAuth scopes supported by the authorization server */\n scopes_supported?: string[];\n /** Response types supported (code, token, etc.) */\n response_types_supported?: string[];\n /** Grant types supported (authorization_code, refresh_token, etc.) */\n grant_types_supported?: string[];\n /** Token endpoint authentication methods supported */\n token_endpoint_auth_methods_supported?: string[];\n /** Whether the authorization response carries an `iss` parameter (RFC 9207) */\n authorization_response_iss_parameter_supported?: boolean;\n}\n\n/**\n * OAuth server capabilities discovered from .well-known endpoint\n */\nexport interface AuthCapabilities {\n /** Whether the server supports Dynamic Client Registration (RFC 7591) */\n supportsDcr: boolean;\n /** Issuer identifier from the authorization server metadata (RFC 8414) */\n issuer?: string;\n /**\n * The protected resource's canonical identifier, from the RFC 9728 metadata\n * document's `resource` field. This is what an RFC 8707 `resource` indicator\n * must carry, and it is the resource server's own statement of its identity -\n * not the URL we happened to dial, and never the base URL discovery was\n * performed against, which has any `/mcp` segment stripped off it.\n *\n * Absent when no protected-resource metadata was published and the\n * authorization server was reached by direct RFC 8414 discovery instead.\n */\n resource?: string;\n /** Whether the authorization response carries an `iss` parameter (RFC 9207) */\n authorizationResponseIssSupported?: boolean;\n /** DCR client registration endpoint */\n registrationEndpoint?: string;\n /** OAuth authorization endpoint */\n authorizationEndpoint?: string;\n /** OAuth token endpoint */\n tokenEndpoint?: string;\n /** Token introspection endpoint */\n introspectionEndpoint?: string;\n /** Supported OAuth scopes */\n scopes?: string[];\n}\n\n/**\n * Client credentials from DCR registration\n */\nexport interface ClientCredentials {\n /** OAuth client ID */\n clientId: string;\n /** OAuth client secret */\n clientSecret: string;\n /** Timestamp when client was registered */\n issuedAt?: number;\n}\n\n/**\n * Options for DCR client registration\n */\nexport interface DcrRegistrationOptions {\n /** Redirect URI for OAuth callback, from the loopback listener the caller has already bound (RFC 8252) */\n redirectUri: string;\n /** Client name to register */\n clientName?: string;\n /**\n * Loopback trust grant for the registration_endpoint fetch (SSRF\n * mitigation - see `src/auth/discovery-fetch.ts`). Compute this from the\n * MCP server the caller is actually talking to, never from\n * `registrationEndpoint` itself (which is typically sourced from\n * remote-controlled AS metadata). Defaults to `false`.\n */\n allowLoopback?: boolean;\n}\n\n/**\n * Options for OAuth authorization flow\n */\nexport interface OAuthFlowOptions {\n /** Port for OAuth callback listener (required - use get-port to find available port) */\n port: number;\n /** Issuer identifier discovered before the flow starts; the `iss` in the authorization response must match it (RFC 9207) */\n issuer: string;\n /** Canonical resource server URI, sent as `resource` on the authorization, token, and refresh requests (RFC 8707) */\n resource: string;\n /** Redirect URI for OAuth callback (optional - will be built from port if not provided) */\n redirectUri?: string;\n /** OAuth scopes to request */\n scopes?: string[];\n /** Whether the authorization server advertises `authorization_response_iss_parameter_supported` (RFC 9207) */\n authorizationResponseIssSupported?: boolean;\n /** Enable PKCE (RFC 7636) - recommended for all clients, required for public clients */\n pkce?: boolean;\n /** Headless mode (don't open browser) */\n headless?: boolean;\n /** Timeout for callback (milliseconds) */\n timeout?: number;\n /** Optional logger for debug output (defaults to singleton logger) */\n logger?: import('../utils/logger.ts').Logger;\n /**\n * Loopback trust grant for the token endpoint fetch (SSRF mitigation - see\n * `src/auth/discovery-fetch.ts`). Compute this from the MCP server the\n * caller is actually talking to, never from `tokenEndpoint` itself (which\n * is typically sourced from remote-controlled AS metadata). Defaults to\n * `false`.\n */\n allowLoopback?: boolean;\n}\n"],"names":[],"mappings":"AAAA;;CAEC,GAED;;CAEC"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/client/src/auth/types.ts"],"sourcesContent":["/**\n * Shared types for OAuth and DCR authentication\n */\n\n/**\n * OAuth callback result from authorization server\n */\nexport interface CallbackResult {\n /** Authorization code from OAuth server */\n code: string;\n /** State parameter for CSRF protection */\n state?: string;\n /** Issuer identifier of the authorization server that minted the response (RFC 9207) */\n iss?: string;\n}\n\n/**\n * PKCE (Proof Key for Code Exchange) parameters (RFC 7636)\n * Used to secure OAuth 2.0 authorization code flow for public clients\n */\nexport interface PkceParams {\n /** Code verifier - cryptographically random string (43-128 characters) */\n codeVerifier: string;\n /** Code challenge - derived from code verifier using challenge method */\n codeChallenge: string;\n /** Code challenge method - S256 (SHA-256) or plain */\n codeChallengeMethod: 'S256' | 'plain';\n}\n\n/**\n * OAuth token set with access and refresh tokens\n */\nexport interface TokenSet {\n /** Access token for API requests */\n accessToken: string;\n /** Refresh token for obtaining new access tokens */\n refreshToken: string;\n /** Timestamp when access token expires (milliseconds since epoch) */\n expiresAt: number;\n /** Scopes granted for this token set */\n scopes?: string[];\n /** Client ID used for DCR registration (stored for future use) */\n clientId?: string;\n /** Client secret used for DCR registration (stored for future use) */\n clientSecret?: string;\n /** Issuer identifier of the authorization server these credentials belong to (SEP-2352) */\n issuer?: string;\n}\n\n/**\n * OAuth 2.0 Protected Resource Metadata (RFC 9728)\n * Response from .well-known/oauth-protected-resource endpoint\n */\nexport interface ProtectedResourceMetadata {\n /** The protected resource identifier */\n resource: string;\n /** List of authorization server URLs that can issue tokens for this resource */\n authorization_servers: string[];\n /** Optional list of scopes supported by this resource */\n scopes_supported?: string[];\n /** Optional list of bearer token methods supported (header, query, body) */\n bearer_methods_supported?: string[];\n}\n\n/**\n * OAuth 2.0 Authorization Server Metadata (RFC 8414)\n * Response from .well-known/oauth-authorization-server endpoint\n */\nexport interface AuthorizationServerMetadata {\n /** The authorization server's issuer identifier */\n issuer?: string;\n /** URL of the authorization endpoint */\n authorization_endpoint?: string;\n /** URL of the token endpoint */\n token_endpoint?: string;\n /** URL of the client registration endpoint (DCR - RFC 7591) */\n registration_endpoint?: string;\n /** URL of the token introspection endpoint */\n introspection_endpoint?: string;\n /** List of OAuth scopes supported by the authorization server */\n scopes_supported?: string[];\n /** Response types supported (code, token, etc.) */\n response_types_supported?: string[];\n /** Grant types supported (authorization_code, refresh_token, etc.) */\n grant_types_supported?: string[];\n /** Token endpoint authentication methods supported */\n token_endpoint_auth_methods_supported?: string[];\n /** Whether the authorization response carries an `iss` parameter (RFC 9207) */\n authorization_response_iss_parameter_supported?: boolean;\n}\n\n/**\n * OAuth server capabilities discovered from .well-known endpoint\n */\nexport interface AuthCapabilities {\n /** Whether the server supports Dynamic Client Registration (RFC 7591) */\n supportsDcr: boolean;\n /** Issuer identifier from the authorization server metadata (RFC 8414) */\n issuer?: string;\n /**\n * The protected resource's canonical identifier, from the RFC 9728 metadata\n * document's `resource` field. This is what an RFC 8707 `resource` indicator\n * must carry, and it is the resource server's own statement of its identity -\n * not the URL we happened to dial, and never the base URL discovery was\n * performed against, which has any `/mcp` segment stripped off it.\n *\n * Absent when no protected-resource metadata was published and the\n * authorization server was reached by direct RFC 8414 discovery instead.\n */\n resource?: string;\n /** Whether the authorization response carries an `iss` parameter (RFC 9207) */\n authorizationResponseIssSupported?: boolean;\n /** DCR client registration endpoint */\n registrationEndpoint?: string;\n /** OAuth authorization endpoint */\n authorizationEndpoint?: string;\n /** OAuth token endpoint */\n tokenEndpoint?: string;\n /** Token introspection endpoint */\n introspectionEndpoint?: string;\n /** Supported OAuth scopes */\n scopes?: string[];\n}\n\n/**\n * Client credentials from DCR registration\n */\nexport interface ClientCredentials {\n /** OAuth client ID */\n clientId: string;\n /** OAuth client secret */\n clientSecret: string;\n /** Timestamp when client was registered */\n issuedAt?: number;\n}\n\n/**\n * Options for DCR client registration\n */\nexport interface DcrRegistrationOptions {\n /** Redirect URI for OAuth callback, from the loopback listener the caller has already bound (RFC 8252) */\n redirectUri: string;\n /** Client name to register */\n clientName?: string;\n /**\n * Loopback trust grant for the registration_endpoint fetch (SSRF\n * mitigation - see `src/auth/discovery-fetch.ts`). Compute this from the\n * MCP server the caller is actually talking to, never from\n * `registrationEndpoint` itself (which is typically sourced from\n * remote-controlled AS metadata). Defaults to `false`.\n */\n allowLoopback?: boolean;\n /** Cancels an in-progress registration request. */\n signal?: AbortSignal;\n}\n\n/**\n * Options for OAuth authorization flow\n */\nexport interface OAuthFlowOptions {\n /** Cancels an in-progress authorization and closes its callback listener. */\n signal?: AbortSignal;\n /** Port for OAuth callback listener (required - use get-port to find available port) */\n port: number;\n /** Issuer identifier discovered before the flow starts; the `iss` in the authorization response must match it (RFC 9207) */\n issuer: string;\n /** Canonical resource server URI, sent as `resource` on the authorization, token, and refresh requests (RFC 8707) */\n resource: string;\n /** Redirect URI for OAuth callback (optional - will be built from port if not provided) */\n redirectUri?: string;\n /** OAuth scopes to request */\n scopes?: string[];\n /** Whether the authorization server advertises `authorization_response_iss_parameter_supported` (RFC 9207) */\n authorizationResponseIssSupported?: boolean;\n /** Enable PKCE (RFC 7636) - recommended for all clients, required for public clients */\n pkce?: boolean;\n /** Headless mode (don't open browser) */\n headless?: boolean;\n /** Timeout for callback (milliseconds) */\n timeout?: number;\n /** Optional logger for debug output (defaults to singleton logger) */\n logger?: import('../utils/logger.ts').Logger;\n /**\n * Loopback trust grant for the token endpoint fetch (SSRF mitigation - see\n * `src/auth/discovery-fetch.ts`). Compute this from the MCP server the\n * caller is actually talking to, never from `tokenEndpoint` itself (which\n * is typically sourced from remote-controlled AS metadata). Defaults to\n * `false`.\n */\n allowLoopback?: boolean;\n}\n"],"names":[],"mappings":"AAAA;;CAEC,GAED;;CAEC"}
@@ -4,7 +4,7 @@
4
4
  * Helper to connect MCP SDK clients to servers with intelligent transport inference.
5
5
  * Automatically detects transport type from URL protocol or type field.
6
6
  */
7
- import type { VersionNegotiationOptions } from '@modelcontextprotocol/client';
7
+ import type { Transport, VersionNegotiationOptions } from '@modelcontextprotocol/client';
8
8
  import { Client } from '@modelcontextprotocol/client';
9
9
  import { type DcrAuthenticatorOptions } from '../dcr/index.js';
10
10
  import type { ServerProcess } from '../spawn/spawn-server.js';
@@ -18,6 +18,12 @@ interface RegistryLike {
18
18
  servers: Map<string, ServerProcess>;
19
19
  }
20
20
  import { type Logger } from '../utils/logger.js';
21
+ /** @internal - Bounds work by aborting the actual request signal at the deadline. */
22
+ export declare function withAbortTimeout<T>(operationFn: (signal: AbortSignal) => Promise<T>, ms: number, operation: string, parentSignal?: AbortSignal): Promise<T>;
23
+ /** @internal - Connects a transport with a deadline that aborts and cleans up the actual connection. */
24
+ export declare function connectTransportWithTimeout(client: Client, transport: Transport, ms: number, operation: string, parentSignal?: AbortSignal): Promise<void>;
25
+ /** @internal - Connects one client/transport pair and reports any failed cleanup. */
26
+ export declare function connectTransport(client: Client, transport: Transport, signal?: AbortSignal): Promise<void>;
21
27
  /**
22
28
  * Connect MCP SDK client to server with full readiness handling.
23
29
  * @internal - Use registry.connect() instead
@@ -65,5 +71,7 @@ export declare function connectMcpClient(registryOrConfig: RegistryLike | Server
65
71
  dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;
66
72
  logger?: Logger;
67
73
  versionNegotiation?: VersionNegotiationOptions;
74
+ /** Cancels readiness, authentication, and transport connection work. */
75
+ signal?: AbortSignal;
68
76
  }): Promise<Client>;
69
77
  export {};
@@ -4,7 +4,7 @@
4
4
  * Helper to connect MCP SDK clients to servers with intelligent transport inference.
5
5
  * Automatically detects transport type from URL protocol or type field.
6
6
  */
7
- import type { VersionNegotiationOptions } from '@modelcontextprotocol/client';
7
+ import type { Transport, VersionNegotiationOptions } from '@modelcontextprotocol/client';
8
8
  import { Client } from '@modelcontextprotocol/client';
9
9
  import { type DcrAuthenticatorOptions } from '../dcr/index.js';
10
10
  import type { ServerProcess } from '../spawn/spawn-server.js';
@@ -18,6 +18,12 @@ interface RegistryLike {
18
18
  servers: Map<string, ServerProcess>;
19
19
  }
20
20
  import { type Logger } from '../utils/logger.js';
21
+ /** @internal - Bounds work by aborting the actual request signal at the deadline. */
22
+ export declare function withAbortTimeout<T>(operationFn: (signal: AbortSignal) => Promise<T>, ms: number, operation: string, parentSignal?: AbortSignal): Promise<T>;
23
+ /** @internal - Connects a transport with a deadline that aborts and cleans up the actual connection. */
24
+ export declare function connectTransportWithTimeout(client: Client, transport: Transport, ms: number, operation: string, parentSignal?: AbortSignal): Promise<void>;
25
+ /** @internal - Connects one client/transport pair and reports any failed cleanup. */
26
+ export declare function connectTransport(client: Client, transport: Transport, signal?: AbortSignal): Promise<void>;
21
27
  /**
22
28
  * Connect MCP SDK client to server with full readiness handling.
23
29
  * @internal - Use registry.connect() instead
@@ -65,5 +71,7 @@ export declare function connectMcpClient(registryOrConfig: RegistryLike | Server
65
71
  dcrAuthenticator?: Partial<DcrAuthenticatorOptions>;
66
72
  logger?: Logger;
67
73
  versionNegotiation?: VersionNegotiationOptions;
74
+ /** Cancels readiness, authentication, and transport connection work. */
75
+ signal?: AbortSignal;
68
76
  }): Promise<Client>;
69
77
  export {};
@@ -7,10 +7,24 @@
7
7
  Object.defineProperty(exports, "__esModule", {
8
8
  value: true
9
9
  });
10
- Object.defineProperty(exports, "connectMcpClient", {
11
- enumerable: true,
12
- get: function() {
10
+ function _export(target, all) {
11
+ for(var name in all)Object.defineProperty(target, name, {
12
+ enumerable: true,
13
+ get: Object.getOwnPropertyDescriptor(all, name).get
14
+ });
15
+ }
16
+ _export(exports, {
17
+ get connectMcpClient () {
13
18
  return connectMcpClient;
19
+ },
20
+ get connectTransport () {
21
+ return connectTransport;
22
+ },
23
+ get connectTransportWithTimeout () {
24
+ return connectTransportWithTimeout;
25
+ },
26
+ get withAbortTimeout () {
27
+ return withAbortTimeout;
14
28
  }
15
29
  });
16
30
  var _client = require("@modelcontextprotocol/client");
@@ -23,6 +37,14 @@ var _urlutilsts = require("../lib/url-utils.js");
23
37
  var _loggerts = require("../utils/logger.js");
24
38
  var _existingprocesstransportts = require("./existing-process-transport.js");
25
39
  var _waitforhttpreadyts = require("./wait-for-http-ready.js");
40
+ function _array_like_to_array(arr, len) {
41
+ if (len == null || len > arr.length) len = arr.length;
42
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
43
+ return arr2;
44
+ }
45
+ function _array_without_holes(arr) {
46
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
47
+ }
26
48
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
27
49
  try {
28
50
  var info = gen[key](arg);
@@ -71,6 +93,14 @@ function _interop_require_default(obj) {
71
93
  default: obj
72
94
  };
73
95
  }
96
+ function _iterable_to_array(iter) {
97
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
98
+ return Array.from(iter);
99
+ }
100
+ }
101
+ function _non_iterable_spread() {
102
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
103
+ }
74
104
  function _object_spread(target) {
75
105
  for(var i = 1; i < arguments.length; i++){
76
106
  var source = arguments[i] != null ? arguments[i] : {};
@@ -86,6 +116,9 @@ function _object_spread(target) {
86
116
  }
87
117
  return target;
88
118
  }
119
+ function _to_consumable_array(arr) {
120
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
121
+ }
89
122
  function _ts_generator(thisArg, body) {
90
123
  var f, y, t, _ = {
91
124
  label: 0,
@@ -185,33 +218,232 @@ function _ts_generator(thisArg, body) {
185
218
  };
186
219
  }
187
220
  }
188
- /**
189
- * Wrap promise with timeout - throws if promise takes too long
190
- * Clears timeout when promise completes to prevent hanging event loop
191
- * @param promise - Promise to wrap
192
- * @param ms - Timeout in milliseconds
193
- * @param operation - Description of operation for error message
194
- * @returns Promise result or timeout error
195
- */ function withTimeout(promise, ms, operation) {
221
+ function _unsupported_iterable_to_array(o, minLen) {
222
+ if (!o) return;
223
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
224
+ var n = Object.prototype.toString.call(o).slice(8, -1);
225
+ if (n === "Object" && o.constructor) n = o.constructor.name;
226
+ if (n === "Map" || n === "Set") return Array.from(n);
227
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
228
+ }
229
+ var HTTP_CONNECTION_TIMEOUT_MS = 30000;
230
+ var CLIENT_CLEANUP_TIMEOUT_MS = 5000;
231
+ function withAbortTimeout(operationFn, ms, operation, parentSignal) {
232
+ return _async_to_generator(function() {
233
+ var controller, timeoutError, abortFromParent, timeoutId;
234
+ return _ts_generator(this, function(_state) {
235
+ switch(_state.label){
236
+ case 0:
237
+ controller = new AbortController();
238
+ timeoutError = new Error("Timeout after ".concat(ms, "ms: ").concat(operation));
239
+ abortFromParent = function abortFromParent() {
240
+ return controller.abort(_instanceof(parentSignal === null || parentSignal === void 0 ? void 0 : parentSignal.reason, Error) ? parentSignal.reason : new Error('Connection was cancelled'));
241
+ };
242
+ parentSignal === null || parentSignal === void 0 ? void 0 : parentSignal.addEventListener('abort', abortFromParent, {
243
+ once: true
244
+ });
245
+ if (parentSignal === null || parentSignal === void 0 ? void 0 : parentSignal.aborted) abortFromParent();
246
+ timeoutId = setTimeout(function() {
247
+ return controller.abort(timeoutError);
248
+ }, ms);
249
+ _state.label = 1;
250
+ case 1:
251
+ _state.trys.push([
252
+ 1,
253
+ ,
254
+ 3,
255
+ 4
256
+ ]);
257
+ return [
258
+ 4,
259
+ operationFn(controller.signal)
260
+ ];
261
+ case 2:
262
+ // Preserve the operation's error unchanged: connection cleanup may have
263
+ // attached failures to the original cancellation or timeout.
264
+ return [
265
+ 2,
266
+ _state.sent()
267
+ ];
268
+ case 3:
269
+ clearTimeout(timeoutId);
270
+ parentSignal === null || parentSignal === void 0 ? void 0 : parentSignal.removeEventListener('abort', abortFromParent);
271
+ return [
272
+ 7
273
+ ];
274
+ case 4:
275
+ return [
276
+ 2
277
+ ];
278
+ }
279
+ });
280
+ })();
281
+ }
282
+ function connectTransportWithTimeout(client, transport, ms, operation, parentSignal) {
196
283
  return _async_to_generator(function() {
197
- var timeoutId;
198
284
  return _ts_generator(this, function(_state) {
199
285
  return [
200
286
  2,
201
- Promise.race([
202
- promise.finally(function() {
203
- return clearTimeout(timeoutId);
204
- }),
205
- new Promise(function(_, reject) {
206
- timeoutId = setTimeout(function() {
207
- return reject(new Error("Timeout after ".concat(ms, "ms: ").concat(operation)));
208
- }, ms);
209
- })
210
- ])
287
+ withAbortTimeout(function(signal) {
288
+ return connectTransport(client, transport, signal);
289
+ }, ms, operation, parentSignal)
211
290
  ];
212
291
  });
213
292
  })();
214
293
  }
294
+ function throwIfAborted(signal) {
295
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) throw _instanceof(signal.reason, Error) ? signal.reason : new Error('Connection was cancelled');
296
+ }
297
+ function closeClientWithinTimeout(client) {
298
+ return _async_to_generator(function() {
299
+ var timeoutId;
300
+ return _ts_generator(this, function(_state) {
301
+ switch(_state.label){
302
+ case 0:
303
+ _state.trys.push([
304
+ 0,
305
+ ,
306
+ 2,
307
+ 3
308
+ ]);
309
+ return [
310
+ 4,
311
+ Promise.race([
312
+ client.close(),
313
+ new Promise(function(_, reject) {
314
+ timeoutId = setTimeout(function() {
315
+ return reject(new Error("Client cleanup did not complete within ".concat(CLIENT_CLEANUP_TIMEOUT_MS, "ms")));
316
+ }, CLIENT_CLEANUP_TIMEOUT_MS);
317
+ })
318
+ ])
319
+ ];
320
+ case 1:
321
+ _state.sent();
322
+ return [
323
+ 3,
324
+ 3
325
+ ];
326
+ case 2:
327
+ if (timeoutId) clearTimeout(timeoutId);
328
+ return [
329
+ 7
330
+ ];
331
+ case 3:
332
+ return [
333
+ 2
334
+ ];
335
+ }
336
+ });
337
+ })();
338
+ }
339
+ function rethrowAfterClientCleanup(error, clients, message) {
340
+ return _async_to_generator(function() {
341
+ var cleanup, cleanupErrors;
342
+ return _ts_generator(this, function(_state) {
343
+ switch(_state.label){
344
+ case 0:
345
+ return [
346
+ 4,
347
+ Promise.allSettled(clients.map(function(client) {
348
+ return closeClientWithinTimeout(client);
349
+ }))
350
+ ];
351
+ case 1:
352
+ cleanup = _state.sent();
353
+ cleanupErrors = cleanup.flatMap(function(result) {
354
+ return result.status === 'rejected' ? [
355
+ result.reason
356
+ ] : [];
357
+ });
358
+ if (cleanupErrors.length > 0) throw new AggregateError([
359
+ error
360
+ ].concat(_to_consumable_array(cleanupErrors)), message, {
361
+ cause: error
362
+ });
363
+ throw error;
364
+ }
365
+ });
366
+ })();
367
+ }
368
+ function connectTransport(client, transport, signal) {
369
+ return _async_to_generator(function() {
370
+ var abortHandler, connecting, aborted, error;
371
+ return _ts_generator(this, function(_state) {
372
+ switch(_state.label){
373
+ case 0:
374
+ _state.trys.push([
375
+ 0,
376
+ 5,
377
+ 7,
378
+ 8
379
+ ]);
380
+ throwIfAborted(signal);
381
+ connecting = client.connect(transport);
382
+ if (!signal) return [
383
+ 3,
384
+ 2
385
+ ];
386
+ aborted = new Promise(function(_, reject) {
387
+ abortHandler = function abortHandler() {
388
+ return reject(_instanceof(signal.reason, Error) ? signal.reason : new Error('Connection was cancelled'));
389
+ };
390
+ signal.addEventListener('abort', abortHandler, {
391
+ once: true
392
+ });
393
+ });
394
+ return [
395
+ 4,
396
+ Promise.race([
397
+ connecting,
398
+ aborted
399
+ ])
400
+ ];
401
+ case 1:
402
+ _state.sent();
403
+ return [
404
+ 3,
405
+ 4
406
+ ];
407
+ case 2:
408
+ return [
409
+ 4,
410
+ connecting
411
+ ];
412
+ case 3:
413
+ _state.sent();
414
+ _state.label = 4;
415
+ case 4:
416
+ return [
417
+ 3,
418
+ 8
419
+ ];
420
+ case 5:
421
+ error = _state.sent();
422
+ return [
423
+ 4,
424
+ rethrowAfterClientCleanup(error, [
425
+ client
426
+ ], 'MCP connection failed and client cleanup also failed')
427
+ ];
428
+ case 6:
429
+ _state.sent();
430
+ return [
431
+ 3,
432
+ 8
433
+ ];
434
+ case 7:
435
+ if (signal && abortHandler) signal.removeEventListener('abort', abortHandler);
436
+ return [
437
+ 7
438
+ ];
439
+ case 8:
440
+ return [
441
+ 2
442
+ ];
443
+ }
444
+ });
445
+ })();
446
+ }
215
447
  /**
216
448
  * Infer transport type from server configuration with validation.
217
449
  *
@@ -253,7 +485,7 @@ function _ts_generator(thisArg, body) {
253
485
  }
254
486
  function connectMcpClient(registryOrConfig, serverName, options) {
255
487
  return _async_to_generator(function() {
256
- var _ref, isRegistry, serversConfig, registry, logger, serverConfig, available, transportType, clientOptions, client, serverHandle, transport, transport1, isSpawnedHttp, url, mcpServerUrl, capabilities, authToken, port, redirectUri, authenticator, tokens, staticHeaders, dcrHeaders, mergedHeaders, transportOptions, transport2, error, errorMessage, cause, isConnectionRefused, shouldFallback, sseClient, staticHeaders1, dcrHeaders1, mergedHeaders1, sseTransportOptions, sseTransport, sseError;
488
+ var _ref, isRegistry, serversConfig, registry, logger, serverConfig, available, transportType, clientOptions, client, serverHandle, transport, transport1, isSpawnedHttp, url, mcpServerUrl, capabilities, authToken, port, redirectUri, authenticator, tokens, staticHeaders, dcrHeaders, mergedHeaders, transportOptions, transport2, error, _options_signal, errorMessage, cause, isConnectionRefused, unavailable, shouldFallback, sseClient, staticHeaders1, dcrHeaders1, mergedHeaders1, sseTransportOptions, sseTransport;
257
489
  return _ts_generator(this, function(_state) {
258
490
  switch(_state.label){
259
491
  case 0:
@@ -262,6 +494,7 @@ function connectMcpClient(registryOrConfig, serverName, options) {
262
494
  serversConfig = isRegistry ? registryOrConfig.config : registryOrConfig;
263
495
  registry = isRegistry ? registryOrConfig : undefined;
264
496
  logger = (_ref = options === null || options === void 0 ? void 0 : options.logger) !== null && _ref !== void 0 ? _ref : _loggerts.logger;
497
+ throwIfAborted(options === null || options === void 0 ? void 0 : options.signal);
265
498
  serverConfig = serversConfig[serverName];
266
499
  if (!serverConfig) {
267
500
  available = Object.keys(serversConfig).join(', ');
@@ -297,7 +530,7 @@ function connectMcpClient(registryOrConfig, serverName, options) {
297
530
  transport = new _existingprocesstransportts.ExistingProcessTransport(serverHandle.process);
298
531
  return [
299
532
  4,
300
- client.connect(transport)
533
+ connectTransport(client, transport, options === null || options === void 0 ? void 0 : options.signal)
301
534
  ];
302
535
  case 1:
303
536
  _state.sent();
@@ -319,7 +552,7 @@ function connectMcpClient(registryOrConfig, serverName, options) {
319
552
  // client.connect() performs initialize handshake - when it resolves, server is ready
320
553
  return [
321
554
  4,
322
- client.connect(transport1)
555
+ connectTransport(client, transport1, options === null || options === void 0 ? void 0 : options.signal)
323
556
  ];
324
557
  case 3:
325
558
  _state.sent();
@@ -327,12 +560,12 @@ function connectMcpClient(registryOrConfig, serverName, options) {
327
560
  case 4:
328
561
  return [
329
562
  3,
330
- 22
563
+ 16
331
564
  ];
332
565
  case 5:
333
566
  if (!(transportType === 'http')) return [
334
567
  3,
335
- 22
568
+ 16
336
569
  ];
337
570
  if (!('url' in serverConfig) || !serverConfig.url) {
338
571
  throw new Error("Server '".concat(serverName, "' has http transport but missing 'url' field"));
@@ -347,7 +580,7 @@ function connectMcpClient(registryOrConfig, serverName, options) {
347
580
  logger.debug("[connectMcpClient] waiting for HTTP server '".concat(serverName, "' at ").concat(serverConfig.url));
348
581
  return [
349
582
  4,
350
- (0, _waitforhttpreadyts.waitForHttpReady)(serverConfig.url)
583
+ (0, _waitforhttpreadyts.waitForHttpReady)(serverConfig.url, 30000, options === null || options === void 0 ? void 0 : options.signal)
351
584
  ];
352
585
  case 6:
353
586
  _state.sent();
@@ -365,7 +598,11 @@ function connectMcpClient(registryOrConfig, serverName, options) {
365
598
  mcpServerUrl = (0, _urlutilsts.normalizeUrl)(serverConfig.url);
366
599
  return [
367
600
  4,
368
- withTimeout((0, _indexts.probeAuthCapabilities)(mcpServerUrl), _constantsts.DCR_CAPABILTY_DISCOVERY_TIMEOUT, 'DCR capability discovery')
601
+ withAbortTimeout(function(signal) {
602
+ return (0, _indexts.probeAuthCapabilities)(mcpServerUrl, {
603
+ signal: signal
604
+ });
605
+ }, _constantsts.DCR_CAPABILTY_DISCOVERY_TIMEOUT, 'DCR capability discovery', options === null || options === void 0 ? void 0 : options.signal)
369
606
  ];
370
607
  case 8:
371
608
  capabilities = _state.sent();
@@ -389,7 +626,7 @@ function connectMcpClient(registryOrConfig, serverName, options) {
389
626
  }, options === null || options === void 0 ? void 0 : options.dcrAuthenticator));
390
627
  return [
391
628
  4,
392
- authenticator.ensureAuthenticated(mcpServerUrl, capabilities)
629
+ authenticator.ensureAuthenticated(mcpServerUrl, capabilities, options === null || options === void 0 ? void 0 : options.signal)
393
630
  ];
394
631
  case 10:
395
632
  tokens = _state.sent();
@@ -407,7 +644,7 @@ function connectMcpClient(registryOrConfig, serverName, options) {
407
644
  12,
408
645
  14,
409
646
  ,
410
- 22
647
+ 16
411
648
  ]);
412
649
  // Try modern Streamable HTTP first (protocol version 2025-03-26)
413
650
  // Merge static headers from config with DCR auth headers (DCR Authorization takes precedence)
@@ -426,16 +663,19 @@ function connectMcpClient(registryOrConfig, serverName, options) {
426
663
  // This is safe at runtime - the undefined is valid per MCP spec
427
664
  return [
428
665
  4,
429
- withTimeout(client.connect(transport2), 30000, 'StreamableHTTP connection')
666
+ connectTransportWithTimeout(client, transport2, HTTP_CONNECTION_TIMEOUT_MS, 'StreamableHTTP connection', options === null || options === void 0 ? void 0 : options.signal)
430
667
  ];
431
668
  case 13:
432
669
  _state.sent();
433
670
  return [
434
671
  3,
435
- 22
672
+ 16
436
673
  ];
437
674
  case 14:
438
675
  error = _state.sent();
676
+ // Cancellation and cleanup failures must reach the caller; neither can
677
+ // safely be converted into an SSE fallback attempt.
678
+ if ((options === null || options === void 0 ? void 0 : (_options_signal = options.signal) === null || _options_signal === void 0 ? void 0 : _options_signal.aborted) || _instanceof(error, AggregateError)) throw error;
439
679
  // Fall back to SSE transport (MCP protocol version 2024-11-05)
440
680
  // SSE is a standard MCP transport used by many servers (e.g., FastMCP ecosystem)
441
681
  errorMessage = _instanceof(error, Error) ? error.message : String(error);
@@ -443,19 +683,12 @@ function connectMcpClient(registryOrConfig, serverName, options) {
443
683
  // Check error.cause.code for ECONNREFUSED (fetch errors wrap the actual error in cause)
444
684
  cause = _instanceof(error, Error) ? error.cause : undefined;
445
685
  isConnectionRefused = (cause === null || cause === void 0 ? void 0 : cause.code) === 'ECONNREFUSED' || errorMessage.includes('Connection refused');
446
- if (!isConnectionRefused) return [
447
- 3,
448
- 16
449
- ];
450
- // Clean up client resources before throwing
451
- return [
452
- 4,
453
- client.close().catch(function() {})
454
- ];
455
- case 15:
456
- _state.sent();
457
- throw new Error("Server not running at ".concat(url));
458
- case 16:
686
+ if (isConnectionRefused) {
687
+ unavailable = new Error("Server not running at ".concat(url), {
688
+ cause: error
689
+ });
690
+ throw unavailable;
691
+ }
459
692
  // Check for known errors that indicate SSE fallback is needed
460
693
  shouldFallback = errorMessage.includes('Missing session ID') || // FastMCP specific
461
694
  errorMessage.includes('404') || // Server doesn't have streamable HTTP endpoint
@@ -483,44 +716,18 @@ function connectMcpClient(registryOrConfig, serverName, options) {
483
716
  }
484
717
  } : undefined;
485
718
  sseTransport = new _client.SSEClientTransport(url, sseTransportOptions);
486
- _state.label = 17;
487
- case 17:
488
- _state.trys.push([
489
- 17,
490
- 19,
491
- ,
492
- 21
493
- ]);
494
719
  return [
495
720
  4,
496
- withTimeout(sseClient.connect(sseTransport), 30000, 'SSE connection')
721
+ connectTransportWithTimeout(sseClient, sseTransport, HTTP_CONNECTION_TIMEOUT_MS, 'SSE connection', options === null || options === void 0 ? void 0 : options.signal)
497
722
  ];
498
- case 18:
723
+ case 15:
499
724
  _state.sent();
500
725
  // Return SSE client instead of original
501
726
  return [
502
727
  2,
503
728
  sseClient
504
729
  ];
505
- case 19:
506
- sseError = _state.sent();
507
- // SSE connection failed - clean up both clients before throwing
508
- return [
509
- 4,
510
- Promise.all([
511
- client.close().catch(function() {}),
512
- sseClient.close().catch(function() {})
513
- ])
514
- ];
515
- case 20:
516
- _state.sent();
517
- throw sseError;
518
- case 21:
519
- return [
520
- 3,
521
- 22
522
- ];
523
- case 22:
730
+ case 16:
524
731
  return [
525
732
  2,
526
733
  client